Ant x6 实现左侧拖拽生成er图

778 阅读2分钟

动画.webp

<template>
  <div class="main">
    <div class="main_left">
//。。。左侧其他代码
    </div>
    <div ref="container" class="main_container" @dragover="dragoverDiv"></div>
  </div>
</template>

<script>
import {Graph, Shape} from '@antv/x6'

export default {
  name: "TabDataSource",
  data() {
    return {
      selectTypeValue: '',
      graph: null,
      cells: []
    }
  },
  mounted() {
    this.initGraph()
  },
  methods: {
    /**
     * 共四个参数,依次为:被拖拽节点对应的 Node、结束拖拽时最后进入的节点(可能为空)、被拖拽节点的放置位置(before、after、inner)、event
     * @param draggingNode
     * @param endNode
     * @param position
     * @param event
     */
    onDrapEnd(draggingNode, endNode, position, event) {
      console.log('draggingNode', draggingNode, 'endNode', endNode, 'position', position, 'event', event)
      const containerDom = this.$refs.container
      this.initNode(event.clientX - containerDom.offsetLeft, event.clientY - containerDom.offsetTop, `${draggingNode.data.code}_${(new Date()).getTime()}`, draggingNode.data)
    },
    //初始化graph
    initGraph() {

      const LINE_HEIGHT = 24
      const NODE_WIDTH = 150
      let container = this.$refs.container
//初始化graph
      const graph = new Graph({
        container: container,//画布容器
        width: container.offsetWidth,//画布宽,
        height: container.offsetHeight,//画布高
        background: false,//背景透明
        //配置连线规则
        panning: {//画布通过开启 panning 选项来支持拖拽平移。
          enabled: false
        },
        mouseWheel: {
          enabled: false
        },
        //网格
        grid: {
          type: 'mesh',
          size: 20,      // 网格大小 10px
          visible: true, // 渲染网格背景
          args: {
            color: '#eeeeee', // 网格线/点颜色
            thickness: 2,     // 网格线宽度/网格点大小
          },
        },
        //连接配置
        connecting: {
          snap: true, // 自动吸附
          allowBlank: false, // 是否允许连接到画布空白位置的点
          allowLoop: false, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点
          allowNode: false, // 是否允许边链接到节点(非节点上的链接桩)
          router: {
            name: 'er',
            args: {
              offset: 25,
              direction: 'H'
            }
          },
          //边配置
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#A2B1C3',
                  strokeWidth: 2
                }
              }
            })
          },
          //高亮
          highlighting: {
            magnetAvailable: {
              name: 'stroke',
              args: {
                padding: 4,
                attrs: {
                  strokeWidth: 4,
                  stroke: '#6a6c8a'
                }
              }
            }
          },
          validateConnection({targetMagnet}) {
            return !!targetMagnet
          },
        },
      })
      //创建链接桩的布局,这里主要是定位链接桩的位置
      Graph.registerPortLayout(
          'erPortPosition',
          (portsPositionArgs) => {
            return portsPositionArgs.map((_, index) => {
              return {
                position: {
                  x: 0,
                  y: (index + 1) * LINE_HEIGHT,
                },
                angle: 0,
              }
            })
          },
          true,
      )
//注册节点,这个节点就是动图中第一行深蓝色
      Graph.registerNode('er-rect',
          {
            inherit: 'rect',
            markup: [
              {
                tagName: 'rect',
                selector: 'body',
              },
              {
                tagName: 'text',
                selector: 'label',
              },
            ],
            //节点样式
            attrs: {
              rect: {
                strokeWidth: 1,
                stroke: '#5F95FF',
                fill: '#5F95FF',
              },
              label: {
                fontWeight: 'bold',
                fill: '#ffffff',
                fontSize: 12,
              },
            },
            //连接桩配置,动图中的2、3、4行浅蓝色部分
            ports: {
              groups: {
                list: {
                  markup: [
                    {
                      tagName: 'rect',
                      selector: 'portBody',
                    },
                    {
                      tagName: 'text',
                      selector: 'portNameLabel',
                      zIndex: 1
                    },
                    {
                      tagName: 'text',
                      selector: 'portTypeLabel',
                    },
                  ],
                  attrs: {
                    portBody: {
                      width: NODE_WIDTH,
                      height: LINE_HEIGHT,
                      strokeWidth: 1,
                      stroke: '#5F95FF',
                      fill: '#EFF4FF',
                      magnet: true,
                    },
                    portNameLabel: {
                      ref: 'portBody',
                      refX: 6,
                      refY: 6,
                      fontSize: 10,
                    },
                    portTypeLabel: {
                      ref: 'portBody',
                      refX: 95,
                      refY: 6,
                      fontSize: 10,
                    },
                  },
                  //使用定义的的定位位置
                  position: 'erPortPosition',
                },
              },
            },
          },
          true,)

      graph.on('edge:added',({ edge, index, options }) => {
        const edges  = graph.getEdges()
        edges.forEach(e =>{
          if (e.target === edge.source && e.source === edge.target){
            return
          }
        })
        console.log('添加了一个边',edge,index,options)
        console.log('获取所有便',graph.getEdges())
      })

      this.graph = graph
    },
    initNode(x, y, id, data) {
      this.cells.push(this.graph.createNode({
        id,
        "shape": "er-rect",
        "label": data.name,
        "width": 150,
        "height": 24,
        "position": {
          x,
          y
        },
        "ports": [
          {
            "id": `${id}-1`,
            "group": "list",
            "attrs": {
              "portNameLabel": {
                "text": "ID"
              },
              "portTypeLabel": {
                "text": `${data.name}-1`
              }
            }
          },
          {
            "id": `${id}-2`,
            "group": "list",
            "attrs": {
              "portNameLabel": {
                "text": "Name"
              },
              "portTypeLabel": {
                "text": `${data.name}-2`
              }
            }
          },
          {
            "id": `${id}-3`,
            "group": "list",
            "attrs": {
              "portNameLabel": {
                "text": "Class"
              },
              "portTypeLabel": {
                "text": `${data.name}-3`
              }
            }
          },
          {
            "id": `${id}-4`,
            "group": "list",
            "attrs": {
              "portNameLabel": {
                "text": "Gender"
              },
              "portTypeLabel": {
                "text": `${data.name}-4`
              }
            }
          }
        ]
      },))
      this.graph.resetCells(this.cells)
    },
    dragoverDiv(ev) {
      ev.preventDefault()
    },
    selectTypeChange(e) {
      console.log(e)
    },
    isDrapFun(e, a) {
      return e.level == 2
    },
    isDropFun() {
      return false
    },
  }
}
</script>

<style lang="scss" scoped>
.main {
  height: 100%;
  display: flex;

  .main_left {
    width: 240px;
    height: 100%;
    border-right: 1px solid #d6d6d6;

    .tree_top_line2 {
      display: flex;
      margin-bottom: 15px;
    }

    .custom_tree_node {
      .tree_node_label {
        margin-left: 5px;
      }
    }
  }

  .main_container {
    position: relative;
    flex: 1;

    .empty {
      position: absolute;
    }
  }
}


</style>