拓扑结构在计算机网络设计和通信领域中非常重要,因为它描述了网络中的设备(即“点”)如何相互连接(即通过“线”)。这种结构不仅涉及物理布局,即物理拓扑,还可以涉及逻辑或虚拟的连接方式,即逻辑拓扑。
图扑软件自研 HT for Web 产品曾参与搭建了众多拓扑可视化解决方案。如机房通信拓扑可视化,实现通过图形图像直观展示机房内部网络设备、服务器、存储设备以及之间连接关系的技术。帮助 IT 管理员和网络工程师更加直观地理解机房的网络结构,便于故障排查、网络优化和规划扩展。
在 HT 中,ht.Node 可充当拓扑图中的“点”角色,ht.Node 上可显示图片图标,这使得创建拓扑图时能够直观地表示每一个“点”的特征。至于拓扑图中的“线”,即用于体现两个节点之间关系的元素,可由 ht.Edge 类型承担这一任务。ht.Edge用于连接起始和目标两个节点,两个节点间可以有多条ht.Edge存在,也允许起始和目标为同一节点。
在搭建 HT 拓扑图前,我们需要先创建一个 HT 的 2D 视图:
const dm = new ht.DataModel(); // 创建一个数据模型 const g2d = new ht.graph.GraphView(dm); // 创建一个 2D 视图 g2d.addToDOM(); // 将 2D 视图添加到 body 中 dm.setBackground('rgb(240,237,237)'); // 设置背景
2D 视图还可按照需求开启树层次渲染:
dm.setHierarchicalRendering(true);
2D 视图创建完成之后就可以创建“点”和“线”了:
const node1 = createNode('symbols/电信/icon_交换机.json', { x: 0, y: 0 }, "交换机"); const node2 = createNode('symbols/电信/icon_路由.json', { x: 300, y: 0 }, "路由"); createEdge(node1, node2); function createNode(icon, position, name) { const node = new ht.Node(); // 创建一个 ht.Node 节点 node.s({ 'label': name, 'label.color': "#fff" }); node.setImage(icon); node.p(position); node.setSize({ width: 100, height: 100 }); dm.add(node); // 将节点加到数据模型中 return node; } function createEdge(source, target, color, reverse) { const edge = new ht.Edge(source, target); // 创建一个 ht.Edge dm.add(edge); // 将连线节点加到数据模型中 return edge; }
运行代码后的效果:
复杂连线
以上展示了一个简洁的示例,直观地展现了如何在图扑自研 HT for Web 中创建节点并将它们通过连线相连。实际应用中的情形往往更为复杂,需要根据实际数据构建拓扑结构。在这个过程中,核心步骤依旧是首先创建 ht.Node 实例以表示各个节点,再利用 ht.Edge 实例来实现节点之间的连接。接下来,让我们通过复杂一些的示例来演示。
创建节点
为了批量创建节点并方便管理节点数据,示例中定义了结构化的数据格式,并将数据存储在一个 JSON 文件中,再通过 ht.Default.xhrLoad() 去获取到 JSON 文件中的数据。获取到数据后就可批量创建节点。
在实际的运用场景中,也可以通过任何 web 端通讯方式 HTTP/AJAX、WebSocket 去获取数据。
equipment.json 文件中定义的数据格式:
[ { "name": "核心交换机1", // 设备名称 "code": "EQ_ASBB1425", // 设备编码(唯一标识) "icon": "symbols/user/900-word/电信拓扑图标/icon_核心交换机.json", // 设备 icon // 设备在图纸中的位置 "size": 60, // 节点大小 "position": { "x": 0, "y": 100 } }, { "name": "核心交换机2", "code": "EQ_ASBB1478", "icon": "symbols/user/900-word/电信拓扑图标/icon_核心交换机.json", "position": { "x": 200, "y": 0 } }, { "name": "服务器1", "code": "EQ_BCGJ2121", "icon": "symbols/user/900-word/电信拓扑图标/空白服务器.json", "position": { "x": 200, "y": 250 } }, ... ]
获取到数据并批量创建节点:
ht.Default.xhrLoad('./equipment.json', function (json) { const data = ht.Default.parse(json); data.forEach((item) = > { createNode(item); }) }) function createNode(data) { const node = new ht.Node(); node.setTag(data.code); // 设置节点唯一标识 node.setImage(data.icon); node.p(data.position); node.s('2d.movable', false); // 禁止移动 node.setSize({ width: data.size || 150, height: data.size || 150 }); dm.add(node); return node; }
创建连线
与节点数据相同,示例中定义了连线对应格式,并且也是存储在一个 JSON 文件中,再通过 ht.Default.xhrLoad() 获取数据。JSON 文件中定义了连线中最重要的几个因素:起始节点、目标节点、连线颜色。
[ { "source": "EQ_ASBB1425", // 起始节点的唯一标识 "target": "EQ_BCGJ2121", // 结束节点的唯一标识 "color": "rgb(0,199,7)" // 连线颜色 }, { "source": "EQ_ASBB1425", "target": "EQ_BCGJ2131", "color": "rgb(0,199,7)" }, ... ]
获取数据并且批量创建连线,这一步需要在创建节点之后执行:
ht.Default.xhrLoad('./connectData.json', function (json) { const connectData = ht.Default.parse(json); connectData.forEach((item) = > { createEdge(item); }) }) function createEdge(data) { const source = dm.getDataByTag(data.source); const target = dm.getDataByTag(data.target); const edge = new ht.Edge(source, target); edge.s({ "edge.color": data.color || "rgb(0,199,7)", "edge.width": 4, "shadow2.offset.x": -4, "shadow2.offset.y": 7, "shadow2": true, "shadow2.color": "rgba(0,0,0,0.18)", }) dm.add(edge); dm.moveToTop(edge); // 将节点移动至顶部 return edge; }
到这里,基本上整个拓扑的效果都已经展示出来了,但是可能还存在一些问题。如终端路由之间的连线被服务器挡住了,可能会被认为是路由 1—服务器 1—服务器 2—路由 2 这样的连接。
这种情况下,就可以采用其他的连线方式。ht.Edge 提供了多种的连线方式,可以通过 edge.s(‘edge.type’, 连接方式) 进行设置。下面展示几种不同的连接方式:
1.弯曲:edge.s(‘edge.type’, ‘flex2’)
2.正交:edge.s(‘edge.type’, ‘ortho2’)
3.先水平后垂直:edge.s(‘edge.type’, ‘h.v2’)
4.先水平后垂直:edge.s(‘edge.type’, ‘v.h2’)
......
ht.Edge 还有很多种的连线方式,这里就先介绍以上几种方式。
在这个示例内,两个路由之间的连线需要跨域多个其他的连线,为了使得连线更加美观易懂,于是我就这条连线采用了 points 的连线方式,这种方式有极高的灵活性,可在连线路径上自由地添加控制点,从而实现非常多样化的效果。
points 类型的连线,有两个非常重要的属性:
edge.points:控制点信息;
edge.segments:用来标识在绘制时如何使用 points 数组中的顶点信息。
将示例中这条连线的连线类型改为 points,并设置上相应的属性:
edge.s({ 'edge.type': 'points', 'edge.center': true, 'edge.points': [ { "x": 680, "y": 105 }, { "x": 490, "y": 200 }, { "x": 470, "y": 200 }, { "x": 410, "y": 230 }, { "x": 400, "y": 250 }, { "x": 360, "y": 270 }, { "x": 340, "y": 270 }, { "x": 260, "y": 310 }, { "x": 250, "y": 330 }, { "x": 80, "y": 415 } ], 'edge.segments': [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] });
使用以上 points 连线类型实现的效果:
增加背景和装饰
可创建一些 ht.Shape 节点作为背景装饰,突出显示特定的设备区域。
createShape([ { x: -100, y: 130 }, { x: 230, y: -50 }, { x: 340, y: 15 }, { x: 10, y: 195 }, { x: -100, y: 130 } ], [1, 2, 2, 2, 5]) createShape([ { x: -155, y: 354 }, { x: 575, y: -30 }, { x: 805, y: 110 }, { x: 60, y: 510 }, { x: -155, y: 355 }, ], [1, 2, 2, 2, 5]); createShape([ { x: 300, y: 470 }, { x: 660, y: 275 }, { x: 805, y: 350 }, { x: 435, y: 550 }, { x: 300, y: 470 }, ], [1, 2, 2, 2, 5]) function createShape(points, segments) { const shape = new ht.Shape(); shape.setPoints(points); shape.setSegments(segments); shape.s({ 'shape.background': "#fff", "shape.border.color": "rgba(13,46,79,0.67)", "shape.border.width": 0.5, }) dm.add(shape); dm.moveToTop(shape); return shape; }
添加背景后的效果如下:
增加一些装饰的节点,这些节点本质上也都是 ht.Node,只是显示了不同的图标/图片,效果如下:
添加箭头
在复杂的网络拓扑中,连线上常常需要表示数据流动方向。在使用图扑 HT 绘制连线时,ht.Edge 提供了 icons 属性,通过 icons 属性,可在 ht.Edge 上定义一系列图标并设置它们在连线上的位置。
在设置 icons 属性前,需要先注册好图标:
ht.Default.setImage('toArrow', { width: 40, height: 20, comps: [ { type: 'shape', points: [5, 2, 10, 10, 5, 18, 20, 10], closePath: true, background: 'rgb(0,199,7)', borderWidth: 1, borderColor: 'rgb(0,199,7)', gradient: 'spread.vertical' } ] }); ht.Default.setImage('fromArrow', { width: 12, height: 12, comps: [ { type: 'circle', rect: [1, 1, 10, 10], background: 'rgb(0,199,7)' } ] });
在 ht.Edge 上设置 icons:
edge.addStyleIcon("fromArrow", { position: 15, // 图标位置 keepOrien: true, // 图标是否默认自动调整方向以保持最好的阅读效果 names: ['fromArrow'] }); edge.addStyleIcon("toArrow", { position: 19, keepOrien: true, names: ['toArrow'] });
设置 icons 之后的效果:
流动动画
在图扑自研产品 HT for Web 中,使用 ht-flow.js 插件,能够为 ht.Edge 连线添加流动动画效果。这种效果可用于表示数据传输、能源流动或任何类型的动态连接。使用 ht-flow.js 插件实现的流动效果配置起来也十分简单,正确引入 ht-flow.js 插件后,使用 g2d.enableFlow(60); 开启流动,再在 ht.Edge 上设置相应的流动属性即可。
ht.Edge 配置流动效果的一些属性说明:
flow:布尔值,设置为 true 以启用流动效果。
flow.count:控制流动组的个数,默认为 1。
flow.step:控制流动的步进,默认为 3。
flow.element.count: 每个流动组中的元素的个数,默认为 10。
flow.element.space: 流动组中元素的间隔,默认为 3.5。
flow.element.image: 字符串类型,指定流动组中元素的图片,图片需要提前通过 ht.Default.setImage 注册。目前支持设置。
flow.element.background: 流动组中元素的背景颜色,默认为 rgba(255, 255, 114, 0.4)。
flow.element.shadow.begincolor: 字符串类型,表示流动组中的元素的渐变阴影的中心颜色,默认为 rgba(255, 255, 0, 0.3)。
flow.element.shadow.endcolor: 字符串类型,表示流动组中的元素的渐变阴影的边缘颜色,默认为 rgba(255, 255, 0, 0)。
flow.element.shadow.visible:流动阴影是否可见。
flow.begin.percent:开始的位置,值为 0 - 1,默认是 0。
flow.element.autorotate:是否自动朝向,根据连线的角度自动朝向。
在示例的 ht.Edge 上设置流动属性:
edge.s({ "flow": true, "flow.element.background": "rgba(240, 225, 19, 0.5)", "flow.element.shadow.begincolor": "rgba(240, 225, 19, 0.5)", "flow.element.shadow.endcolor": "rgba(240, 225, 19, 0)", "flow.element.count": 1 });
设置完成后的效果:
在更为复杂的场景中,仅仅依赖简单的样式配置难以满足设计需求,为此 ht-flow.js 提供了 flow.element.image 属性,该属性支持将流动的元素设置为图片或图标,还支持设置为多个图片/图标流动的效果。
在流动上设置图标,需要先注册图标:
ht.Default.setImage('dataIcon1', { "width": 50, "height": 50, "comps": [ { "type": "shape", "background": "rgb(125,195,125)", "borderColor": "#979797", "points": [ 2.94441, 16.1039, 26.41008, 16.1039, 26.41008, 4.28571, 47.05559, 25.58442, 27.23783, 45.71429, 27.23783, 33.84863, 2.94441, 33.84863, 2.94441, 16.1039 ] } ] }) ht.Default.setImage('dataIcon2', { "width": 50, "height": 50, "comps": [ { "type": "shape", "background": "#32D3EB", "borderColor": "#979797", "points": [ 2.94441, 16.1039, 26.41008, 16.1039, 26.41008, 4.28571, 47.05559, 25.58442, 27.23783, 45.71429, 27.23783, 33.84863, 2.94441, 33.84863, 2.94441, 16.1039 ] } ] }); 在 ht.Edge 上设置属性: edge.s({ "flow": true, "flow.element.count": 2, "flow.element.image": ["dataIcon1", "dataIcon2"], "flow.element.max": 20, "flow.element.min": 20, "flow.element.shadow.visible": false, "flow.element.space": 50, "flow.element.autorotate": true }); 设置完成后的效果:
设置完成后的效果:
拓扑可视化优点
直观性:将抽象的关系和数据通过图形呈现,使得人们可以直观地理解和分析系统或网络的结构。
互动性:现代拓扑可视化工具通常支持用户与图形的交互操作,如缩放、拖拽节点、探索节点之间的路径等,进一步提升了分析的深度和广度。
动态性:能够实时反映系统或网络的变化,及时展现新增元素和调整后的结构关系,对于监控和管理系统状态尤为重要。
灵活性:用户可以根据需要选择不同的布局算法,调整图形的展示方式,更好地适应不同的分析场景。
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !