使用antv/x6绘制vue流程表单

Antv/X6介绍

简介

X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和开箱即用的内置扩展,方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。 图编辑核心能力:节点、连线与画布,可使用React、Vue、Angular组件节点

开始使用

创建画布

容器 复制代码
<div ref="containerRef" class="x6-container"></div>
csharp 复制代码
import { ref, watch, onMounted, onUnmounted } from "vue"
import { Graph } from "@antv/x6";
const containerRef = ref(ref)
const graph = new Graph({
  container: containerRef.value
})
    
onUnmounted(() => {
    graph.dispose() // 销毁
})

尺寸:初始创建可使用width:1200和height:600属性指定画布大小,默认是容器宽高

js 复制代码
const ports = {
    groups: {
      top: {
        position: "top",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden"
            }
          }
        }
      },
      right: {
        position: "right",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden"
            }
          }
        }
      },
      bottom: {
        position: "bottom",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden"
            }
          }
        }
      },
      left: {
        position: "left",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden"
            }
          }
        }
      }
    },
    items: [
      {
        group: "top"
      },
      {
        group: "right"
      },
      {
        group: "bottom"
      },
      {
        group: "left"
      }
    ]
  }
  
  new Graph({
  container: containerRef.value,
  ports: {
      ...ports
  }
})

使用ports指定连接桩内置有上下左右点,按照节点尺寸设置,也可使用position: [88, 62]具体坐标添加连接桩,节点内部组件可以溢出节点显示(组件尺寸比节点指定尺寸大),可指定位置保证连接桩在显示区域边上

js 复制代码
  const nodeMouseenter = () => {
    const container = containerRef.value
    const ports = container.querySelectorAll(".x6-port-body")
    showPorts(ports, true)
  }
  const nodeMouseleave = () => {
    const container = containerRef.value
    const ports = container.querySelectorAll(".x6-port-body")
    showPorts(ports, false)
  }
    graph.on("node:mouseenter", nodeMouseenter)
    graph.on("node:mouseleave", nodeMouseleave)

连接桩默认隐藏,使用画布监听事件控制显示隐藏

js 复制代码
new Graph({
    connecting:{
        router: "manhattan",
        connector: {
          name: "rounded",
          args: {
            radius: 8
          }
        },
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: false,
        snap: {
          radius: 20
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#1890FF",
                strokeWidth: 2,
                targetMarker: {
                  name: "block",
                  width: 12,
                  height: 8
                }
              }
            },
            zIndex: 0
          })
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet
        }
      }
  }

Edge(边/连线)使用connecting属性设置,画布手动连接的线会使用此配置,在创建Edge时需要单独设置,边的路径类型,颜色、箭头都可以设置

js 复制代码
import { Dnd } from "@antv/x6-plugin-dnd"
dnd = new Dnd({
  target: graph,
  scaled: false,
  dndContainer: nodeContainerRef.value,
  validateNode: (cls, node) => {
    ...
    return false
  }
})

X6通过Dnd组件内置节点拖拽功能,指定节点拖拽容器和画布,validateNode为拖拽回调,可在此控制节点添加行为或者使用内置的Stencil插件创建拖拽部分

js 复制代码
import { Scroller } from "@antv/x6-plugin-scroller"
 graph.use(
   new Scroller({
     enabled: true,
     pannable: false
   })
 )

X6内置了滚动功能,使用插件开启,可滚动和鼠标拖动,鼠标操作可能会有冲突按使用场景控制

js 复制代码
graph = new Graph({
      container: containerRef.value,
      interacting: () => {
        return false
      },
      ...
    })
javascript 复制代码
translating: {
        restrict(view) {
          if (view) {
            const cell = view.cell
            if (cell.isNode()) {
              const parent = cell.getParent()
              if (parent) {
                return parent.getBBox()
              }
            }
          }
          return null
        },
      },

X6内置多种方法可以控制画布节点拖动行为,可以使用tanslating设置控制,设置{ restrict: false/true }或者指定函数控制(可指定[x,y]范围控制),实际使用中控制节点完全不允许移动,实践下来translating单节点没有问题,Group添加子节点之后父节点移动控制有问题,姿势不对或者是bug,使用interacting属性可以控制节点完全不移动

js 复制代码
graph.on("node:mouseenter", ({ node }) => {
      node.addTools([
        {
          name: "button-remove",
          args: {
            x: node.shape === "node-select-point" ? 176 : 260,
            y: 0,
            onClick({ cell }) {
                graph.removeNode(cell)
            }
          }
        }
      ])
    })
    graph.on("node:mouseleave", ({ node }) => {
      if (node.hasTool("button-remove")) {
        node.removeTool("button-remove")
      }
    })

X6有内置小组件,可动态添加删除按钮删除节点,可使用onClick指定删除行为或者不指定使用默认删除

Node节点

js 复制代码
    graph.createNode({
      shape: 'rect',
      data: {
      },
      ...
    })

可以使用createNode方法或者addNode方法创建节点使用shape指定类型返回值为节点

js 复制代码
<template>
<TeleportContainer></TeleportContainer>
</template>
import { register, getTeleport } from "@antv/x6-vue-shape"
const TeleportContainer = getTeleport()

register({
      shape: '...',
      width: 100,
      height: 100,
      component: ...,
      ports: {
        ...ports
      }
    })
graph.createNode({
  shape: '...',
  data: {
    parent: null,
    children: []
  }
})

使用Vue组件节点需要先使用register注册shape,使用时创建节点指定shape名称即可

js 复制代码
    graph.on("cell:added", ({ cell, index, options }) => {
    })
    graph.on("cell:removed", ({ cell, index, options }) => {
    }

可监听事件回调,处理对用逻辑

X6节点有群组概念,可使用节点addChild方法添加子节点建立父子关系,可使用graph.getNodes方法获取节点(注:使用toJSON方法获取的节点没有cell类等继承方法),使用getNodes获取的都是节点类型,Group通过children获取的子节点包含节点和边

Edge边/连线

js 复制代码
graph.createEdge({
      source: { cell: id, port: id : id },
      target: { cell: id, port: id},
      router: "normal",
      attrs: {
        line: {
          stroke: "#586C90",
          strokeWidth: 2,
          targetMarker: {
            name: "block",
            width: 12,
            height: 8
          }
        }
      }
    })
    graph.addEdge(edge)

可使用createEdge或者addEdge方法创建边/连接线,指定连接点可使用节点和连接桩id建立连接或者直接指定连接坐标[x,y]来连线,手动创建连线需要指定连线配置,不共用画布连接线设置。

流程表单

使用Vue节点创建的组件和普通Vue节点没本质区别,但是其是由X6托管,和项目Vue组件之间没有关联关系,内部数据交互需要使用pinia/vuex或者node节点data来管理

js 复制代码
export default defineComponent({
  name: 'ProgressNode',
  inject: ['getNode'],
  data() {
    return {
      percentage: 80,
    }
  },
  mounted() {
    const node = (this as any).getNode() as Node
    node.on('change:data', ({ current }) => {
      const { progress } = current
      this.percentage = progress
    })
  },
})

Vue节点内部可使用inject("getNode")获取节点,通过监听节点方法来获取节点数据

js 复制代码
 import { useStore } from "@/store/..."
 const store = useStore()
 const getNode = inject("getNode")
  const node = getNode()
  const id = node.id

节点可使用节点id通过pinia来管理节点内部表单数据,外部组件和X6Vue节点交互都需要通过pinia来进行。数据变动通过watch监听pinia变动来更新。

可以通过toJSON和fromJSON方法来保存流程图和还原流程图,X6托管的Vue节点没有生命周期回调,还原表单数据是需要注意等Vue节点都mounted之后再触发pinia数据更新触发内部watch回填表单数据

相关推荐
持续前行11 小时前
vscode 中找settings.json 配置
前端·javascript·vue.js
JosieBook11 小时前
【Vue】11 Vue技术——Vue 中的事件处理详解
前端·javascript·vue.js
安逸点11 小时前
Vue项目中使用xlsx库解析Excel文件
vue.js
一只小阿乐11 小时前
vue 改变查询参数的值
前端·javascript·vue.js·路由·router·网文·未花中文网
小酒星小杜12 小时前
在AI时代下,技术人应该学会构建自己的反Demo地狱系统
前端·vue.js·ai编程
Code知行合壹12 小时前
Pinia入门
vue.js
今天也要晒太阳47312 小时前
element表单和vxe表单联动校验的实现
vue.js
依赖_赖13 小时前
前端实现token无感刷新
前端·javascript·vue.js
hhcccchh14 小时前
学习vue第十三天 Vue3组件深入指南:组件的艺术与科学
javascript·vue.js·学习
zhengxianyi51514 小时前
ruoyi-vue-pro本地环境搭建(超级详细,带异常处理)
前端·vue.js·前后端分离·ruoyi-vue-pro