Skip to content

VisNetworkContainer

网络拓扑展示容器使用

npm, github, docs

安装依赖

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
  }
}