圖形化引擎antv/G6--自定義節點創建緊湊樹


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
            }
          },
})    

 

 

 

 

。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM