Vue + AntV X6 流程图在线编辑器(一)

11,002 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

前言

流程图在线编辑器是信息系统中常用的功能,公司新的项目中有这样的需求,查阅资料后发现AntV X6 可以实现项目需求,让我们一起来学习如何使用AntV X6 来打造一个流程图在线编辑器吧!

官网:x6.antv.vision/zh

项目代码: vue-antvx6

image.png

整体布局

整体布局可以分为三个区域:

  1. 头部区域:工具栏。
  2. 中部区域:流程面板。
  3. 右侧区域:画布/节点/线条操作配置,可拓展更多的配置项。

编辑器实现的功能:

  1. 在工具栏中选择不同的图形节点,拖拽至流程面板中;
  2. 可以选择不同的线条样式连接节点;
  3. 选中节点/线条,可对其挂载的内容进行修改;
  4. 可删除指定节点或清空面板所有内容;
  5. 将流程及其节点以Json格式输出。

安装

vue 安装流程不再详细记录,安装 antv x6 时建议使用 yarn 命令安装,否则 x6-vue-shape 会出现安装失败的问题。

# yarn
$ yarn add @antv/x6

# yarn
yarn add @antv/x6-vue-shape

# 在 vue2 下还需要安装 @vue/composition-api
yarn add @vue/composition-api --dev

开始使用

1. 创建容器

创建一个用于容纳X6绘图的容器,主要内容就在这里面显示

<div id="containerChart"></div>

2. 创建画布

  • history.undo() 撤销。options 将被传递到事件回调中。
  • history.redo() 重做。options 将被传递到事件回调中。
  • enablePanning() 启用画布平移。
  • enableMouseWheel() 启用鼠标滚轮缩放画布。
import '@antv/x6-vue-shape'
import { Graph, Shape, Addon, FunctionExt, DataUri } from '@antv/x6'
const data = {}
export default {
    data() {
      return {
        graph:'',
        connectEdgeType:{  //连线方式
          connector: 'normal',
          shape: 'custom-edge-label',
          router: {
            name: ''
          }
        },
        grid:{ // 网格设置
          size: 20,      // 网格大小 10px
          visible: true, // 渲染网格背景
          type: 'mesh',
          args: {
            color: '#D0D0D0',
            thickness: 1, // 网格线宽度/网格点大小
            factor: 10
          }
        }
      }
    },
    mounted () {
        this.initX6()
    },
    methods: {
        initX6(){
          var _that = this
          this.graph = new Graph({
            container: document.getElementById('containerChart'),
            width: 1700,
            height: '100%',
            grid: _that.grid,
            resizing: { // 调整节点宽高
              enabled: true,
              orthogonal:false,
            }, 
            selecting: true, // 可选
            snapline:  true,
            interacting: {
              edgeLabelMovable: true
            },
            connecting: { // 节点连接
              anchor: 'center',
              connectionPoint: 'anchor',
              allowBlank: false,
              snap: true,
              createEdge () {
                return new Shape.Edge({
                  attrs: {
                    line: {
                      stroke: '#1890ff',
                      strokeWidth: 1,
                      targetMarker: {
                        name: 'classic',
                        size: 8
                      },
                      strokeDasharray: 0, //虚线
                      style: {
                        animation: 'ant-line 30s infinite linear',
                      }
                    }
                  },
                  label: {
                    text:''
                  },
                  connector: _that.connectEdgeType.connector,
                  router: {
                    name: _that.connectEdgeType.router.name || ''
                  },
                  zIndex: 0
                })
              }
            },
            highlighting: {
              magnetAvailable: {
                name: 'stroke',
                args: {
                  padding: 4,
                  attrs: {
                    strokeWidth: 4,
                    stroke: '#6a6c8a'
                  }
                }
              }
            },
          });
          insertCss(`
            @keyframes ant-line {
              to {
                  stroke-dashoffset: -1000
              }
            }
          `)
          this.graph.fromJSON(data)
          this.graph.history.redo()
          this.graph.history.undo()
          this.graph.enablePanning()
          this.graph.enableMouseWheel()
          // 鼠标移入移出节点
          this.graph.on('node:mouseenter',FunctionExt.debounce(() => {
            const container =  document.getElementById('containerChart')
            const ports = container.querySelectorAll(
              '.x6-port-body'
            )
            this.showPorts(ports, true)
          }), 500)
          this.graph.on('node:mouseleave', () => {
            const container =  document.getElementById('containerChart')
            const ports = container.querySelectorAll(
              '.x6-port-body'
            )
            this.showPorts(ports, false)
          })
          this.graph.on('blank:click', () => {
            this.type = 'grid'
          })
          this.graph.on('cell:click', ({ cell }) => {
            this.type = cell.isNode() ? 'node' : 'edge'
          })
          this.graph.on('selection:changed', (args) => {
            args.added.forEach(cell => {
              this.selectCell = cell
              if(cell.isEdge()){
                cell.isEdge() && cell.attr('line/strokeDasharray', 5) //虚线蚂蚁线
                cell.addTools([
                  {
                    name: 'vertices',
                    args: {
                      padding: 4,
                      attrs: {
                        strokeWidth: 0.1,
                        stroke: '#2d8cf0',
                        fill: '#ffffff',
                      }
                    }
                  }
                ])
              }
            })
            args.removed.forEach(cell => {
              cell.isEdge() && cell.attr('line/strokeDasharray', 0)  //正常线
              cell.removeTools()
            })
          })
      }
    }
}

以上,画布就已经创建完毕,在页面上就可以看到画布的样式啦~ 注意:初始化的方法需要放在mounted内,放在 created 内会加载不出来样式。

结语

画布已经创建好了,明天让我们继续学习关于节点的内容吧(ง •_•)ง

image.png