开发需求背景
今天领导派了一个小活,要求我将公司的物联网平台的网络拓扑图画出来。做一个数据展示的页面,集成到现有的iot平台上。
说到拓扑图,大家都也都比较清楚,能够清晰地表示网络链路的链接关系。
官方一点的解释是:
网络拓扑结构是指用传输媒体互连各种设备的物理布局(将参与LAN工作的各种设备用媒体互连在一起有多种方法,但是实际上只有几种方式能适合LAN的工作)。
网络拓扑图是指由网络节点设备和通信介质构成的网络结构图。
一般的拓扑图都是这样子的
还有这一种
这些设计图都是架构师使用软件画出来的,数据都是固定的,不支持动态修改,没有动效,而我们需要支持动态添加网络节点。需要有动效。
经过一天不歇的努力,终于在下班前做出来了一个原型图。
先给大家看看,下面来详细讲解如何使用echarts一步一步完成这个拓扑图的。
技术调研
接到需求后我调研了几个物联网仪表盘后,我觉得使用echart来试试,因为d3太难了。😃
拓扑图中需要与几个实体,代表链路中的每一个设备,一个设备可能有进线,有出线,也有可能有多条线,线的条数都不能固定的。因为随着设备的增加,中央机器到达各个设备的线也是逐渐增加的。设备之间有线,有了线,就要有流量的流动,就是在线上方覆盖一个箭头,逐渐从数据的发出方到达数据的接受方。此外每台设备都要有个名称,鼠标放到设备上,需要有一个动效,最好能显示一些详细情况。
ok
需求分析完毕,一个图大致有以下几个视图
- 设备
- 设备之间的线
- 线上的流量流向箭头
- 设备的附加信息
- 其他动效
开始编码
在真正的编码开始之前,我们需要对这个需求有个抽象的概念,怎么抽象那?
我们可以将设备,线,箭头,都看做物品,而这些物品都存在于一个平面直角坐标系上。有了平面直角坐标系也就有了他们各自的位置。
比如设备1的坐标是x: 500 y: 1000
, 设备2的坐标是 x: 500 y: 600
那么设备2就是在设备1的下方。 而设备1到设备2的链接,也就是好说了, 这条线段的的气质坐标是{x: 500 y: 1000}
=> {x: 500, y: 600}
这样就非常容易理解了。而echarts是支持 使用二维的直角坐标系(也称笛卡尔坐标系)。
具体设置是在series 中的一些类型下, 设置coordinateSystem
为cartesian2d
官方文档的解释。
思路清晰了,我们先来做一个简单的。
先画出二个设备,然后再连线。
定义二个设备
{
x: 500,
y: 1000,
nodeName: '服务器',
svgPath: 'M544 552.325V800a32 32 0 0 1-32 32 31.375 31.375 0 0 1-32-32V552.325L256 423.037a32 32 0 0 1-11.525-43.512A31.363 31.363 0 0 1 288 368l224 128 222.075-128a31.363 31.363 0 0 1 43.525 11.525 31.988 31.988 0 0 1-11.525 43.513L544 551.038z m0 0,M64 256v512l448 256 448-256V256L512 0z m832 480L512 960 128 736V288L512 64l384 224z m0 0',
symbolSize: 70,
},
{
x: 500,
y: 600,
nodeName: '设备1',
svgPath: 'M1172.985723 682.049233l-97.748643-35.516964a32.583215 32.583215 0 0 0-21.830134 61.582735l25.7398 9.123221-488.744218 238.181638L115.670112 741.349163l47.245961-19.223356a32.583215 32.583215 0 0 0-22.808051-60.604819l-119.579777 47.896905a32.583215 32.583215 0 0 0 0 59.952875l557.820313 251.540496a32.583215 32.583215 0 0 0 27.695632 0l570.527227-278.584184a32.583215 32.583215 0 0 0-3.258721-59.952875z,M1185.041693 482.966252l-191.587622-68.749123a32.583215 32.583215 0 1 0-21.831133 61.254764l118.927833 43.010323-488.744218 237.855666-471.474695-213.744727 116.973-47.244961a32.583215 32.583215 0 1 0-24.111938-60.604819l-190.609705 75.593537a32.583215 32.583215 0 0 0-20.528246 29.650465 32.583215 32.583215 0 0 0 20.528246 30.30141l557.819313 251.866468a32.583215 32.583215 0 0 0 27.695632 0l570.201254-278.584184a32.583215 32.583215 0 0 0 18.24744-30.953354 32.583215 32.583215 0 0 0-21.505161-29.651465z,M32.583215 290.075742l557.819313 251.540496a32.583215 32.583215 0 0 0 27.695632 0l570.201254-278.584184a32.583215 32.583215 0 0 0-3.257721-59.952875L626.244463 2.042365a32.583215 32.583215 0 0 0-23.134022 0l-570.527226 228.080502a32.583215 32.583215 0 0 0-19.224357 30.627382 32.583215 32.583215 0 0 0 19.224357 29.325493zM615.817355 67.534767l474.733416 170.408432-488.744218 238.180638-471.474695-215.372588z'
},
x, y 代表设备的坐标, nodeName定义了设备的名称, svgPath是使用svg的指令语法来生成一个设备图标。
效果图
定义连线
{
coords:
[
[500, 1000],
[500, 800],
]
},
{
coords: [
[500, 800],
[500, 600],
]
},
效果图
解释:
coords作为一个数组,存放的是几个点的坐标
[
[500, 1000],
[500, 800],
]
数组的第一个元素表示起点,第二个元素表示终点
那么这条线段就是从 x500,y1000
到达 x500,y800
完整的代码
var nodes = [{
x: 500,
y: 1000,
nodeName: '应用',
svgPath: 'M544 ',
symbolSize: 70,
}, {
x: 100,
y: 600,
nodeName: '模块1',
svgPath: 'M1172. '
},
{
x: 500,
y: 600,
nodeName: '模块2',
svgPath: 'M1 615.817355 67.534767l474.733416 170.408432-488.744218 238.180638-471.474695-215.372588z'
},
{
x: 900,
y: 600,
nodeName: '模块3',
svgPath: 'M117 615.817355 67.534767l474.733416 170.408432-488.744218 238.180638-471.474695-215.372588z'
},
{
x: 0,
y: 300,
nodeName: '节点1',
svgPath: 'M887.5 68 68.25472-68.224 68.28544l-0.06144-0.06656z',
},
{
x: 300,
y: 300,
nodeName: '节点2',
svgPath: 'M88 37.71392 0 68.29056 30.57152 68.28544 68.29056 0 37.68832-30.53568 68.25472-68.224 68.28544l-0.06144-0.06656z',
},
{
x: 700,
y: 300,
nodeName: '节点3',
svgPath: 'M887.55 25472-68.224 68.28544l-0.06144-0.06656z',
},
{
x: 1000,
y: 300,
nodeName: '节点4',
svgPath: 'M887.55 0.53568 68.25472-68.224 68.28544l-0.06144-0.06656z',
},
]
var charts = {
nodes: [],
linesData: [{
coords: [
[500, 1000],
[500, 800],
]
}, {
coords: [
[500, 800],
[100, 800],
[100, 600]
]
}, {
coords: [
[500, 800],
[500, 600],
]
}, {
coords: [
[500, 800],
[900, 800],
[900, 600]
]
},
{
coords: [
[100, 600],
[0, 300]
]
},
{
coords: [
[100, 600],
[300, 300]
]
},
{
coords: [
[900, 600],
[700, 300]
]
},
{
coords: [
[900, 600],
[1000, 300]
]
}
]
}
for (var j = 0; j < nodes.length; j++) {
const {
x,
y,
nodeName,
svgPath,
symbolSize
} = nodes[j];
var node = {
nodeName,
value: [x, y],
symbolSize: symbolSize || 50,
symbol: 'path://' + svgPath,
itemStyle: {
color: 'orange',
}
}
charts.nodes.push(node)
}
option = {
backgroundColor: "#0B1321",
xAxis: {
min: 0,
max: 1000,
show: false,
type: 'value'
},
yAxis: {
min: 0,
max: 1000,
show: false,
type: 'value'
},
series: [{
type: 'graph',
coordinateSystem: 'cartesian2d',
label: {
show: true,
position: 'bottom',
color: 'orange',
formatter: function(item) {
return item.data.nodeName
}
},
data: charts.nodes,
}, {
type: 'lines',
polyline: true,
coordinateSystem: 'cartesian2d',
lineStyle: {
type: 'dashed',
width: 2,
color: '#175064',
curveness: 0.3
},
effect: {
show: true,
trailLength: 0.1,
symbol: 'arrow',
color: 'orange',
symbolSize: 8
},
data: charts.linesData
}]
};
这里svg的指令太多,我删减了一部分,具体的动效图。
技术回顾
使用echart画物联网各种仪表盘时,掌握坐标系就掌握了各个物体的位置。随你发挥.
此外需要注意一下,我们的设备图表使用的是series-graph
可以用于展现节点以及节点之间的关系数据。
写在最后
掌握住echarts的配置项,可以画出很多精美的仪表盘,后续我和大家继续分享其他的物联网相关的仪表盘.如果文章对你有帮助,请记得点赞留言。