antV G6流程圖在Vue中的使用


最近我司項目中需要加入流程圖制作功能,於是乎百度各種找可視化繪制拓撲圖的輪子,大部分都是國外的,看文檔太吃力,不過好在最終讓我發現了AntV G6流程圖圖表庫,最新版為2.0,不過編輯器在2.0版本還沒有進行開源,所以只能退而求其次,使用了1.2.8版本。希望2.0版本的編輯器盡早開源,在交互方面1.2.8版本還是差了一些。

該組件並非開箱即食,需要根據自己的業務進行修改,右側屬性表單部分如果有時間考慮改為插槽形式,方便以后復用~

如何將數據進行數據可視化展現?

技術棧

效果圖

在這里插入圖片描述

引入

index.html中進行了全局引用



<script src="./static/plugin/g6.min.js"></script>

實例代碼

仿照2.0版本的編輯器將G6作為了一個組件使用,代碼:


<template>
  <div id="flowChart">
    <div class="operating">
      <div class="btn-group">
        <div class="btn" @click="addCircle" title="起始節點">
          <i class="iconfont icon-circle-oeps"></i>
        </div>
        <div class="btn" @click="addRect" title="常規節點">
          <i class="iconfont icon-square-oeps"></i>
        </div>
        <div class="btn" @click="addRhombus" title="條件節點">
          <i class="iconfont icon-square-ling"></i>
        </div>
      </div>
      <div class="btn-group">
        <div class="btn" @click="addLine" title="直線">
          <i class="iconfont icon-zhixian"></i>
        </div>
        <div class="btn" @click="addSmooth" title="曲線">
          <i class="iconfont icon-quxian"></i>
        </div>
        <div class="btn" @click="addArrowLine" title="箭頭直線">
          <i class="iconfont icon-jiantouzhixian"></i>
        </div>
        <div class="btn" @click="addArrowSmooth" title="箭頭曲線">
          <i class="iconfont icon-jiantouquxian"></i>
        </div>
      </div>
      <div class="btn-group">
        <div class="btn" @click="changeMode('edit')" title="選擇模式">
          <i class="iconfont icon-chose"></i>
        </div>
        <div class="btn" @click="changeMode('drag')" title="拖拽模式">
          <i class="iconfont icon-move"></i>
        </div>
      </div>
      <div class="btn-group">
        <div class="btn" @click="del" style="margin-top: 5px;" title="刪除">
          <i class="el-icon-delete"></i>
        </div>
        <div class="btn" @click="save" title="保存">
          <i class="iconfont icon-baocun"></i>
        </div>
      </div>
      <div class="btn-group">
        <el-input size="mini" v-model="workflowName" placeholder="請輸入流圖名稱..."></el-input>
      </div>
    </div>
    <div class="info">
      <div class="title">
        <span>{{infoTitle}}屬性</span>
      </div>
      <div class="content">
        <el-checkbox v-if="isBlank === true" v-model="checked">網格對齊</el-checkbox>
        <el-form v-else label-position="left" label-width="60px">
          <el-form-item v-if="isNode !== true" label="動作">
            <el-select v-model="action" size="mini" filterable placeholder="綁定動作" value="">
              <el-option
                v-for="item in actionList"
                :key="item.id"
                :label="item.label"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>   <!-- 線-->
          <el-form-item v-if="isNode === true" label="名稱">
            <el-input size="mini" v-model="name"></el-input>
          </el-form-item>
          <el-form-item v-if="isNode === true" label="功能">
            <el-select v-model="func" size="mini" filterable placeholder="綁定功能" value="">
              <el-option
                v-for="item in funcList"
                :key="item.id"
                :label="item.label"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item v-if="isNode === true" label="賬號">
            <el-select v-model="account" size="mini" filterable multiple
                       collapse-tags placeholder="綁定賬號" value="">
              <el-option
                v-for="item in accountList"
                :key="item.id"
                :label="item.label"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item v-if="isNode === true" label="流圖">
            <el-select v-model="workflow" size="mini" filterable clearable placeholder="綁定流圖" value="">
              <el-option
                v-for="item in workflowList"
                :key="item.id"
                :label="item.label"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item v-if="isNode === true" label="類型">
            <el-select v-model="nodeType" size="mini" filterable placeholder="請選擇類型" value="">
              <el-option
                v-for="item in nodeTypeList"
                :key="item.id"
                :label="item.label"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="顏色">
            <el-color-picker v-model="color"></el-color-picker>
          </el-form-item>
        </el-form>
      </div>
    </div>
  </div>
</template>

<script>

  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: () => {
          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) => {
          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(()=>{
              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 => {
          const item = ev.item;
          self.oldColor = item.get('model').color;     //獲取節點顏色
          self.net.update(item, {
            color: '#108EE9',
          });
          self.net.refresh();
        });
        self.net.on('itemmouseleave', ev => {
          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 => {
            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()
      }
    }
  }
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
  #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;
    &: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;
      }
      &:hover {
        border: 1px solid #E9E9E9;
        color: #767A85;
        border-radius: 2px;
        background: #FAFAFE;
      }
    }
    .el-form-item {
      margin-bottom: 0 !important;
    }
  }
</style>

流圖屬性

參數 說明 類型 可選值 默認值
actionList 動作數據 Array —— []
funcList 功能數據 Array —— []
accountList 賬號數據 Array —— []
workflowList 流圖數據 Array —— []
nodeTypeList 節點類型數據 Array —— [{id: 0, label: '普通節點'},{id: 1, label: '入口節點'},{id: 2, label: '出口節點'}]
所有屬性接收的數據格式需要與 nodeTypeList的默認值相同

流圖事件

事件名 說明 參數
saveData 當用戶手動點擊保存觸發事件 source,type
參數 type可為空,在此項目中主要用來區分 新建編輯

流圖方法

方法名 說明 參數
clearView 清空當前視圖 ——
source 渲染數據 nodes, edges, name, type
參數 type與事件中相同,參數 name的作用是用來取流圖名

參考文檔

使用 G6關系圖類庫 開發流程圖工具

舊版本G6 1.x API 文檔

新版本G6 2.x API 文檔

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM