antV G6流程图在Vue中的使用

2018/12/18 16:23
阅读数 495

<blockquote>最近我司项目中需要加入流程图制作功能,于是乎百度各种找可视化绘制拓扑图的轮子,大部分都是国外的,看文档太吃力,不过好在最终让我发现了AntV G6流程图图表库,最新版为2.0,不过编辑器在2.0版本还没有进行开源,所以只能退而求其次,使用了1.2.8版本。希望2.0版本的编辑器尽早开源,在交互方面1.2.8版本还是差了一些。<p>该组件并<strong><code>非开箱即食</code></strong>,需要根据自己的业务进行修改,右侧属性表单部分如果有时间考虑改为插槽形式,方便以后复用~</p> </blockquote> <a href="http://www.jqhtml.com/24333.html" target="_blank">如何将数据进行数据可视化展现?</a> <h3>技术栈</h3> <ul> <li> <a href="https://cn.vuejs.org/" rel="nofollow noreferrer">Vue</a> <code>v3.0.1</code> </li> <li> <a href="http://element.eleme.io/#/zh-CN" rel="nofollow noreferrer">Element-ui</a> <code>v2.4.5</code> </li> <li> <a href="http://antvis.github.io/g6/api/index.html" rel="nofollow noreferrer">antV G6</a> <code>v1.2.8</code> </li> <li>Sass</li> </ul> <h3>效果图</h3>

在这里插入图片描述

<h3>引入</h3> <p>在<code>index.html</code>中进行了全局引用</p>



&lt;script src="./static/plugin/g6.min.js"&gt;&lt;/script&gt;

<h3>实例代码</h3> <p>仿照2.0版本的编辑器将G6作为了一个组件使用,代码:</p>


