企业级开发中,开箱即用的VUE流程图开发组件 AntV G6

1 篇文章 0 订阅
1 篇文章 0 订阅

什么是 AntV G6 ?

企业级应用开发往往需要使用流程图组件,AntV G6就是一款可以开箱即用的由蚂蚁金服提供的,全新一代数据可视化解决方案,是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力。旨在让关系变得透明,简单。让用户获得关系数据的 Insight

 G6 可以做什么 ?

 上面这些关系图都是它可以轻松搞定的,我们可以通过他快速创建出自己的图分析和编辑引用

如何快速使用G6呢

第一步: 使用命令行在项目目录下执行以下命令:

npm install --save @antv/g6

第二步:在需要的位置引用它

import G6 from '@antv/g6';

 第三步:在引用页面制造容器

<div id="container" style="width:100%;height:500px;"></div>

第四步:在data数据中 ,创建适用的流程图数据

data:  {
    nodeExtraAttrs: {
        begin: {
          fill: 'rgba(24, 144, 255, 0.1)',
          stroke: '#1890FF',
        },
        end: {
          fill: 'rgba(242, 65, 48, 0.1)',
          stroke: '#F24130',
        },
        ORIGINAL: {
          fill: 'rgba(38, 191, 89, 0.1)',
          stroke: '#26BF59',
        },
      },
        nodes: [
           {
            id: 'node1',
            label: 'node1',
            text: null,
            key: 'ORIGINAL',
           
          },
          {
            id: 'node2',
            label: 'node2',
            text: null,
            key: 'begin',
           
          },
          {
            id: 'node3',
            label: 'node3',
            text: 'node3',
            key: 'ORIGINAL',
          },
           {
            id: 'node4',
            label: 'node4',
            text: 'node4',
            key: 'begin',
          },
          {
            id: 'node5',
            label: 'node5',
            text: 'node5',
            key: 'ORIGINAL',
          },
           {
            id: 'node6',
            label: 'node6',
            text: 'node6',
            key: 'end',
          },
          {
            id: 'node7',
            label: 'node7',
            text: 'node7',
            key: 'end',
          },
           {
            id: 'node8',
            label: 'node8',
            text: 'node8',
            key: 'begin',
          },
          {
            id: 'node9',
            label: 'node9',
            text: 'node9',
            key: 'ORIGINAL',
          },
          {
            id: 'node10',
            label: 'node10',
            text: 'node10',
            key: 'begin',
          },
        ],
        edges: [
          {
            source: 'node1',
            target: 'node2',
          },
          {
            source: 'node2',
            target: 'node3',
          },
          {
            source: 'node3',
            target: 'node4',
          },
          {
            source: 'node4',
            target: 'node5',
          },
          {
            source: 'node5',
            target: 'node6',
          },
          {
            source: 'node6',
            target: 'node7',
          },
          {
            source: 'node6',
            target: 'node8',
          },
          {
            source: 'node7',
            target: 'node9',
          },
          {
            source: 'node8',
            target: 'node9',
          },
          {
            source: 'node9',
            target: 'node10',
          },
        ],
      }

第五步:具体实现画流程图的方法 

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) => {
          
            // if(cfg.key==="ORIGINAL")  圆形

            //圆形
            if(cfg.key==="ORIGINAL") {
              // ctg上的id key label 都可以决定当前节点的类型
              cfg.size = (cfg.label.length / 10) * 130;
              let widthX = 2;
              

              const rect = group.addShape('ellipse', {
                attrs: _extends(
                  {
                    x: -widthX / 2,
                    y: 0,
                    rx: 60,
                    ry: 40,
                    fill: 'blue',
                  },
                  this.nodeExtraAttrs[cfg.key]
                ),
              });
              return rect;
            }else{

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

               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: 'container',
        //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 + '<br>');
                // });
                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',
          },
        },
      });


      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,
              },
            },
          };
        }
      });

       // 单击节点
      graph.on('node:click', (e) => {
        const nodeItem = e.item // 获取被点击的节点元素对象
        console.log(nodeItem._cfg)
      })
       // 鼠标进入节点
      graph.on('node:mouseenter', (e) => {
        const nodeItem = e.item // 获取鼠标进入的节点元素对象
        console.log('鼠标移入', nodeItem._cfg)
      })
      // 双击节点
      graph.on('node:dblclick', (e) => {
        const nodeItem = e.item // 获取被点击的节点元素对象
        console.log('双击', nodeItem._cfg)
      })

      graph.data(this.data);
      // 渲染
      graph.render();
    },

