sqlNode.js 4.91 KB
import { HtmlNode, HtmlNodeModel, h } from '@logicflow/core'

class SqlNode extends HtmlNode {
  /**
   * 1.1.7版本后支持在view中重写锚点形状。
   * 重写锚点新增
   */
  // 自定义锚点形状
  getAnchorShape(anchorData) {
    const { x, y, type } = anchorData
    // 将锚点渲染为矩形,左右锚点使用不同的样式类
    return h('rect', {
      x: x - 5,
      y: y - 5,
      width: 10,
      height: 10,
      className: `custom-anchor ${
        type === 'left' ? 'incoming-anchor' : 'outgoing-anchor'
      }`,
    })
  }

  setHtml(rootEl) { // 渲染节点的 HTML 内容
    rootEl.innerHTML = ''
    const {
      properties: { fields, tableName },
    } = this.props.model
    rootEl.setAttribute('class', 'table-container')
    const container = document.createElement('div')
    container.className = `table-node table-color-${Math.ceil(
      Math.random() * 4,
    )}`
    const tableNameElement = document.createElement('div')
    tableNameElement.innerText = tableName
    tableNameElement.className = 'table-name'
    container.appendChild(tableNameElement)
    const fragment = document.createDocumentFragment()
    for (let i = 0; i < fields.length; i++) {
      const item = fields[i]
      const itemElement = document.createElement('div')
      itemElement.className = 'table-felid'
      const itemKey = document.createElement('span')
      itemKey.innerText = item.key
      const itemType = document.createElement('span')
      itemType.innerText = item.type
      itemType.className = 'felid-type'
      itemElement.appendChild(itemKey)
      itemElement.appendChild(itemType)
      fragment.appendChild(itemElement)
    }
    container.appendChild(fragment)
    rootEl.appendChild(container)
  }
}

class SqlNodeModel extends HtmlNodeModel {
  /**
   * 给model自定义添加字段方法
   */
  addField(item) {
    this.properties.fields.unshift(item) // 在字段列表开头添加新字段
    this.setAttributes() // 更新节点尺寸
    // 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。
    this.move(0, 24 / 2) // 调整节点位置保持顶部对齐
    // 更新节点连接边的path
    this.incoming.edges.forEach((edge) => {
      // 调用自定义的更新方案
      edge.updatePathByAnchor()
    })
    this.outgoing.edges.forEach((edge) => {
      // 调用自定义的更新方案
      edge.updatePathByAnchor()
    })
  }

  getOutlineStyle() {
    const style = super.getOutlineStyle()
    style.stroke = 'none' // 移除选中外框
    style.hover.stroke = 'none' // 设置节点轮廓为透明
    return style
  }

  // 如果不用修改锚地形状,可以重写颜色相关样式
  getAnchorStyle(anchorInfo) {
    const style = super.getAnchorStyle()
    if (anchorInfo.type === 'left') { // 左侧锚点红色(输入)
      style.fill = 'red'
      style.hover.fill = 'transparent'
      style.hover.stroke = 'transparent'
      style.className = 'lf-hide-default'
    } else { // 右侧锚点绿色(输出)
      style.fill = 'green'
    }
    return style
  }

  setAttributes() { // 设置节点属性
    this.width = 200; // 设置节点宽度为 200
    const {
      properties: { fields },
    } = this
    this.height = 60 + fields.length * 24; // 根据字段数量计算高度
    // 添加连线规则:
    // 1. 只能从右侧锚点连出
    // 2. 只能连接到左侧锚点
    const circleOnlyAsTarget = {
      message: '只允许从右边的锚点连出',
      validate: (sourceNode, targetNode, sourceAnchor) => {
        return sourceAnchor.type === 'right'
      },
    }
    this.sourceRules.push(circleOnlyAsTarget)
    this.targetRules.push({
      message: '只允许连接左边的锚点',
      validate: (sourceNode, targetNode, sourceAnchor, targetAnchor) => {
        return targetAnchor.type === 'left'
      },
    })
  }

  getDefaultAnchor() { // 获取默认锚点
    const {
      id,
      x,
      y,
      width,
      height,
      isHovered,
      isSelected,
      properties: { fields, isConnection },
    } = this
    const anchors = []
    fields.forEach((felid, index) => {
      // 如果是连出,就不显示左边的锚点
      if (isConnection || !(isHovered || isSelected)) {
        anchors.push({
          x: x - width / 2 + 10,
          y: y - height / 2 + 60 + index * 24,
          id: `${id}_${felid.key}_left`,
          edgeAddable: false, // 设置左侧锚点不能作为连线起点, 自定义锚点支持设置edgeAddable属性,用于控制是否可以在此锚点手动创建连线。
          type: 'left',
        })
      }
      if (!isConnection) {
        anchors.push({
          x: x + width / 2 - 10,
          y: y - height / 2 + 60 + index * 24,
          id: `${id}_${felid.key}_right`,
          type: 'right',
        })
      }
    })
    return anchors
  }
}

export default {
  type: 'sql-node',
  model: SqlNodeModel,
  view: SqlNode,
}