企业开发中,如何在Vue中实现流程图

企业开发中,如何在Vue中实现流程图

这是我在工作中,vue项目中,实现画出业务流程图,使用方法如以下:

1、安装依赖

这里使用第三方插件:@antv/g6

详见官网@antv/g6

$ npm install --save @antv/g6

2、在使用的组件中导入依赖

import G6 from '@antv/g6';

3、在视图模板中创建流程图容器

<div id="流程图容器的id">div>

4、在data中,创建保存流程图数据的状态变量

data() {
    return {
      // 保存自定义节点的数据  
      // 一般实际开发中,流程图节点样式都是在自定义的
      nodeExtraAttrs: {
        begin: {
          fill: 'rgba(24, 144, 255, 0.1)',
          stroke: '#1890FF',
        },
        end: {
          fill: 'rgba(242, 65, 48, 0.1)',
          stroke: '#F24130',
        },
        接口返回的nodes字段的key: {
          fill: 'rgba(38, 191, 89, 0.1)',
          stroke: '#26BF59',
        }
      },
      // 这块的数据都是后台接口返回的
      // 节后按照g6插件的配置字段返回数据的
      // 所以这块要和后端沟通好
      data: {
        nodes: [
          {
            id: '节点起始id',
            label: 'name',
            key: 'ACTION',
            text: null,
          },
          {
            id: '节点结束id',
            label: 'name',
            key: 'ORIGINAL',
            text: '带标签的字符串',
          },
        ],
        edges: [
          {
            source: '节点起始id',
            target: '节点结束id',
          },
        ],
      },
    };
  },

5、实现画流程的方法

