先上預覽地址:http://oxoyo.co/X-Flowchart-Vue/
再上倉庫地址:https://github.com/OXOYO/X-Flowchart-Vuejavascript
初衷很簡單,開發一個基於Vue的流程編輯器。項目初期研究過jsplumb,不是很理想,後來就着手拿SVG直接堆一個出來,第一版開發完基本知足需求。
在通過了3個版本的迭代後,算是有一個比較成型的編輯器了,下面簡單介紹一下。html
該版本使用原生SVG開發,實現了基礎的節點拖拽、連線、屬性配置、右鍵菜單、導出數據功能,基本知足項目需求。vue
該版本原計劃是在V1.0基礎上作功能優化、功能擴展的,但開發了一段時間後以爲總體設計不夠理想就擱置了。java
該版本是基於 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 | ✔ | ✔ | ✔ | 反饋 |
撤銷、清空日誌、重作,在 state
中存儲 log
數據,經過 mutation
來更新 log
數據。github
statecurrent
就是當前畫布上的數據。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: '' })
複製、粘貼,經過 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 ... } ... }
刪除元素,經過 removeItem
方法刪除 node
、edge
。
清空畫布,經過 clear
方法清空畫布。
縮放、放大、縮小,經過 zoomTo
方法將畫布縮放到某個比例
適應屏幕,經過 fitView
方法將畫布縮放到適應屏幕;經過。
實際大小,經過 zoomTo
方法將畫布縮放到 1
比例。
填充顏色、線條顏色、線條寬度、線條樣式、線條類型、起點、終點,經過 updateItem
方法更新節點、邊的屬性。
置頂,經過 toFront
方法將節點、邊置頂。
置底,經過 toBack
方法將節點、邊置底。
全選,經過 updateItem
方法設置全部節點爲同一個 groupId
,經過 setItemState
方法設置全部節點 active
狀態。
編輯、預覽,經過 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' ] ... })
上傳,經過 input
文本選擇窗口上傳 json
數據文件,經過 FileReader
解析數據,經過 data
設置畫布數據,經過 render
渲染畫布。
下載,經過 downloadImage
下載爲圖片,經過 save
下載爲 json
數據。
國際化,經過 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
時使用插件。
產品在開發過程當中參考瞭如下項目部分實現:
@alibaba/GGEditor
@guozhaolong/wfd
grapheditor
最後歡迎各位大佬 star、pr。