antv/x6 动态添加更新连接桩(port)

@antv/x6 动态添加更新连接桩(port)

antv/x6 动态添加更新连接桩(port)_第1张图片

antv/x6 动态添加更新连接桩(port)_第2张图片
首先通过自定义html节点,生成一个可以迭代多个子节点的模块cell,然后再定义一个进线连接桩(左),定义一系列出线连接桩(erPortPosition),在对连接桩进线增删改的时候,进行条件判断。

HTML自定义节点

	  let that = this
      Shape.HTML.register({
          shape: 'condition',
          width: 120,
          height: 24,
          effect: ['data'],
          html(cell) {
              const { label, props } = cell.getData()
              const div = document.createElement('div')
              div.className = 'custom-html'
              div.style.width = 120
              const titleDiv = document.createElement('div')
              titleDiv.style.width = '120px'
              titleDiv.style.height = '24px'
              titleDiv.style.background = '#d4380d'
              titleDiv.style.color = 'white'
              titleDiv.style.fontSize = '14px'
              titleDiv.style.paddingLeft = '8px'
              titleDiv.style.lineHeight = '24px'
              titleDiv.style.boxSizing = 'border-box'
              titleDiv.style.whiteSpace = 'nowrap'
              titleDiv.style.textOverflow = 'ellipsis'
              titleDiv.style.overflow = 'hidden'
              titleDiv.style.fontSize = '14px'
              titleDiv.className = 'custom--html-title'
              titleDiv.textContent = label
              div.append(titleDiv)
              props.children.map((item, index) => {
                  const itemDiv = document.createElement('div')
                  itemDiv.className = 'custom--html-item'
                  itemDiv.style.width = '120px'
                  itemDiv.style.height = '24px'
                  itemDiv.style.background = 'rgba(212, 56, 13, 0.2)'
                  itemDiv.style.color = '#666'
                  itemDiv.style.fontSize = '14px'
                  itemDiv.style.padding = '0 4px'
                  itemDiv.style.lineHeight = '22px'
                  itemDiv.style.boxSizing = 'border-box'
                  itemDiv.style.fontSize = '12px'
                  itemDiv.style.whiteSpace = 'nowrap'
                  itemDiv.style.textOverflow = 'ellipsis'
                  itemDiv.style.overflow = 'hidden'
                  itemDiv.style.border = '1px solid rgb(212, 56, 13)'
                  itemDiv.style.borderTop = 'none'
                  if (item.key === 'qi_ta_tiao_jian') {
                    itemDiv.textContent = `${item.label}`
                  } else {
                    itemDiv.textContent = `${that.$t('tiao_jian')}_${index + 1}`
                  }
                  div.append(itemDiv)
              })
              return div
          },
      })

      this.r11 = this.graph.createNode({
          shape: 'condition',
          data: {
              props: {
                  children: [],
                  random: ''
              },
              label: this.$t('tiao_jian_pan_duan')
          },
          ports: {
              groups: {
                  right: {
                      position: 'erPortPosition',
                      attrs: {
                          circle: {
                              r: 4,
                              magnet: true,
                              stroke: '#389e0d',
                              strokeWidth: 1,
                              fill: '#fff',
                              style: {
                                  visibility: 'visible',
                              },
                          },
                      },
                  },
                  left: {
                      position: {
                          name: 'absolute',
                          args: { x: 0, y: 12 },
                      },
                      attrs: {
                          circle: {
                              r: 4,
                              magnet: true,
                              stroke: '#cf1322',
                              strokeWidth: 1,
                              fill: '#fff',
                              style: {
                                  visibility: 'visible',
                              },
                          },
                      },
                  },
              },
              items: [
                  {
                      group: 'left',
                  },
              ],
          }
      })

erPortPosition是声明的自定义连接桩布局;
group将连接桩分为左右两个类别,左侧为进线连接桩,右侧为出线的;

        const LINE_HEIGHT = 24
        const NODE_WIDTH = 120
        Graph.registerPortLayout(
          'erPortPosition',
          (portsPositionArgs) => {
            return portsPositionArgs.map((_, index) => {
              return {
                position: {
                  x: NODE_WIDTH,
                  y: (index + 1) * LINE_HEIGHT + 12,
                },
                angle: 0,
              }
            })
          },
          true,
        )

动态更新连接桩

如图,对连接桩进线编辑的时候,可能会删除或者添加,有的时候还会跳转顺序,所以单纯的addPort(一直会在末尾处添加连接桩)并不能满足此需求,解决的思路是:

  1. 对于明确删除的连接桩直接删除;removePort
  2. 对于增加的连接桩直接增加;addPort
  3. 对于更新的连接桩先删除,再增加;removePortaddPort,并且要先获取是否有连线,增加后要绘制之前存在的连线;addEdge
		// data.id是当前cell.id
		let cell = this.graph.getCellById(data.id)
		
		// form.delPortArr是明确要删除的port数组
        if (form.delPortArr.length > 0) { // delete port
          form.delPortArr.map((item) => {
            cell.removePort(item)
          })
        }

		let edges = []
        this.graph.toJSON().cells.forEach((item1) => {
          if (item1.shape === 'edge' && item1.source.cell === data.id) {
            edges.push(item1)
          }
        })
        
        // form.conditionList是当前节点包含的子节点数组
        form.conditionList.map((item) => {
          if (!item.id) { // add port
            cell.addPort({
              group: 'right'
            })
          } else { // edit port
            // delete old port and add new port , update new port by old port ID
            cell.removePort(item.id)
            cell.addPort({
              group: 'right'
            })
            let lastPortId = cell.port.ports.pop().id
            cell.setPortProp(lastPortId, 'id', item.id)
            edges.forEach((item1) => {
              if (item1.source.port === item.id) {
                this.graph.addEdge(item1)
              }
            })
          }
        })
        // 将portid赋值给children,这样html自定义生产子节点的时候,可以保持子节点id和对应的portid一致。
        let _children = form.conditionList.map((item, index) => {
          return {
            ...item,
            id: cell.port.ports[index + 1].id
          }
        })
        // 更新节点数据,以驱动html节点重新渲染
        cell.prop('data', {
          props: {
            url: form.url,
            children: _children
          },
          label: form.name
        })
        // 调整cell的尺寸
        cell.prop('size', {
          height: 24 * (form.conditionList.length + 1),
          width: 120
        })

你可能感兴趣的:(antv,前端,前端,html5,javascript)