&lt;template&gt;
  &lt;div id="flowChart"&gt;
    &lt;div class="operating"&gt;
      &lt;div class="btn-group"&gt;
        &lt;div class="btn" @click="addCircle" title="起始节点"&gt;
          &lt;i class="iconfont icon-circle-oeps"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="addRect" title="常规节点"&gt;
          &lt;i class="iconfont icon-square-oeps"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="addRhombus" title="条件节点"&gt;
          &lt;i class="iconfont icon-square-ling"&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="btn-group"&gt;
        &lt;div class="btn" @click="addLine" title="直线"&gt;
          &lt;i class="iconfont icon-zhixian"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="addSmooth" title="曲线"&gt;
          &lt;i class="iconfont icon-quxian"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="addArrowLine" title="箭头直线"&gt;
          &lt;i class="iconfont icon-jiantouzhixian"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="addArrowSmooth" title="箭头曲线"&gt;
          &lt;i class="iconfont icon-jiantouquxian"&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="btn-group"&gt;
        &lt;div class="btn" @click="changeMode('edit')" title="选择模式"&gt;
          &lt;i class="iconfont icon-chose"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="changeMode('drag')" title="拖拽模式"&gt;
          &lt;i class="iconfont icon-move"&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="btn-group"&gt;
        &lt;div class="btn" @click="del" style="margin-top: 5px;" title="删除"&gt;
          &lt;i class="el-icon-delete"&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="btn" @click="save" title="保存"&gt;
          &lt;i class="iconfont icon-baocun"&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="btn-group"&gt;
        &lt;el-input size="mini" v-model="workflowName" placeholder="请输入流图名称..."&gt;&lt;/el-input&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="info"&gt;
      &lt;div class="title"&gt;
        &lt;span&gt;{{infoTitle}}属性&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class="content"&gt;
        &lt;el-checkbox v-if="isBlank === true" v-model="checked"&gt;网格对齐&lt;/el-checkbox&gt;
        &lt;el-form v-else label-position="left" label-width="60px"&gt;
          &lt;el-form-item v-if="isNode !== true" label="动作"&gt;
            &lt;el-select v-model="action" size="mini" filterable placeholder="绑定动作" value=""&gt;
              &lt;el-option
                v-for="item in actionList"
                :key="item.id"
                :label="item.label"
                :value="item.id"&gt;
              &lt;/el-option&gt;
            &lt;/el-select&gt;
          &lt;/el-form-item&gt;   &lt;!-- 线--&gt;
          &lt;el-form-item v-if="isNode === true" label="名称"&gt;
            &lt;el-input size="mini" v-model="name"&gt;&lt;/el-input&gt;
          &lt;/el-form-item&gt;
          &lt;el-form-item v-if="isNode === true" label="功能"&gt;
            &lt;el-select v-model="func" size="mini" filterable placeholder="绑定功能" value=""&gt;
              &lt;el-option
                v-for="item in funcList"
                :key="item.id"
                :label="item.label"
                :value="item.id"&gt;
              &lt;/el-option&gt;
            &lt;/el-select&gt;
          &lt;/el-form-item&gt;
          &lt;el-form-item v-if="isNode === true" label="账号"&gt;
            &lt;el-select v-model="account" size="mini" filterable multiple
                       collapse-tags placeholder="绑定账号" value=""&gt;
              &lt;el-option
                v-for="item in accountList"
                :key="item.id"
                :label="item.label"
                :value="item.id"&gt;
              &lt;/el-option&gt;
            &lt;/el-select&gt;
          &lt;/el-form-item&gt;
          &lt;el-form-item v-if="isNode === true" label="流图"&gt;
            &lt;el-select v-model="workflow" size="mini" filterable clearable placeholder="绑定流图" value=""&gt;
              &lt;el-option
                v-for="item in workflowList"
                :key="item.id"
                :label="item.label"
                :value="item.id"&gt;
              &lt;/el-option&gt;
            &lt;/el-select&gt;
          &lt;/el-form-item&gt;
          &lt;el-form-item v-if="isNode === true" label="类型"&gt;
            &lt;el-select v-model="nodeType" size="mini" filterable placeholder="请选择类型" value=""&gt;
              &lt;el-option
                v-for="item in nodeTypeList"
                :key="item.id"
                :label="item.label"
                :value="item.id"&gt;
              &lt;/el-option&gt;
            &lt;/el-select&gt;
          &lt;/el-form-item&gt;
          &lt;el-form-item label="颜色"&gt;
            &lt;el-color-picker v-model="color"&gt;&lt;/el-color-picker&gt;
          &lt;/el-form-item&gt;
        &lt;/el-form&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;

  export default {
    name: "index",
    components: {},
    mounted() {
      this.initG6();
    },
    props: {
      actionList: {
        type: Array, default: []
      },
      funcList: {
        type: Array, default: []
      },
      accountList: {
        type: Array, default: []
      },
      workflowList: {
        type: Array, default: []
      },
      nodeTypeList: {
        type: Array, default: () =&gt; {
          return [
            {id: 0, label: '普通节点'},
            {id: 1, label: '入口节点'},
            {id: 2, label: '出口节点'}
          ]
        }
      }
    },
    data() {
      return {
        action: '',
        name: '',
        func: '',
        account: '',
        workflow: '',
        nodeType: 0,
        color: '',

        net: '',
        Util: '',
        workflowName: '',
        activation: '', //当前激活的节点
        isNode: false, //当前是节点
        isBlank: true,   //当前是空白区
        checked: true,  //网格对齐
        infoTitle: '画布',//属性标题
        oldColor: '',    //获取节点本身颜色
        type: '',        //有值为编辑状态
      }
    },
    methods: {
      initG6() {
        let self = this;
        self.Util = G6.Util;
        let grid;
        if (self.checked) {
          grid = {
            forceAlign: true, // 是否支持网格对齐
            cell: 25,         // 网格大小
          };
        } else {
          grid = null;
        }
        self.net = new G6.Net({
          id: 'flowChart',      // 容器ID
          mode: 'edit',
          grid: grid,
          /*width: 500,    // 画布宽*/
          height: 800    // 画布高
        });
        /*self.net.tooltip({
          title: '信息', // @type {String} 标题
          split: ':',  // @type {String} 分割符号
          dx: 0,       // @type {Number} 水平偏移
          dy: 0        // @type {Number} 竖直偏移
        });*/

        /**
         *点击空白处
         */
        self.net.on('click', (ev) =&gt; {
          if (!self.Util.isNull(ev.item)) {
            self.isBlank = false
          } else {
            self.isBlank = true;
            self.infoTitle = '画布'
          }
        });
        /**
         *点击节点
         */
        self.net.on('itemclick', function (ev) {
          self.isNode = self.Util.isNode(ev.item);   //是否为Node
          self.activation = ev.item;
          if (self.isNode) {
            /* 激活节点后节点名称input聚焦*/
            self.$nextTick(()=&gt;{
              self.$refs.inputFocus.$el.querySelector('input').focus();
            });
            self.infoTitle = '节点';
            self.name = ev.item.get('model').label;
            self.func = ev.item.get('model').func;
            self.account = ev.item.get('model').account || [];
            self.workflow = ev.item.get('model').workflow;
            self.nodeType = ev.item.get('model').nodeType;
          } else {
            self.infoTitle = '边';
            self.action = ev.item.get('model').action;
          }
          self.color = self.oldColor;
        });
        /**
         * 鼠标移入移出事件改变颜色
         */
        self.net.on('itemmouseenter', ev =&gt; {
          const item = ev.item;
          self.oldColor = item.get('model').color;     //获取节点颜色
          self.net.update(item, {
            color: '#108EE9',
          });
          self.net.refresh();
        });
        self.net.on('itemmouseleave', ev =&gt; {
          const item = ev.item;
          self.net.update(item, {
            color: self.oldColor
          });
          self.net.refresh();
        });
        /**
         * 提示信息
         */
       /* self.net.node().tooltip(['label', 'func', 'role', 'color']);
        self.net.edge().tooltip(['label', 'color']);*/
        /**
         * 渲染
         */
        /*self.net.source(self.nodes, self.edges);*/  //加载资源数据
        self.net.render();
      },
      addCircle() {
        this.net.beginAdd('node', {
          shape: 'circle',
          nodeType: 0
        })
      },//添加起始节点
      addRect() {
        this.net.beginAdd('node', {
          shape: 'rect',
          nodeType: 0
        })
      },//添加常规节点
      addRhombus() {
        this.net.beginAdd('node', {
          shape: 'rhombus',
          nodeType: 0
        })
      }, //添加条件节点
      addLine() {
        this.net.beginAdd('edge', {
          shape: 'line'
        });
      }, //添加直线
      addSmooth() {
        this.net.beginAdd('edge', {
          shape: 'smooth'
        })
      },  //添加曲线
      addArrowSmooth() {
        this.net.beginAdd('edge', {
          shape: 'smoothArrow'
        })
      }, //添加箭头曲线
      addArrowLine() {
        this.net.beginAdd('edge', {
          shape: 'arrow'
        });
      }, //添加箭头直线
      addPolyLine() {
        this.net.beginAdd('edge', {
          shape: 'polyLineFlow'
        });
      }, //添加折线
      changeMode(mode) {
        this.net.changeMode(mode)
      }, //拖拽与编辑模式的切换
      del() {
        this.net.del()
      },//删除
      save() {
        /* 验证流图名称*/
        if (this.workflowName !== '') {
          let data = this.net.save();
          if (data.source.nodes.length === 0) {
            this.$message({type: 'error', message: '流图内容不能为空'});
            return false
          }
          /* 验证节点名称*/
          for (let item of data.source.nodes) {
            if (item.label === '' || item.label === null || item.label === undefined) {
              this.$message({type: 'error', message: '节点名称不能为空'});
              return false
            }
          }
          data.source['name'] = this.workflowName;
          /*let json = JSON.stringify(data, null, 2);*/
          this.$emit('saveData', data.source, this.type);
        } else {
          this.$message({type: 'error', message: '流图名称不能为空'})
        }
        /*console.log(saveData, json);*/
      },//保存
      update() {
        if (this.activation.get('type') === 'node') {
          this.net.update(this.activation, {
            label: this.name,
            func: this.func,
            account: this.account,
            workflow: this.workflow,
            nodeType: this.nodeType,
            color: this.color
          });
        } else {
          /* 根据ID取出label*/
          let label = this.actionList.map(item =&gt; {
            if (item.id === this.action) {
              return item.label
            }
          }).join('');
          this.net.update(this.activation, {
            label: label,
            color: this.color,
            action: this.action
          });
        }
      },  //更新节点
      clearView() {
        this.type = '';
        this.workflowName = '';
        this.net.changeData()
      },   //清空视图
      source(nodes, edges, name, type) {
        this.type = type;
        this.workflowName = name;
        this.net.changeData(nodes, edges)
      },  //更新数据
    },
    watch: {
      /**
       * 监听输入框
       */
      action: function () {
        this.update()
      },
      name: function () {
        this.update()
      },
      func: function () {
        this.update()
      },
      account: function () {
        this.update()
      },
      workflow: function () {
        this.update()
      },
      nodeType: function () {
        this.update()
      },
      color: function () {
        this.update()
      },
      /**
       * 网格切换
       */
      checked: function () {
        let _saveData = this.net.save();
        this.net.destroy();  //销毁画布
        this.initG6();
        this.net.read(_saveData);
        this.net.render()
      }
    }
  }
