// 建立 G6 圖實例 const graph = new G6.Graph({ container: 'mountNode', // 指定圖畫布的容器 id,與第 9 行的容器對應 // 畫布寬高 width: 800, height: 500, }); // 讀取數據 graph.data(data); // 渲染圖 graph.render(); //監聽 graph.on()
Graph 對象的生命週期爲:初始化 —> 加載數據 —> 渲染 —> 更新 —> 銷燬。node
上面代碼中實例化 Graph 的部分使用了三個必要的配置項:git
container
width
、height
renderer
fitView
fitViewPadding
fitCenter
defaultNode
defaultEdge
nodeStateStyles
edgeStateStyles
layout
modes
animate
animateCfg
plugins
每一個圖元素由圖形(Shape) 組成,且都會有本身的惟一關鍵圖形(keyShape)。web
獲取實例的屬性值。算法
更新實例的單個繪圖屬性。canvas
批量更新實例繪圖屬性。api
表明元素的圖形數組
變換dom
圖的元素(Item)包含圖上的節點 Node 、邊 Edge 和 Combo 三大類。ide
style
字段對象進行配置,和元素的關鍵圖形相關,例如 fill
,stroke
。id
、type
,不能在元素狀態改變是進行改變,可經過 graph.updateItem 進行手動更新。節點svg
G6 的內置節點包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect。這些內置節點的默認樣式分別以下圖所示。
定義方式
// 1 defaultNode: { type: 'circle', // 其餘配置 } //2 graph.node((node) => { return { id: node.id, type: 'rect', style: { fill: 'blue', }, }; }); graph.data(data); graph.render(); //3 const data = { nodes: [ { id: 'node_circle', x: 100, y: 100, type: 'circle', label: 'circle', },] }
自定義
G6.registerNode( 'nodeName', { options: { style: {}, stateStyles: { hover: {}, selected: {}, }, }, /** * 繪製節點,包含文本 * @param {Object} cfg 節點的配置項 * @param {G.Group} group 圖形分組,節點中圖形對象的容器 * @return {G.Shape} 返回一個繪製的圖形做爲 keyShape,經過 node.get('keyShape') 能夠獲取。 * 關於 keyShape 可參考文檔 核心概念-節點/邊/Combo-圖形 Shape 與 keyShape */ draw(cfg, group) {}, /** * 繪製後的附加操做,默認沒有任何操做 * @param {Object} cfg 節點的配置項 * @param {G.Group} group 圖形分組,節點中圖形對象的容器 */ afterDraw(cfg, group) {}, /** * 更新節點,包含文本 * @override * @param {Object} cfg 節點的配置項 * @param {Node} node 節點 */ update(cfg, node) {}, /** * 更新節點後的操做,通常同 afterDraw 配合使用 * @override * @param {Object} cfg 節點的配置項 * @param {Node} node 節點 */ afterUpdate(cfg, node) {}, /** * 響應節點的狀態變化。 * 在須要使用動畫來響應狀態變化時須要被複寫,其餘樣式的響應參見下文說起的 [配置狀態樣式] 文檔 * @param {String} name 狀態名稱 * @param {Object} value 狀態值 * @param {Node} node 節點 */ setState(name, value, node) {}, /** * 獲取錨點(相關邊的連入點) * @param {Object} cfg 節點的配置項 * @return {Array|null} 錨點(相關邊的連入點)的數組,若是爲 null,則沒有控制點 */ getAnchorPoints(cfg) {}, }, // 繼承內置節點類型的名字,例如基類 'single-node',或 'circle', 'rect' 等 // 當不指定該參數則表明不繼承任何內置節點類型 extendedNodeName, );
鏈接方式
// 接入點 anchorPoints: [ [0, 1], [0.5, 1], ],
jsx寫法
<[group|shape] [key]="value" style={{ [key]: value }}> <[more tag] /> ... <text>value</text> </[group|shape]>
邊
定義方式: 與節點相似
箭頭:
//默認 style: { endArrow: true, startArrow: true } //內置 6種 endArrow: { // 使用內置箭頭路徑函數,參數爲箭頭的 寬度、長度、偏移量(默認爲 0,與 d 對應) path: G6.Arrow.triangle(10, 20, 25), d: 25 } // 自定義箭頭 // 只有內置箭頭和自定義箭頭能夠配置樣式 style: { endArrow: { path: 'M 0,0 L 20,10 L 20,-10 Z', d: 5, fill: '#f00', stroke: '#0f0', opacity: 0.5, lineWidth: 3, // ... }, }
自定義:同節點
combo
G6 的內置 Combo 包括 circle 和 rect 兩種類型
對於熟悉圖可視化類庫的用戶來講,節點分組是很是實用的一個功能
G6 已經存在一個節點分組 Node Group 功能,但它的機制沒法支持一些較複雜的功能,例如:帶有節點分組的圖佈局、自定義 Combo、嵌套節點分組的均勻 padding、節點與分組的邊、分組與分組的邊、空的節點分組等
{ nodes: [ { id: 'node1', comboId: 'comboA' // node1 屬於 comboA }, { id: 'node2', comboId: 'comboB' // node2 屬於 comboB }, { id: 'node3' // node3 不屬於任何 combo }, // ... ], edges: [ // ... ], combos: [ { // 定義 comboA id: 'comboA', label: 'A', parentId: 'comboC' }, { // 定義 comboB id: 'comboB', parentId: 'comboB' }, { // 定義 comboC,這是一個空的 combo id: 'comboC' }, // ... ] }
其餘內容:相似與節點
高級樣式
背景
defaultNode: { position: 'left', style: { background: { fill: '#ffffff', stroke: 'green', padding: [3, 2, 3, 2], radius: 2, lineWidth: 3, }, },
三種方式更新文本樣式
// 1. 實例化默認 defaultNode: { type: 'node', labelCfg: { style: { fill: '#fff', fontSize: 14, }, }, }, // 2.數據指定 const data = { nodes: [ { id: 'node1', label: 'node1', labelCfg: { style: { fill: '#fff', fontSize: 12, }, }, }, ], }; // 3.update/updateItem graph.updateItem(node, { // 節點的樣式 style: { stroke: 'blue', }, // 節點上文本的樣式 labelCfg: { style: { fill: '#fff', fontSize: 12, }, }, });
漸變色/紋理
操做
更新樣式
更新節點邊: 三種方式
層級
全部節點會繪製在全部邊的上層
先繪製圖形在後繪製圖形後邊
toFront()
與 toBack()
顯示/隱藏
show()/hide()
多條邊
自定義邊 edgeType
鎖定/解鎖
lock()
、unlock()
和 hasLocked()
不可拖動
不可縮放
通常佈局
樹圖
佈局切換
updateLayout(params)
:佈局方法或參數的切換;graph.updateLayout({ type: 'force', // 佈局名稱 preventOverlap: true, // 佈局參數,是否容許重疊 nodeSize: 40, // 佈局參數,節點大小,用於判斷節點是否重疊 linkDistance: 100, // 佈局參數,邊長 }); * `changeData()`:數據的切換。 graph.changeData(data2);
子圖
子圖佈局獨立與全局佈局的思路,與 graph 不掛鉤,直接使用實例化佈局方法的方式,灌入子圖數據,經過佈局將位置寫到相應數據中。這種機制還可供外部的全局佈局使用,即便不用 G6 渲染,也能夠計算節點佈局後的位置
// 實例化佈局 const subgraphLayout = new G6.Layout['force']({ center: [500, 450], }); // 初始化佈局,灌入子圖數據 subgraphLayout.init({ nodes: subGraphNodes, edges: subGraphEdges, }); // 執行佈局 subgraphLayout.execute(); // 圖實例根據數據更新節點位置 graph.positionsAnimate();
webworker
在大規模圖可視化中,佈局算法每每須要較大的計算量。
workerEnabled: true, // 開啓 Web-Worker
自定義佈局
getDefaultCfg() { return {}; }, /** * 初始化 * @param {object} data 數據 */ init(data) {}, /** * 執行佈局 */ execute() {}, /** * 根據傳入的數據進行佈局 * @param {object} data 數據 */ layout(data) {}, /** * 更新佈局配置,但不執行佈局 * @param {object} cfg 須要更新的配置項 */ updateCfg(cfg) {}, /** * 銷燬 */ destroy() {}, });
佈局預測
import { GraphLayoutPredict } from '@antv/vis-predict-engine' const { predictLayout, confidence } = await GraphLayoutPredict.predict(data); const graph = new G6.Graph({ // 省略其餘配置 layout: { type: predictLayout } })
監聽/綁定
mousedown
,mouseup
,click
,mouseenter
,mouseleave
等;node:mousedown
,edge:click
等,以 type:eventName
爲事件名稱;時機事件:
beforeadditem
,afteradditem
等;beforerefreshitem
與 afterrefreshitem
;beforelayout
與 afterlayout
。graph.on('click', (ev) => { const shape = ev.target; const item = ev.item; if (item) { const type = item.getType(); } }); graph.on('node:click', (ev) => { const shape = ev.target; const node = ev.item; });
內置 behavior
ehavior 是 G6 提供的定義圖上交互事件的機制。
G6 目前共提供瞭如下 14 個內置的 Behavior。
drag-combo
collapse-expand-combo
drag-canvas
zoom-canvas
drag-node
click-select
tooltip
edge-tooltip
activate-relations
brush-select
lasso-select
collapse-expand
create-edge
shortcuts-call
在交互行爲上, G6 主要考慮了三個場景:
在這些場景中只要用戶可能沒法一眼看清楚全部須要的信息,都須要進行交互,例如:
modes: { // 支持的 behavior default: ['drag-canvas', 'zoom-canvas'], edit: ['click-select'], },
// 解綁目前圖模式的全部事件監聽;
// 生成新的 Behavior ,進行事件初始化;
// 綁定新的行爲對應的事件監聽。
graph.setMode('edit');
graph.addBehaviors
graph.removeBehaviors
狀態State
判斷是否該使用 state 的原則很簡單,從交互和業務兩個層面來看:
知足上述條件其一,則應該使用 state。
在 G6 中,有兩種方式配置不一樣狀態的樣式:
nodeStateStyles
和 edgeStateStyles
對象定義;stateStyles
對象中定義狀態;setItemState
clearItemStates
updateItem
graph.setItemState(item, stateName, stateValue) graph.clearItemStates(item, 'selected');
// 實例化 nodeStateStyles: { }, //數據 stateStyles: { }, //updataItem stateStyles: { // 修改 hover 狀態下的樣式 hover: { opacity: 0.1, // 修改 name 爲 'node-label' 的子圖形 hover 狀態下的樣式 'node-text': { stroke: 'blue', }, }, }, //優先級 item.hasState('active');
// 實例化 Image Minimap 插件 const imageMinimap = new G6.ImageMinimap({ width: 200, graphImg: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eD7nT6tmYgAAAAAAAAAAAABkARQnAQ' }); const graph = new G6.Graph({ //... 其餘配置項 plugins: [imageMinimap], // 配置 imageMinimap 插件 });
計算nodes,edges x/y
全局
//全局 animate: true, // Boolean,切換佈局時是否使用動畫過分,默認爲 false graph.updateLayout(cfg) 佈局的變化 graph.changeData() 數據的變化
元素
//開始 shape.animate( (ratio) => { // 每一幀的操做,入參 ratio:這一幀的比例值(Number)。返回值:這一幀須要變化的參數集(Object)。 // 先變大、再變小 const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10; let radius = cfg.size; if (isNaN(radius)) radius = radius[0]; // 返回這一幀須要變化的參數集,這裏只包含了半徑 return { r: radius / 2 + diff, }; }, { // 動畫重複 repeat: true, duration: 3000, easing: 'easeCubic', }, ); // 一次動畫持續的時長爲 3000,動畫效果爲 'easeCubic' //結束 shape.stopAnimate();