vue3项目中使用v-network-graph绘制拓扑图/网络图
学习v-network-graph;vue3+elementplus项目中集成v-network-graph库;使用v-network-graph构建网络图/拓扑图
v-network-graph
v-network-graph 是一个专为Vue 3设计的交互式网络图形可视化组件。它基于SVG绘制,充分利用Vue的响应式系统和双向数据绑定特性,简化了动态数据驱动的复杂网络图的创建过程。该组件允许开发者实时操控图表,如添加或删除元素、改变节点位置及调整视觉样式等,无需复杂的集成工作,显著降低了学习成本和编码量。目前该库已经基本成熟,还有些小功能未完善,比如两个拓扑节点之间存在汇总边时,选中样式这个小功能还未完成开发,但是在实际开发中几乎不会对项目造成什么影响。
项目背景
网络系统中的各个层的网络设备资源,在运行过程中都可能发成故障,存在故障肯定就会有告警,故障引起的原因有很多,性能、网络、数据等等,为了方便用户直观的了解各个资源的动态信息,所以需要以资源关系绘制拓扑图大屏,以满足客户的需求,并且拓扑图需要支持可配置(节点,边,文本,背景)。
将v-network-graph集成到项目
注意:官网上的例子是以ts编写的,我这里由于项目原因以js编写。
1.下载
npm/pnpm install v-network-graph
2. 在项目入口文件main.js
// main.js
import { createApp } from "vue"
import VNetworkGraph from "v-network-graph"
import "v-network-graph/lib/style.css"
import App from "./App.vue"
const app = createApp(App)
app.use(VNetworkGraph)
app.mount("#app")
# 也可以在组件中局部引入,无需全局注册
<!-- YourVueComponent.vue -->
<script setup lang="ts">
import { VNetworkGraph } from "v-network-graph"
import "v-network-graph/lib/style.css"
...
</script>
3.创建自己的画布组件
<template>
<v-network-graph class="networkContainer">
</v-network-graph>
</template>
<script setup>
</script>
<style lang="scss">
.networkContainer {
...yourself style
}
</style>
4.创建网络图需要的必要参数。
<template>
<v-network-graph
:nodes="nodes"
:edges="edges"
/>
</template>
<script setup>
// nodes 该参数代表网络图的所有节点的数据
const nodes = {
node1: { name: "Node 1" },
node2: { name: "Node 2" },
node3: { name: "Node 3" },
node4: { name: "Node 4" },
}
// edges 该参数代表网络图的所有节点之间的边数据
const edges = {
edge1: { source: "node1", target: "node2" },
edge2: { source: "node2", target: "node3" },
edge3: { source: "node3", target: "node4" },
}
</script>
完成以上四部就可以绘制出一个简单的网络图了。
如何让拓扑图变得复杂一些呢
如上简单的拓扑图肯定满足不了复杂的项目需求,我下面会从三个方面深入:
布局
如果你要自定义布局,那么会有layouts属性进行布局,x,y的值代表节点在画布上的坐标值。
const layouts = {
nodes: {
node1: { x: 0, y: 0 },
node2: { x: 50, y: 50 },
node3: { x: 100, y: 0 },
node4: { x: 150, y: 50 },
},
}
<template>
<v-network-graph
:nodes="nodes"
:edges="edges"
:layouts="layouts"
/>
</template>
可配置节点和边
如果要对边和节点的自定义配置,必须添加configs属性。
const config = {
node: {
normal: {
type: "circle",
radius: node => node.size, // Use the value of each node object
color: node => node.color,
},
hover: {
radius: node => node.size + 2,
color: node => node.color,
},
selectable: true,
label: {
visible: node => !!node.label,
},
focusring: {
color: "darkgray",
},
},
edge: {
normal: {
width: edge => edge.width, // Use the value of each edge object
color: edge => edge.color,
dasharray: edge => (edge.dashed ? "4" : "0"),
},
},
}
<template>
<v-network-graph
:nodes="nodes"
:edges="edges"
:layouts="layouts"
:configs="configs"
/>
</template>
注意:如果你不需要动态去改变边或者节点的某个属性,属性值不需要写成箭头函数的方式,可以直接写成具体的常量。
其实除了边和节点的配置以外,还有很多很多,并且还能对画布view进行属性配置等等,我就在这里不一一赘述了,如果有兴趣可以详细阅读下面的文档;(此文档问英文文档,需要的可借助翻译软件更容易理解)
v-network-graph官方文档https://dash14.github.io/v-network-graph/examples/appearance.html
复杂场景来了
元素层级问题
官方文档上对于层级问题是这么描述的,大概意思就是,需要自定义层级问题的话需要在配置文件的视图view属性上去设置。
You can add layers in the SVG generated by v-network-graph.
To add a layer, define the layer name and insertion position in the attribute, and define a named slot with the specified layer name in.
下图是图层各类型元素默认的层顺序:
自定义层级
在configs配置属性的view属性上添加如下配置信息,可以根据自己的业务场景调整其顺序;
const topoConfig = {
view: {
builtInLayerOrder: ['edge-labels', 'edges', 'node-labels', 'nodes'],
},
...其他配置属性
}
重点:图层元素对应的数组索引越小层级越高,如果不写某些图层元素则会拿默认值元素索引定义层级。
自定义元素内容
元素自定义是很常见的业务场景,官方针对节点,节点标题(label),边都提供了对应的插槽入口
# 替换节点插槽
<template #override-node="{ nodeId, scale, config }">
</template>
# 替换label插槽
<template #override-node-label="{ scale, text }">
</template>
# 替换边的插槽
<template #edge-overlay="{ edge, scale, length, pointAtLength }">
</template>
# 自定义边的标记形状
<defs>
<marker
id="marker-custom-diamond"
markerWidth="6"
markerHeight="6"
refX="3"
refY="3"
orient="auto"
markerUnits="strokeWidth"
>
<polygon points="0 3, 3 0, 6 3, 3 6" fill="#ff6666" />
</marker>
</defs>
如上的代码怕片段插槽能提供的参数只写了部分,其它参数可以去官方文档案例中查看;由于该库是基于svg编写的,所以自定义内容需要利用svg的标签编写,具体的svg标签用途和功能可以阅读该文档;https://developer.mozilla.org/zh-CN/docs/Web/SVGhttps://developer.mozilla.org/zh-CN/docs/Web/SVG
图形元素的事件对象
绘制出复杂的网路图后,用户交互场景也同样重要,组件提供了event-handlers这个参数来实现交互场景。事件对象包含两大类,组件事件对象和图层事件对象。
<template>
<v-network-graph
:nodes="nodes"
:edges="edges"
:layouts="layouts"
:configs="configs"
:event-handlers="eventHandlers"
/>
</template>
<script setup>
const eventHandlers = {
// 视图鼠标左击操作
"view:click": ({ event}) => {
// 自定义交互内容
},
// 视图鼠标左键双击操作
"view:dblclick": ({ event }) => {
// 自定义交互内容
},
...
// 节点鼠标左击操作
"node:click": ({ node }) => {
// toggle
nodes[node].active = !nodes[node].active
},
// 节点鼠标左键双击操作
"node:dblclick": ({ node, event }) => {
// toggle
nodes[node].active = !nodes[node].active
},
...
// 鼠标左击边操作
"edge:click": ({ edge, deges, event, summarized}) => {
// 自定义交互内容
},
// 鼠标左键双击边操作
"edge:dblclick": ({ deges, event, summarized }) => {
// 自定义交互内容
},
...
}
</script>
上面只罗列了视图,节点,边的单击和双击事件对象,还有很多可以在文档上查找。除了元素交互方法外,还给开发者暴露了一些方法:
这些方法如何调用呢?
<template>
<v-network-graph
ref="graphRef"
v-model:selected-nodes="selectedNodes"
v-model:selected-edges="selectedEdges"
:nodes="nodes"
:edges="edges"
:layouts="data.layouts"
:configs="data.configs"
/>
</template>
<script setup>
import { ref } from 'vue'
const graphRef = ref(null) // 网络图ref
// 调用方法
async function downloadAsSvg() {
if (!graph.value) return
const text = await graphRef.value.exportAsSvgText()
const url = URL.createObjectURL(new Blob([text], { type: "octet/stream" }))
const a = document.createElement("a")
a.href = url
a.download = "network-graph.svg" // filename to download
a.click()
window.URL.revokeObjectURL(url)
}
</script>
总结
v-network-graph这个库提供很多功能,能满足很多复杂的业务场景,上面是我在开发中自己总结学习的东西,整理了最常用的功能点,还有很多功能就不一一赘述,需要深入了解的小伙伴一定要仔细阅读我上面提供的文档,希望我的内容能帮到遇到同样问题的小伙伴!欢迎评论留言。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)