&lt;/script&gt;

&lt;style rel="stylesheet/scss" lang="scss" scoped&gt;
  #flowChart {
    border: 1px solid #ebeef5;
    position: relative;
    overflow: hidden;
  }

  .operating {
    position: absolute;
    z-index: 99;
    background-color: #ffffff;
    padding: 20px 10px;
    box-shadow: 1px 1px 4px 0 #0a0a0a2e;
  }

  .info {
    position: absolute;
    right: 0;
    z-index: 99;
    box-shadow: 1px 1px 4px 0 #0a0a0a2e;
    .title {
      height: 40px;
      padding-left: 10px;
      border-top: 1px solid #DCE3E8;
      border-bottom: 1px solid #DCE3E8;
      border-left: 1px solid #DCE3E8;
      background: rgb(235, 238, 242);
      line-height: 40px;
      span {
        font-size: 14px;
      }
    }
    .content {
      background: rgba(247, 249, 251, 0.45);
      width: 200px;
      height: 800px;
      border-left: 1px solid #E6E9ED;
      padding: 10px;
    }
  }

  .btn-group {
    border-right: 1px solid #efefef;
    display: inline-block;
    padding-left: 10px;
    padding-right: 14px;
    &amp;:last-of-type {
      border-right: 0;
    }
    .btn {
      display: inline-block;
      margin: 2px;
      width: 30px;
      height: 30px;
      line-height: 30px;
      text-align: center;
      cursor: pointer;
      border: 1px solid rgba(233, 233, 233, 0);
      i {
        font-size: 20px;
      }
      &amp;:hover {
        border: 1px solid #E9E9E9;
        color: #767A85;
        border-radius: 2px;
        background: #FAFAFE;
      }
    }
    .el-form-item {
      margin-bottom: 0 !important;
    }
  }
