基於G6和Vue的可視化圖形編輯器

先上預覽地址:http://oxoyo.co/X-Flowchart-Vue/
再上倉庫地址:https://github.com/OXOYO/X-Flowchart-Vuejavascript

初衷很簡單,開發一個基於Vue的流程編輯器。項目初期研究過jsplumb,不是很理想,後來就着手拿SVG直接堆一個出來,第一版開發完基本知足需求。
在通過了3個版本的迭代後,算是有一個比較成型的編輯器了,下面簡單介紹一下。html

V1.0

該版本使用原生SVG開發,實現了基礎的節點拖拽、連線、屬性配置、右鍵菜單、導出數據功能,基本知足項目需求。vue

V2.0

該版本原計劃是在V1.0基礎上作功能優化、功能擴展的,但開發了一段時間後以爲總體設計不夠理想就擱置了。java

V3.0

該版本是基於 antvis/G6 實現,屬於對前兩版本的重構。node

功能

目前已實現的功能以下表所示:git

功能 狀態 快捷鍵 工具欄 右鍵菜單 備註
logo Logo
undo ctrl + z 撤銷
clearLog ctrl + shift + l 清空操做日誌
redo ctrl + shift + z 重作
copy ctrl + c 複製
paste ctrl + v 粘貼
delete Delete 刪除
clear ctrl + shift + e 清空畫布
zoom 縮放
zoomIn ctrl + + 放大
zoomOut ctrl + - 縮小
fit ctrl + 0 適應屏幕
actualSize ctrl + 1 實際大小
fill 填充顏色
lineColor 線條顏色
lineWidth 線條寬度
lineStyle 線條樣式
lineType 線條類型
startArrow 起點
endArrow 終點
toFront 置於頂層
toBack 置於底層
selectAll ctrl + a 全選
marquee 框選
edit 編輯
preview 預覽
upload 上傳
download 下載
language 語言
github Github
feedback 反饋

undoclearLogredo

撤銷清空日誌重作,在 state 中存儲 log 數據,經過 mutation 來更新 log 數據。github

state
current 就是當前畫布上的數據。
list 就是操做日誌列表。json

// /src/store.js
export default new Vuex.Store({
    state: {  
      editor: {  
        ...
        // 操做日誌  
        log: {  
          current: null,  
          list: []
        }
        ...
      }
    },
    ...
    mutations: {
      ...
      'editor/log/update': (state, data) => {
        ...
      }
    }
})

更新
在須要記錄操做的地方經過 commit editor/currentItem/update 來更新 log 數據canvas

// 更新操做日誌  
_t.$store.commit('editor/log/update', {
  // 操做類型:undo、clearLog、redo
  action: ''
})

copypaste

複製粘貼,經過 clipboard 存儲複製的節點數據,經過 addItem 方法將節點粘貼到畫布上。jsp

// /src/components/Editor/Index.vue
...
// 數據定義
data () {
  return {
    ...
    clipboard: {  
      data: null,  
      // 粘貼計數器  
      count: 0  
    }
    ...
  }
}
...
handleToolTrigger (info) {
  ...
  switch (info.name) {
    ...
    case 'copy':  
      (() => {  
        // FIXME 目前只支持節點的複製,不支持邊的複製,邊只能經過拖拽生成  
        let data = _t.currentItem ? _t.currentItem.filter(item => item.type === 'node') : []  
        _t.clipboard = {
          data,
          count: 0  
        }
      })()
    break
    case 'paste':
      (() => {  
        let data = _t.clipboard.data  
        _t.clipboard.count++
        if (data.length) {  
          data.forEach((item, index) => {  
            let model = item.model  
            // 計算座標,添加必定偏移量,防止重疊  
            let x = model.x + 10 * _t.clipboard.count  
            let y = model.y + 10 * _t.clipboard.count  
            // 若是經過右鍵菜單觸發的,則獲取觸發菜單時的canvas座標  
            if (info && info.context === 'ContextMenu' && info.data) {  
              if (info.data.hasOwnProperty('canvasX')) {  
                x = model.x + info.data.canvasX - data[0].model.x  
              }  
              if (info.data.hasOwnProperty('canvasY')) {  
                y = model.y + info.data.canvasY - data[0].model.y  
              }  
            }  
            let node = {  
              ...model,  
              id: G6.Util.uniqueId(),
              groupId: '',  
              x,  
              y  
            }
            // 添加節點到畫布上
            _t.editor.addItem('node', node)  
          })
        }  
      })()
    break
    ...
  }
  ...
}

delete

刪除元素,經過 removeItem 方法刪除 nodeedge

clear

清空畫布,經過 clear 方法清空畫布。

zoomzoomInzoomOut

縮放放大縮小,經過 zoomTo 方法將畫布縮放到某個比例

fitactualSize

適應屏幕,經過 fitView 方法將畫布縮放到適應屏幕;經過。
實際大小,經過 zoomTo 方法將畫布縮放到 1 比例。

filllineColorlineWidthlineStylelineTypestartArrowendArrow

填充顏色線條顏色線條寬度線條樣式線條類型起點終點,經過 updateItem 方法更新節點、邊的屬性。

toFronttoBack

置頂,經過 toFront 方法將節點、邊置頂。
置底,經過 toBack 方法將節點、邊置底。

selectAll

全選,經過 updateItem 方法設置全部節點爲同一個 groupId,經過 setItemState 方法設置全部節點 active 狀態。

editepreview

編輯預覽,經過 setMode 方法設置畫布不一樣的模式,不一樣模式下會執行不一樣的 behavior

// /src/components/Editor/index.vue
// 生成編輯器實例  
_t.editor = new G6.Graph({
  ...
  // 模式  
modes: {  
  // 編輯模式
  edit: [
    {  
      // 自定義節點控制交互
      type: 'node-control',
      config: {...}
    }
  ],
  // 預覽模式
  preview: [ 
    'zoom-canvas',  
    'drag-canvas',  
    'preview-canvas'  
  ]
  ...
})

uploaddownload

上傳,經過 input 文本選擇窗口上傳 json 數據文件,經過 FileReader 解析數據,經過 data 設置畫布數據,經過 render 渲染畫布。
下載,經過 downloadImage 下載爲圖片,經過 save 下載爲 json 數據。

language

國際化,經過 i18n 處理多語言。


熱鍵

使用 mousetrap 處理快捷鍵綁定。

自定義節點

/src/global/g6/node/ 目錄下是自定義節點的實現,經過 G6.registerNode 方法註冊自定義節點。

自定義邊

/src/global/g6/edge/ 目錄下是自定義邊的實現,經過 G6.registerEdge 方法註冊自定義邊。

自定義交互

/src/global/g6/behavior/ 目錄下是自定義交互的實現,經過 G6.registerBehavior 方法註冊自定義交互。

自定義插件

/src/global/g6/plugins/ 目錄下是自定義插件的實現,經過繼承擴展插件,在建立實例 new G6.Graph 時使用插件。

參考

@antvis/g6

產品在開發過程當中參考瞭如下項目部分實現:
@alibaba/GGEditor
@guozhaolong/wfd
grapheditor

最後歡迎各位大佬 star、pr。

相關文章
相關標籤/搜索