一、前言
G6-Editor 是 AntV 官方提供的、專注於圖視覺化編輯器的類庫,也是市面上完成度較高的圖視覺化編輯器。然而令人詬病的是其文件對新手極度不友好,我一度懷疑此文件只有他們自己開發人員才能看得懂,回首學習的過程裡如同是漆黑中前行,苦不堪言。為了讓後來者不重蹈覆轍,我願化為螢火用微弱的光點指引前行的道路。
目標
1、元件使用
2、自定義節點
3、資料關聯
4、自定義命令
開發環境
這裡使用的框架是Vue,UI使用Element-ui,以及主角G6-Editor,建議clone文章最下面的github專案結合閱讀。
二、進入實戰
Editor 是整個編輯器的主控類,其主要職責是將編輯器的各個元件協同起來。
用法:
import G6Editor from '@antv/g6-editor'
const editor = new G6Editor()
// 元素皮膚欄 Itempannel
const itempannel = new G6Editor.Itempannel({
container: 'itempannel',
})
// 工具欄 Toolbar
const toolbar = new G6Editor. Toolbar({
container: 'toolbar',
})
// 詳細皮膚 Detailpannel
const detailpannel = new G6Editor.Detailpannel ({
container: 'detailpannel'
})
// 縮圖 Minimap
const minimap = new G6Editor.Minimap({
container: 'minimap',
height: 226,
width: 226
})
// 元件掛載到Editor
editor.add(page)
editor.add(itempannel)
editor.add(toolbar)
editor.add(detailpannel)
editor.add(minimap)
複製程式碼
Tips:先例項化元件,然後再掛載到Editor
△ 以上。
Toolbar 工具欄類,負責工具欄按鈕的命令繫結、可用禁用狀態控制。
G6-Editor內建了多種命令,亦可以自定義命令。
用法:
<!-- Toolbar -->
<div id="toolbar" class="toolbar">
<i data-command="delete" class="command el-icon el-icon-delete" title="刪除"></i>
<i data-command="zoomIn" class="command el-icon el-icon-zoom-in" title="放大"></i>
<i data-command="save" class="command el-icon el-icon-upload" title="儲存"></i>
</div>
複製程式碼
// Command
const Command = G6Editor.Command
// 自定義Save命令
Command.registerCommand('save', {
// 命令是否進入佇列,預設是 true
queue: false,
// 命令是否可用
enable(eidtor) {
return true
},
// 正向命令
execute(eidtor) {
// 獲取當前page
const page = this.editor.getCurrentPage()
const data = page.save()
console.log(data)
},
// 快捷鍵:Ctrl+shirt+s
shortcutCodes : [['ctrlKey', 'shiftKey', 's']]
})
複製程式碼
Tips:工具欄的控制元件標籤必須要有 data-command="delete"
和 class="command"
否則無效。其中delete
為內建或自定義命令名稱。
△ 以上。
Itempannel 元素皮膚欄,負責處理元素新增的通訊。用法:
<!-- 元素皮膚欄 -->
<div id="itempannel" class="ph left">
<div class="getItem" data-type="node" data-shape="flow-rect" data-size="120*48" data-label="常規節點" data-color="#1890FF">
<img draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/wHcJakkCXDrUUlNkNzSy.svg" alt="" srcset="">
</div>
<div class="getItem" data-type="node" data-shape="flow-circle" data-size="72*72" data-label="起止節點" data-color="#FA8C16">
<img draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/ZnPxbVjKYADMYxkTQXRi.svg" alt="" srcset="">
</div>
<div class="getItem" data-type="node" data-shape="flow-rhombus" data-size="80*72" data-label="分叉節點" data-color="#13C2C2">
<img draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/SnWIktArriZRWdGCnGfK.svg" alt="" srcset="">
</div>
<div class="getItem" data-type="node" data-shape="flow-capsule" data-size="80*48" data-label="模型節點" data-color="#722ED1">
<img draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/rQMUhHHSqwYsPwjXxcfP.svg" alt="" srcset="">
</div>
<!-- 注意!我跟別人不一樣,我是自定義的節點 -->
<div class="getItem" data-type="node" data-shape="customNode" data-size="80*48" data-label="我是自定義的" data-color="#722ED1">
<img draggable="false" src="https://user-gold-cdn.xitu.io/2019/3/15/169809645b016da6?w=114&h=128&f=png&s=1893" alt="" srcset="">
</div>
</div>
複製程式碼
自定義節點
// 注意!這裡不能使用new G6Editor.Flow()的形式,是無效的。
// 應使用 const Flow = G6Editor.Flow
const Flow = G6Editor.Flow
Flow.registerNode('customNode', {
draw(item){
const group = item.getGraphicGroup()
const model = item.getModel()
group.addShape('text', {
attrs: {
x: 0,
y: 0,
fill: '#333',
text: model.label
}
})
group.addShape('text', {
attrs: {
x: 0,
y: 0,
fill: '#333',
text: ' ('+model.x+', '+model.y+') \n 原點是組的圖座標',
textBaseline: 'top'
}
})
return group.addShape('rect', {
attrs: {
x: 0,
y: 0,
width: 100,
height: 100,
stroke: 'red'
}
})
}
})
複製程式碼
含class="getItem"
的元素會被當做節點,可以往編輯器拖動。
data-*
所有 * 都會被設定進新增圖項的資料模型。
data-type
元素型別
data-shape
元素圖形
data-size
元素大小
data-label
元素標籤
data-color
元素顏色
draggable
禁止、啟動拖拽預設行為
△ 以上。
Detailpannel 屬性欄類,負責屬性欄顯示隱藏的控制。通俗點說,就是不同的操作可以顯示不同的皮膚。用法:
<!-- 詳細皮膚 -->
<div id="detailpannel" class="detailpannel">
<div data-status="node-selected" class="panel" id="node_detailpanel">
<div class="panel-title">屬性詳情</div>
<div class="block-container">
<el-input v-model="nodeLabel" size="mini" @change="changeNodeLabel" placeholder="請輸入內容"></el-input>
</div>
</div>
</div>
複製程式碼
data-status
標識不同頁面狀態下,各個右鍵選單容器的顯示隱藏。
<div data-status="node-selected">節點屬性欄</div>
<div data-status="edge-selected">邊屬性欄</div>
<div data-status="group-selected">群組屬性欄</div>
<div data-status="canvas-selected">畫布屬性欄</div>
<div data-status="multi-selected">多選時屬性欄</div>
複製程式碼
△ 以上。
Minimap 縮圖類,負責繪製縮圖及雙圖聯動。 <!-- 縮圖 -->
<div class="minimap">
<div class="panel-title">縮圖</div>
<div id="minimap"></div>
</div>
複製程式碼
這個倒沒什麼好說的,可以參考官方的文件和例項。
△ 以上。
高能預警! 最後一個也是最重要的一個!資料關聯!!!不和業務資料關聯的一切都是耍流氓。
還記得Detailpannel
屬性欄類嗎? 裡面有一個輸入框,事件繫結了changeNodeLabel
,用來修改節點的label
屬性。
// methods
changeNodeLabel(value) {
const editor = this.editor
// 執行命令
editor.executeCommand(() => {
const page = editor.getCurrentPage()
const selectedItems = page.getSelected()
selectedItems.forEach(item => {
// 更新屬性
page.update(item.id, {
label: value
})
})
})
}
複製程式碼
另外選擇節點,也需要將label
的值設定到輸入框裡。
// 獲取當前page
const currentPage = editor.getCurrentPage()
// 監聽選擇變化
currentPage.on('afteritemselected', ev => {
// 選擇物件為Node節點
if (ev.item.isNode) {
// 獲取屬性
const nm = ev.item.getModel()
_this.nodeLabel = nm.label
}
// 選擇物件為Edge節點
if (ev.item.isEdge) {
// 獲取屬性
const nm = ev.item.getModel()
_this.nodeLabel = nm.label
}
})
複製程式碼
△ 以上。
後話
由於程式碼段都是比較零散,最好結合下面提供在github上的專案食用,如果文章對你有幫助,請隨手一個贊或者收藏。另外文章寫得倉促有很多不足的地方,希望大家輕拍,哈哈哈~
github倉庫 :github.com/leeggco/g6-…
這篇文章只提供了基礎的知識,後續的進階還是需要結合G6、G6-editor的文件。
那麼!到這裡本篇教程就結束了,大家辛苦了。