drawView() {
      // 重写方法
      const _extends =
        Object.assign ||
        function (target) {
          for (let i = 1; i < arguments.length; i++) {
            const source = arguments[i];
            for (const key in source) {
              if (Object.prototype.hasOwnProperty.call(source, key)) {
                target[key] = source[key];
              }
            }
          }
          return target;
        };
      // 自定义节点   内置节点无法满足需求
      // G6.registerNode(typeName: string, nodeDefinition: object, extendedTypeName?: string)
      G6.registerNode(
         // 该新节点类型名称
        'node', 
        // 该新节点类型的定义
        // 当有 extendedTypeName (第三个参数)时,没被复写的函数将会继承 extendedTypeName 的定义
        {
          // cfg  节点身上所有的配置:包括label,size,x,y坐标等 

          // 这个方法,每渲染一个节点,执行一次
          drawShape: (cfg, group) => {
            // ctg上的id key label 都可以决定当前节点的类型
            cfg.size = (cfg.label.length / 10) * 130;
            let widthX = 0;
            if (cfg.label.length / 10 < 1) {
              widthX = 120;
            } else {
              widthX = cfg.size;
            }
            // if(cfg.key==="ORIGINAL")  圆形
            const rect = group.addShape('rect', {
              attrs: _extends(
                {
                  x: -widthX / 2,
                  y: -25,
                  width: widthX,
                  height: 50,
                  radius: 4,
                  fill: '#FFD591',
                  fillOpacity: 1,
                },
                // 相当于:
                // ORIGINAL: {
                //   fill: 'rgba(38, 191, 89, 0.1)',
                //   stroke: '#26BF59',
                // },

                // 属性为fill 和 stroke的对象
                this.nodeExtraAttrs[cfg.key]
              ),
            });
            return rect;
          },
          /**
           * 获取锚点(相关边的连入点)
           * @param  {Object} cfg 节点的配置项
           * @return {Array|null} 锚点(相关边的连入点)的数组,如果为 null,则没有控制点
           */
          // 自定义锚点
          getAnchorPoints: () => {
            return [
              [0, 0.5], // 左侧中间
              [1, 0.5], // 右侧中间
            ];
          },
        },
        // 被继承的节点类型,可以是内置节点类型名,也可以是其他自定义节点的类型名。
        // extendedTypeName 未指定时代表不继承其他类型的节点;
        // 例如基类 'single-node',或 'circle', 'rect' 等
        'single-shape'
      );
      /**
       * 自定义带箭头的贝塞尔曲线 edge
       */
      G6.registerEdge('line-with-arrow', {
        itemType: 'edge',
        draw: (cfg, group) => {
          const startPoint = cfg.startPoint;
          const endPoint = cfg.endPoint;
          const centerPoint = {
            x: (startPoint.x + endPoint.x) / 2,
            y: (startPoint.y + endPoint.y) / 2,
          };
          // 控制点坐标
          const controlPoint = {
            x: (startPoint.x + centerPoint.x) / 2,
            y: startPoint.y,
          };
          // 为了更好的展示效果, 对称贝塞尔曲线需要连到箭头根部
          const path = group.addShape('path', {
            attrs: {
              path: [
                ['M', startPoint.x, startPoint.y],
                ['Q', controlPoint.x, controlPoint.y, centerPoint.x, centerPoint.y],
                ['T', endPoint.x, endPoint.y],
                ['L', endPoint.x, endPoint.y],
              ],
              stroke: '#ccc',
              lineWidth: 1.6,
              endArrow: {
                path: 'M 4,0 L -4,-4 L -4,4 Z',
                d: 4,
              },
            },
          });
          return path;
        },
      });
      const graph = new G6.Graph({
        // 常用配置项 
        // 类型:Boolean;默认:'false'。图是否自适应画布。
        fitView: true,
        // 类型:Number | Array;默认:0。图自适应画布时的四周留白像素值。fitView 为 true 时生效。
        // fitViewPadding : 0
        // 类型:Boolean;默认:'false'。是否平移图使其中心对齐到画布中心。v3.5.1 后支持。
        fitCenter: true,
        // bloodView:流程图容器id
        container: '流程图容器的id',
        //modes 交互行为相关
        // 配置多种交互模式及其包含的交互事件的。
        modes: {
          default: [
            'drag-canvas',
            'zoom-canvas',
            {
              type: 'tooltip',
              formatText(model) {
                const cfg = model.text;
                const text = model.text;
                // cfg.forEach((row) => {
                //   text.push(row.label + ':' + row.value + '
');
// }); return text; }, offset: 30, }, ], }, // 若数据中不存在节点位置,则默认为随机布局。配置布局类型及其参数。 layout: { // 类型 总共三种:径向:radial 有向分层:dagre 力导:force type: 'dagre', // 'LR':从左至右布局; rankdir: 'LR', // 可选可选值:'TB' | 'BT' | 'LR' | 'RL',默认为图的中心 TB }, // defaultNode类型:Object。默认情况下全局节点的配置项,包括样式属性和其他属性 // G6 的内置节点包括 // circle圆形,rect长方形,ellipse椭圆,diamond菱形,triangle三角形, // star五角星,image图片,modelRect卡片,donut圆形(v4.2.5 起支持)。 defaultNode: { type: 'node', // 这里的type指向自定义节点 // size:300, labelCfg: { style: { fill: '#595959', fontSize: 14, }, }, }, // defaultEdge 类型:Object。默认情况下全局边的配置项,包括样式属性和其他属性 defaultEdge: { type: 'line-with-arrow', style: { endArrow: true, lineWidth: 2, stroke: '#ccc', }, }, }); graph.data(this.data); // 渲染 graph.render(); },

6、 在获取到数据接口后调用画流程图的方法

this.$nextTick(() => {
 this.drawView();
});

注意: 因为调用接口是异步,不能保证获取到画布的容器元素,所以需要把调用drawView方法放在$nextTick里面

7、实际开发中不同的需求实现

7.1 节点边edge添加图形,且图形上附带文字,如图所示

企业开发中,如何在Vue中实现流程图_第1张图片
代码实现如下

const graph = new G6.Graph({
  container: 'container',
  defaultEdge: {
    labelCfg: {  // 设置边上的文字
      autoRotate: true,
      style: {
        fill: '#1890ff', // 文字颜色
        fontSize: 14, // 文字大小
        background: {
          fill: '#ffffff',  // 背景填充颜色
          stroke: '#9EC9FF',  // 边
          padding: [2, 2, 2, 2], // 矩形
          radius: 2,  // 圆角
        },
      },
    },
  },
});

不同边上的矩形样式,可以在流程图数据edges数组上区别,如下

this.data.edges.forEach((item, index) => {
  if (item.upstreamKey === 'WORK') {
    item.labelCfg = {
      autoRotate: true,
      style: {
        fill: '#262626', //  文字颜色
        fontSize: 10,
        cursor: 'pointer',
        background: {
          fill: 'rgba(38, 191, 89, 0.1)',
          stroke: '#26BF59',
          padding: [4.5, 16.5, 4.5, 16.5],
          radius: 2,
        },
      },
    };
  } else if (item.upstreamKey === 'ORIGINAL') {
    item.labelCfg = {
      autoRotate: true,
      style: {
        fill: '#262626', //  文字颜色
        fontSize: 10,
        cursor: 'pointer',
        background: {
          fill: 'rgba(255, 167, 64, 0.1)',
          stroke: '#FFA740',
          padding: [4.5, 16.5, 4.5, 16.5],
          radius: 2,
        },
      },
    };
  } else if (item.upstreamKey === 'FINAL') {
    item.labelCfg = {
      autoRotate: true,
      style: {
        fill: '#262626', //  文字颜色
        fontSize: 10,
        cursor: 'pointer',
        background: {
          fill: 'rgba(24, 144, 255, 0.1)',
          stroke: '#1890FF',
          padding: [4.5, 16.5, 4.5, 16.5],
          radius: 2,
        },
      },
    };
  }
});

你可能感兴趣的:(web前端,实际开发总结-前端,knowledge,graph)