&lt;/style&gt;

<h3>流图属性</h3> <table> <thead><tr> <th>参数</th> <th>说明</th> <th>类型</th> <th>可选值</th> <th>默认值</th> </tr></thead> <tbody> <tr> <td>actionList</td> <td>动作数据</td> <td>Array</td> <td>——</td> <td>[]</td> </tr> <tr> <td>funcList</td> <td>功能数据</td> <td>Array</td> <td>——</td> <td>[]</td> </tr> <tr> <td>accountList</td> <td>账号数据</td> <td>Array</td> <td>——</td> <td>[]</td> </tr> <tr> <td>workflowList</td> <td>流图数据</td> <td>Array</td> <td>——</td> <td>[]</td> </tr> <tr> <td>nodeTypeList</td> <td>节点类型数据</td> <td>Array</td> <td>——</td> <td><code>[{id: 0, label: '普通节点'},{id: 1, label: '入口节点'},{id: 2, label: '出口节点'}]</code></td> </tr> </tbody> </table> <blockquote>所有属性接收的数据格式需要与<code>nodeTypeList</code>的默认值相同</blockquote> <h3>流图事件</h3> <table> <thead><tr> <th>事件名</th> <th>说明</th> <th>参数</th> </tr></thead> <tbody><tr> <td>saveData</td> <td>当用户手动点击保存触发事件</td> <td>source,type</td> </tr></tbody> </table> <blockquote>参数<code>type</code>可为空,在此项目中主要用来区分<code>新建</code>与<code>编辑</code> </blockquote> <h3>流图方法</h3> <table> <thead><tr> <th>方法名</th> <th>说明</th> <th>参数</th> </tr></thead> <tbody> <tr> <td>clearView</td> <td>清空当前视图</td> <td>——</td> </tr> <tr> <td>source</td> <td>渲染数据</td> <td>nodes, edges, name, type</td> </tr> </tbody> </table> <blockquote>参数<code>type</code>与事件中相同,参数<code>name</code>的作用是用来取流图名</blockquote> <h3>参考文档</h3> <p><a href="https://www.jianshu.com/p/e28c70a3605c" rel="nofollow noreferrer">使用 G6关系图类库 开发流程图工具</a></p> <p><a href="http://antvis.github.io/g6/api/index.html" rel="nofollow noreferrer">旧版本G6 1.x API 文档</a></p> <p><a href="https://antv.alipay.com/zh-cn/g6/1.x/api/graph.html" rel="nofollow noreferrer">新版本G6 2.x API 文档</a></p>

来源:https://segmentfault.com/a/1190000016445313

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部