VisNetworkContainer
网络拓扑展示容器使用
安装依赖
shell
pnpm add vis-network效果
查看代码
vue
<template>
<VisNetworkContainer
ref="visNetworkContainerRef"
style="background-color: #f2f7fa; height: 400px"
/>
</template>
<script lang="ts" setup>
import { message } from 'ant-design-vue'
import { onMounted, ref } from 'vue'
import VisNetworkContainer from './VisNetworkContainer.vue'
import { createEdge, createNode } from './helper'
const visNetworkContainerRef = ref<InstanceType<typeof VisNetworkContainer>>()
onMounted(() => {
const mockData = {
nodes: [
{
id: '9a3ecf08-88fd-4bc5-abdc-d341a17496f6',
name: 'node1'
},
{
id: '0c36a5f0-6cb8-4b9d-9ed8-4bc3b9bb8dd4',
name: 'network1'
},
{
id: '25d02247-36fa-4cbf-a93c-8343d3f92a43',
name: 'node2'
}
],
edges: [
{
source: '25d02247-36fa-4cbf-a93c-8343d3f92a43',
target: '9a3ecf08-88fd-4bc5-abdc-d341a17496f6'
},
{
source: '0c36a5f0-6cb8-4b9d-9ed8-4bc3b9bb8dd4',
target: '9a3ecf08-88fd-4bc5-abdc-d341a17496f6'
}
]
}
visNetworkContainerRef.value?.setData({
nodes: mockData.nodes.map(v => createNode({ id: v.id, label: v.name })),
edges: mockData.edges.map(v => createEdge(v.source, v.target))
})
visNetworkContainerRef.value?.registerNodeDoubleClickEvent(nodeId =>
message.info(`nodeId: ${nodeId}被双击`)
)
visNetworkContainerRef.value?.registerNodeSelectEvent(nodeId =>
nodeId ? message.info(`nodeId: ${nodeId}被选中`) : message.info(`取消选中`)
)
})
</script>vue
<template>
<div class="vis-network" ref="visContainer" />
</template>
<script lang="ts" setup>
import { DataSet, Network, type Options } from 'vis-network/standalone'
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
// https://github.com/visjs/vis-network
// https://ame.cool/pages/43724c/#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E9%A1%B9%E9%A2%84%E8%A7%88
const props = defineProps<{ options?: Options }>()
const visContainer = ref()
const visInstance = shallowRef<Network | null>(null)
onMounted(() => {
const el = visContainer.value as HTMLDivElement
visInstance.value = new Network(
el,
{
edges: new DataSet([]),
nodes: new DataSet([])
},
{ autoResize: true, ...props.options }
)
const observer = new ResizeObserver(() => {
visInstance.value?.setSize(`${el.clientWidth}px`, `${el.clientHeight}px`)
visInstance.value?.redraw()
visInstance.value?.fit()
})
observer.observe(el)
onUnmounted(() => {
observer.unobserve(el)
visInstance.value?.destroy()
})
})
/**
* 封装节点事件处理函数
*
* @param callback 回调函数,接收一个节点ID作为参数
* @returns 返回封装后的节点事件处理函数
*/
function visNodeEventEncapsulation(callback: (nodeId: string) => void) {
return function nodeEvent(this: Network, event: any) {
const nodeId = event.nodes[0]
callback(nodeId)
}
}
defineExpose({
setData(data: { nodes: any[]; edges: any[] }) {
visInstance.value?.setData(data)
},
/**
* 注册节点双击事件
*
* @param callback 回调函数,当节点被双击时触发,接收一个参数 nodeId(字符串类型),表示被双击的节点的ID
*/
registerNodeDoubleClickEvent(callback: (nodeId: string) => void) {
visInstance.value?.off('doubleClick', visNodeEventEncapsulation(callback))
visInstance.value?.on('doubleClick', visNodeEventEncapsulation(callback))
},
/**
* 注册选中事件
*
* @param callback 回调函数,当节点被双击时触发,接收一个参数 nodeId(字符串类型),表示被双击的节点的ID
*/
registerNodeSelectEvent(callback: (nodeId: string) => void) {
visInstance.value?.off('select', visNodeEventEncapsulation(callback))
visInstance.value?.on('select', visNodeEventEncapsulation(callback))
}
})
</script>ts
import image from './node.png'
export const createNode = (option: { id: string; label: string }) => {
return {
id: option.id,
label: option.label,
shape: 'image',
image: image
}
}
export const createEdge = (sourceId: string, targetId: string) => {
return {
from: sourceId,
to: targetId
}
}