使用X6+自定义Vue节点实现拓扑关系

1. 概述

接到一个任务,是要前端实现系统功能模块间拓扑关系图,需求设计需要节点能够自定义布局;新增节点是通过表单配置后生成(后面优化我补充了连接桩),所以需要节点的坐标(position:x,y)能够自适应;调研后可以通过使用X6+自定义Vue节点实现拓扑关系,于是开始学习X6技术,并最终能够按要求实现需求设计

2. 技术

  • 使用的框架:Vue
  • 使用的组件库:iView、Element
  • X6 图编辑引擎 X6 是 AntV 旗下的图编辑引擎,提供了一系列开箱即用的交互组件和简单易用的节点定制能力,方便我们快速搭建 DAG 图、ER 图、流程图等应用。
  • X6功能思维导图:
  • X6优点:
  1. 极易定制:支持使用 SVG/HTML/React/Vue 定制节点样式和交互;
  2. 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等;
  3. 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑;
  4. 事件驱动:可以监听图表内发生的任何事件。

3. 实现

  • 安装库
ruby 复制代码
$ npm install @antv/x6 --save 
$ yarn add @antv/x6
  • 引入
javascript 复制代码
import { Graph, Line, Path, Curve } from "@antv/x6"; // 引入X6
import customNode from "./components/customNode"; //引入自定义节点Vue组件
import { register } from "@antv/x6-vue-shape"; // 注册自定义节点
  • 实现画布 在 X6 中,Graph 是图的载体,它包含了图上的所有元素(节点、边等),同时挂载了图的相关操作(如交互监听、元素操作、渲染等)。
javascript 复制代码
const graph = new Graph({
        container: document.getElementById("container"),
 })
 
 // 双击边
 graph.on("edge:dblclick", ({ e, x, y, cell, view }) => {})
 // 双击节点
 graph.on("node:dblclick", ({ e, x, y, cell, view }) => {})
 // 鼠标移入 展示连接桩、删除button
 graph.on("cell:mouseenter", ({ cell }) => {})
 // 鼠标移出 隐藏连接桩、删除button
 graph.on("cell:mouseenter", ({ cell }) => {})
  • 注册自定义节点
php 复制代码
register({
        shape: "custom-node",
        width: 400,
        height: 130,
        ports: { ...ports },
        component: {
          render: (h) =>
            h(customNode, {
              on: {
                // 监听 customNode组件触发的事件,获取传递出来的数据
                myEvent: (data) => {
                  this.handleMyEvent(data);
                },
              },
              props: {},
            }),
        },
  });
  • 注册自定义连线样式
ini 复制代码
let options = { raw: true, index: 1, total: 6, gap: 12 };
      Graph.registerConnector(
        "multi-smooth",
        (sourcePoint, targetPoint, routePoints) => {
          const { index = 0, total = 1, gap = 12 } = options;
          const line = new Line(sourcePoint, targetPoint);
          const centerIndex = (total - 1) / 2;
          const dist = index - centerIndex;
          const diff = Math.abs(dist);
          const factor = diff === 0 ? 1 : diff / dist;
          const vertice = line
            .pointAtLength(line.length() / 2 + gap * factor * Math.ceil(diff))
            .rotate(90, line.getCenter());

          const points = [sourcePoint, vertice, targetPoint];
          const curves = Curve.throughPoints(points);
          const path = new Path(curves);
          return options.raw ? path : path.serialize();
        },
        true
      );
  • 实现效果

这里节点是引入自定义节点Vue组件实现,在该组件中可任意使用iView、Element组件库中各组件。

图1是通过新增按钮触发配置节点信息弹框,通过计算节点将新增在画布的大概中心位置。

图2是通过图片工具栏拖拽自动生成节点。

图1

图2

4. 总结与经验

  • 为节点、连线添加快捷删除工具"button-remove"后如何实现删除拦截二次确认?
php 复制代码
cell.addTools({
              name: "button-remove",
              args: {
                distance: "50%",
                onClick({ view }) {
                   this.$Modal.confirm({
                    title: "提示",
                    content: "是否确认删除该连线",
                    okText: "是",
                    cancelText: "否",
                    onOk: () => {},
                    onCancel: () => {},
                  });
                },
              },
            });
  • 监听手动连线使用connected较为正确,added仅能拿到连线的源端信息
javascript 复制代码
graph.on("edge:connected", ({ isNew, edge }) => {
})
  • 如何为节点动态添加连接桩?
javascript 复制代码
// 展示
  graph.on("cell:mouseenter", ({ cell }) => {
          // 鼠标移入节点上时执行
          if (cell.isNode()) {
          // 展示节点四周的连接桩
            const allPorts = cell.getPorts();
            allPorts.forEach((port) => {
              cell.setPortProp(port.id, "attrs/circle", {
                stroke: "#ed4014",
              });
            });
          }
       })
  
  // 隐藏
 graph.on("cell:mouseleave", ({ cell }) => {
          // 鼠标移除节点时执行
          if (cell.isNode()) {
            //隐藏连接点
            const allPorts = cell.getPorts();
            allPorts.forEach((port) => {
              cell.setPortProp(port.id, "attrs/circle", {
                stroke: "transparent",
              });
            });
      })

5. 遗留问题

  • 两个节点之间的双箭头连线当对角时排列变成两条单箭头连线?
相关推荐
bmxy小明同学3 小时前
2026-10-11-幻觉治理
服务器·前端·javascript
Coder_张三3 小时前
iOS 26 适配
前端·ios·swift
m0_587383003 小时前
无人自助拼豆系统落地开发实战指南 核心逻辑实现与部署经验分享
前端·javascript·vue.js·人工智能·经验分享·需求分析
zhaiyy3 小时前
HTML Popover API 实践
前端·javascript·html
牧艺4 小时前
SPA 也能像原生 App:View Transitions API 从原理到可上线实战
前端·javascript·css
Dovis(誓平步青云)4 小时前
现场问题先关闭还是先验收,建筑任务怎样处理依赖
前端·javascript·数据库·mysql·音视频
用户84298142418104 小时前
压缩 ≠ 加密:前端代码保护的三层实践与踩坑记录
前端·javascript
前端一课4 小时前
别把人生过成一场等待退休的倒计时
前端
CENTER SAYS4 小时前
企业400电话办理全流程详解与材料准备(实操向)
前端·crm
:mnong4 小时前
Web 三维可视化技术对比:ParaView Web vs 本项目 wasm + Three.js
前端·webgl·opengl·opencl·科学可视化