第六步:在需要调用的地方进行引用

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

 第七步:完整代码如下

        实现效果如下:

<template>
  <div>
    <div id="container" style="width:100%;height:500px;"></div>
  </div>
</template>

<script>
import G6 from '@antv/g6';
export default {

  components: {
  },
  props: {
    // 是否显示
    page: {
      type: String,
      default: null
    }
  },
  setup() {

  },
  data() {
    return {
      url: null,
      // 保存自定义节点的数据  
      // 一般实际开发中,流程图节点样式都是在自定义的
      nodeExtraAttrs: {
        begin: {
          fill: 'rgba(24, 144, 255, 0.1)',
          stroke: '#1890FF',
        },
        end: {
          fill: 'rgba(242, 65, 48, 0.1)',
          stroke: '#F24130',
        },
        ORIGINAL: {
          fill: 'rgba(38, 191, 89, 0.1)',
          stroke: '#26BF59',
        },
      },
      data:  {
        nodes: [
           {
            id: 'node1',
            label: 'node1',
            text: null,
            key: 'ORIGINAL',
           
          },
          {
            id: 'node2',
            label: 'node2',
            text: null,
            key: 'begin',
           
          },
          {
            id: 'node3',
            label: 'node3',
            text: 'node3',
            key: 'ORIGINAL',
          },
           {
            id: 'node4',
            label: 'node4',
            text: 'node4',
            key: 'begin',
          },
          {
            id: 'node5',
            label: 'node5',
            text: 'node5',
            key: 'ORIGINAL',
          },
           {
            id: 'node6',
            label: 'node6',
            text: 'node6',
            key: 'end',
          },
          {
            id: 'node7',
            label: 'node7',
            text: 'node7',
            key: 'end',
          },
           {
            id: 'node8',
            label: 'node8',
            text: 'node8',
            key: 'begin',
          },
          {
            id: 'node9',
            label: 'node9',
            text: 'node9',
            key: 'ORIGINAL',
          },
          {
            id: 'node10',
            label: 'node10',
            text: 'node10',
            key: 'begin',
          },
        ],
        edges: [
          {
            source: 'node1',
            target: 'node2',
          },
          {
            source: 'node2',
            target: 'node3',
          },
          {
            source: 'node3',
            target: 'node4',
          },
          {
            source: 'node4',
            target: 'node5',
          },
          {
            source: 'node5',
            target: 'node6',
          },
          {
            source: 'node6',
            target: 'node7',
          },
          {
            source: 'node6',
            target: 'node8',
          },
          {
            source: 'node7',
            target: 'node9',
          },
          {
            source: 'node8',
            target: 'node9',
          },
          {
            source: 'node9',
            target: 'node10',
          },
        ],
      }
    }
  },
  watch: {
    page: {
      handler(val, oldV) {
        this.url = val
        switch (val) {
          case '物料工程':
            this.url = '/diagram/wuliaogongcheng.html'
            break
          default :
            console.log('step other')
        }
      },
      immediate: true
    }
  },
  created() {
    
  },
  mounted() {
    this.$nextTick(() => {
      this.drawView();
    });
  },
  methods: {
    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) => {
          
            // if(cfg.key==="ORIGINAL")  圆形

            //圆形
            if(cfg.key==="ORIGINAL") {
              // ctg上的id key label 都可以决定当前节点的类型
              cfg.size = (cfg.label.length / 10) * 130;
              let widthX = 2;
              

              const rect = group.addShape('ellipse', {
                attrs: _extends(
                  {
                    x: -widthX / 2,
                    y: 0,
                    rx: 60,
                    ry: 40,
                    fill: 'blue',
                  },
                  this.nodeExtraAttrs[cfg.key]
                ),
              });
              return rect;
            }else{

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

               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: 'container',
        //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 + '<br>');
                // });
                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',
          },
        },
      });


      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,
              },
            },
          };
        }
      });

       // 单击节点
      graph.on('node:click', (e) => {
        const nodeItem = e.item // 获取被点击的节点元素对象
        console.log(nodeItem._cfg)
      })
       // 鼠标进入节点
      graph.on('node:mouseenter', (e) => {
        const nodeItem = e.item // 获取鼠标进入的节点元素对象
        console.log('鼠标移入', nodeItem._cfg)
      })
      // 双击节点
      graph.on('node:dblclick', (e) => {
        const nodeItem = e.item // 获取被点击的节点元素对象
        console.log('双击', nodeItem._cfg)
      })

      graph.data(this.data);
      // 渲染
      graph.render();
    },
  }

}
</script>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值