1.參考: G6 TreeGraph樹圖默認展開幾層節點
graph.data(data) graph.render() graph.fitCenter() // 移到圖中心 setTimeout(() => { // 1 默認展開兩層節點,之后,重新渲染 G6.Util.traverseTree(data, function(item) { console.log(item) if (item.depth > 0) { //collapsed為true時默認收起 item.collapsed = true } }) graph.render() graph.fitCenter() // 移到圖中心 }, 10)
2.樹形節點增刪改,需要重新調用 graph.render()或者 graph.layout()
3.樹形圖,右鍵菜單插件
以此為例,右鍵菜單的觸發事件回調函數: handleMenuClick
const menu = new G6.Menu({ offsetX: 10, offsetY: 10, itemTypes: ['node'], getContent(e) { const {item} = e console.log(item.getModel()) let {bqglParentUuid} = item.getModel() if (bqglParentUuid == 'root') { return `` } const outDiv = document.createElement('div') outDiv.innerHTML = `<ul class="ant-cascader-menu"> <li class="add">增加節點</li> <li class="addClassification">增加分類</li> <li class="del">刪除節點</li> <li class="proview">查看節點</li> <li class="edit">編輯節點</li> </ul>` return outDiv }, handleMenuClick: (target, item) => { var nodeId = item.get('id') const newParentData = graph.findDataById(nodeId) let newchildren = newParentData.children switch (target.className) { case 'add': var childData = { id: 'child-data-' + new Date().getTime(), type: 'flow-rect', name: 'x-' } graph.addChild(childData, nodeId) graph.render() graph.fitCenter() // 移到圖中心 graph.fitView() break case 'addClassification': console.log(target.innerText) break case 'del': graph.removeChild(nodeId) graph.render() graph.fitCenter() // 移到圖中心 graph.fitView() // graph.fitView() break case 'proview': console.log(target.innerText) break case 'edit': console.log(target.innerText) break default: break } } })
4.樹形圖 矩形上線連接點的位置
//自定義節點 G6.registerNode( 'flow-rect', { getAnchorPoints() { //矩形上線連接點的位置 return [ [0.5, 0], [0.5, 1] ] } }, 'rect' ) //連接線 G6.registerEdge('line-arrow', { options: { style: { stroke: '#ccc' } }, draw: function draw(cfg, group) { const startPoint = cfg.startPoint const endPoint = cfg.endPoint const stroke = (cfg.style && cfg.style.stroke) || this.options.style.stroke const startArrow = (cfg.style && cfg.style.startArrow) || undefined const endArrow = (cfg.style && cfg.style.endArrow) || undefined //連接線路徑 const keyShape = group.addShape('path', { attrs: { path: [ ['M', startPoint.x, startPoint.y], ['L', startPoint.x, (startPoint.y + endPoint.y) / 2], ['L', endPoint.x, (startPoint.y + endPoint.y) / 2], ['L', endPoint.x, endPoint.y] ], stroke, lineWidth: 1, startArrow, endArrow }, className: 'edge-shape', name: 'edge-shape' }) return keyShape } })
5. 點擊切換選中
setState(name, value, item) {
var group = item.getContainer()
// 獲取外邊框
var nodeRect = group.find(function(e) {
return e.get('name') === 'node-rect'
})
// 獲取任務名稱
var collapseTitleText = group.find(function(e) {
return e.get('name') === 'node-name'
})
// 獲取折疊點
var collapseText = group.find(function(e) {
return e.get('name') === 'collapse-text'
})
// 設置狀態
if (name === 'selected') {
if (value) {
nodeRect.attr({
stroke: '#1258ED',
lineWidth: 2
})
collapseTitleText.attr({
fill: '#1258ED'
})
} else {
nodeRect.attr({
stroke: '#999999',
lineWidth: 1
})
collapseTitleText.attr({
fill: '#333'
})
}
}
}
//點擊節點文字 graph.on('node-name:click', e => { const {item} = e graph.setItemState(item, 'selected', !item.hasState('selected')) // 切換選中 })
6.解決自定義節點動態更新調用graph.render(),坐標問題
根據G6坐標系的 pointX/pointY 縮放平移不影響 pointX/pointY 坐標計算 ,
通過記錄最初創建時的 畫布中心point坐標,計算拖拽后和最初創建的坐標差,在每次render后進行平移
記錄縮放比例,render之后進行還原
注意:縮放比例和縮放中心的坐標,需要和拖拽后畫布中心的坐標一致,否則會有位置差
//this.initGraphCenterPoint 為創建時保存的畫布中心坐標
updateGraph() {
this.graphCenterPoint = graph.getGraphCenterPoint()
this.graphCenterZoom = graph.getZoom()
let x = this.graphCenterPoint.x - this.initGraphCenterPoint.x,
y = this.graphCenterPoint.y - this.initGraphCenterPoint.y
graph.render()
graph.fitCenter()
graph.translate(x, y)
graph.zoomTo(this.graphCenterZoom, this.graphCenterPoint)
},
7.雙擊節點編輯
//監聽雙擊點擊 graph.on('node:dblclick', e => { const nodeItem = e.item // 獲取被點擊的節點元素對象 that.editNode(e) console.log('雙擊', nodeItem._cfg) }) //雙擊編輯 editNode(evt) { let that = this const item = evt.item const model = item.get('model') const {x, y, width, height} = item.calculateBBox() const graph = evt.currentTarget const realPosition = evt.currentTarget.getClientByPoint(x, y) const el = document.createElement('div') el.style.fontSize = 16 + 'px' el.style.position = 'fixed' el.style.top = realPosition.y + 'px' el.style.left = realPosition.x + ((width - G6.Util.getTextSize(model.bqglLabel, 20)[0]) * graph.getZoom()) / 2 + 'px' el.style.transformOrigin = 'top left' el.style.transform = `scale(${evt.currentTarget.getZoom()})` const input = document.createElement('input') input.value = model.bqglLabel input.style.width = G6.Util.getTextSize(model.bqglLabel, 20)[0] + 'px' input.style.fontWeight = 'bold' input.style.height = height + 'px' input.className = 'dice-input' el.className = 'dice-input' el.appendChild(input) document.body.appendChild(el) const destroyEl = () => { document.body.removeChild(el) } const clickEvt = event => { if ( !( event.target && event.target.classList.length && event.target.className && event.target.className.includes('dice-input') ) ) { window.removeEventListener('mousedown', clickEvt) window.removeEventListener('scroll', clickEvt) graph.updateItem(item, { bqglLabel: input.value }) //更新視圖 that.updateGraph() graph.layout() graph.off('wheelZoom', clickEvt) destroyEl() } } graph.on('wheelZoom', clickEvt) window.addEventListener('mousedown', clickEvt) window.addEventListener('scroll', clickEvt) input.addEventListener('keyup', event => { if (event.key === 'Enter') { clickEvt({ target: {} }) } }) },
8.dom節點插入
SVG 與 DOM 圖形在 V3.3.x 中不支持。 僅在 Graph 的 renderer
為 'svg'
時可以使用 DOM 自定義節點。
new G6.TreeGraph({ renderer: 'svg', })
G6 的節點/邊事件不支持 DOM 類型的圖形。如果需要為 DOM 節點綁定事件,請使用原生 DOM 事件
參考文檔:使用-dom-自定義節點
rectConfig 為基礎公共變量配置對象
rectConfig: { //配置項 width: 200, height: 40, lineWidth: 1, fontSize: 16, fill: '#fff', // 填充背景 radius: 4, stroke: '#F7F7F7', opacity: 1 }
此處代碼是循環插入
cfg.list.forEach((item, i) => { let agrments = `${i},"${cfg.id}","${item.bqglLabel}"`, classList = item.selected ? `childNode selected` : `childNode` group.addShape('dom', { itemData: { bqglUuid: cfg.bqglUuid, bqglType: cfg.bqglType, bqglLabel: cfg.bqglLabel }, attrs: { x: nodeOrigin.x + 10, y: i * (rectConfig.height + 5) + nodeOrigin.y + 30, width: rectConfig.width - 20, height: rectConfig.height, html: ` <div class='${classList}' oncontextmenu='nodeChildern(event , ${agrments})' onclick='clickNodeChildern(event , ${agrments})' onmousemove='nodeChildernMοusemove(event, ${agrments})' onmouseout='nodeChildernMοuseout(event, ${agrments})' style='height:${rectConfig.height}px' > <span ondblclick='dbclickNodeChildern(event , ${agrments})' >${that.fittingString(item.bqglLabel, rectBBox.width - 10 * 2 - rectConfig.height, 16)} </span> </div>` }, name: 'node-childern-rect' }) })
原生DOM事件函數,在 mounted 中聲明 綁定在window上
//標簽右鍵觸發的事件 window.nodeChildern = (e, index, parentId) => { } //標簽點擊觸發的事件 window.clickNodeChildern = (e, index, parentId) => { } //標簽雙擊觸發的事件 window.dbclickNodeChildern = (e, index, parentId) => { } //鼠標移入 window.nodeChildernMοusemove = (e, index, parentId, bqglLabel) => { } //標簽鼠標移出 window.nodeChildernMοuseout = (e, index, parentId, bqglLabel) => { t.style.display = 'none' }
9.節點偏移量修正
寬度未自適應,造成重疊的bug
在 getHeight 中改變下高度間距,觸發了引擎 layout 重新渲染最終位置被修正
new G6.TreeGraph({ layout: { type: 'compactBox', //緊湊型樹形菜單 direction: 'TB', //垂直 dropCap: false, getHeight: nodeItem => { //添加判斷后就可以自適應了 if (nodeItem.collapsed) { return rectConfig.height + 30 } return rectConfig.height + 20 }, getWidth: () => { return rectConfig.width + 40 } }, })
。。。