首页 > 编程语言 >vue3 antvX6的使用源码

vue3 antvX6的使用源码

时间:2024-10-14 17:01:11浏览次数:8  
标签:const name value antvX6 cell 源码 vue3 container 节点

npm install --save @antv/x6
<template>
  <div class="dashboard-container">
    <p>选择节点</p>
    <button @click="save">保存</button>
    <div class="antvBox">
      <div class="menu-list">
        <div
          v-for="item in moduleList"
          :key="item.id"
          draggable="true"
          @dragend="handleDragEnd($event, item)"
        >
          <img :src="item.image" alt="" />
          <p>{{ item.name }}</p>
        </div>
      </div>
      <div class="canvas-card">
        <div id="container" />
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { Graph } from '@antv/x6'

import t1 from '../../assets/images/1.png'
import t2 from '../../assets/images/2.png'
import t3 from '../../assets/images/3.png'
import t4 from '../../assets/images/4.png'
import t5 from '../../assets/images/5.png'

const moduleList = ref([
  {
    id: 1,
    name: '节点1',
    image: t1
  },
  {
    id: 8,
    name: '节点2',
    image: t2
  },
  {
    id: 2,
    name: '节点3',
    image: t3
  },
  {
    id: 3,
    name: '节点4',
    image: t4
  },
  {
    id: 4,
    name: '节点5',
    image: t5
  }
])

const curSelectNode = ref(null)

/**
 * 拖拽左侧
 * @param e
 * @param item
 */
const handleDragEnd = (e, item) => {
  addHandleNode(e.pageX - 300, e.pageY - 200, new Date().getTime(), item.image, item.name)
}

const graph = ref<Graph | null>(null)

const initGraph = () => {
  const container = document.getElementById('container')
  if (container === null) {
    throw new Error('Container element not found')
  }
  graph.value = new Graph({
    container: container, // 画布容器
    width: container.offsetWidth, // 画布宽
    height: container.offsetHeight, // 画布高
    background: false, // 背景(透明)
    snapline: true, // 对齐线
    // 配置连线规则
    connecting: {
      snap: true, // 自动吸附
      allowBlank: false, // 是否允许连接到画布空白位置的点
      allowMulti: true, // 是否允许在相同的起始节点和终止之间创建多条边
      allowLoop: true, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点
      highlight: true, // 拖动边时,是否高亮显示所有可用的节点
      highlighting: {
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#5F95FF',
              stroke: '#5F95FF'
            }
          }
        }
      },
      router: {
        // 对路径添加额外的点
        name: 'orth'
      },
      connector: {
        // 边渲染到画布后的样式
        name: 'rounded',
        args: {
          radius: 8
        }
      }
    },
    panning: {
      enabled: false
    },
    mousewheel: {
      enabled: true, // 支持滚动放大缩小
      zoomAtMousePosition: true,
      modifiers: 'ctrl',
      minScale: 0.5,
      maxScale: 3
    },
    grid: {
      type: 'dot',
      size: 20, // 网格大小 10px
      visible: true, // 渲染网格背景
      args: {
        color: '#a0a0a0', // 网格线/点颜色
        thickness: 2 // 网格线宽度/网格点大小
      }
    }
  })
  nodeAddEvent()
}
/**
 * 添加画布到节点
 * x坐标、y坐标、id节点唯一标识、image图片、name节点名称
 */
//添加节点到画布
const addHandleNode = (x, y, id, image, name) => {
  graph.value.addNode({
    id: id,
    shape: 'image', // 指定使用何种图形,默认值为 'rect'
    x: x,
    y: y,
    width: 60,
    height: 60,
    imageUrl: image,
    attrs: {
      body: {
        stroke: '#ffa940',
        fill: '#ffd591'
      },
      label: {
        textWrap: {
          width: 90,
          text: name
        },
        fill: 'black',
        fontSize: 12,
        refX: 0.5,
        refY: '100%',
        refY2: 4,
        textAnchor: 'middle',
        textVerticalAnchor: 'top'
      }
    },
    ports: {
      groups: {
        group1: {
          position: [30, 30]
        }
      },
      items: [
        {
          group: 'group1',
          id: 'port1',
          attrs: {
            circle: {
              r: 6,
              magnet: true,
              stroke: '#ffffff',
              strokeWidth: 2,
              fill: '#5F95FF'
            }
          }
        }
      ]
    },
    zIndex: 10
  })
}
/**
 * 鼠标移入节点再显示链接桩
 */
const nodeAddEvent = () => {
  const container = document.getElementById('container')
  if (container === null) {
    throw new Error('Container element not found')
  }
  const changePortsVisible = visible => {
    const ports = container.querySelectorAll('.x6-port-body')
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
      ports[i].style.visibility = visible ? 'visible' : 'hidden'
    }
  }
  graph.value.on('node:mouseenter', () => {
    changePortsVisible(true)
  })
  graph.value.on('node:mouseleave', () => {
    changePortsVisible(false)
  })

  // 节点绑定点击事件 删除节点
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  graph.value.on('node:click', ({ e, x, y, node, view }) => {
    console.log('点击!!!', node)
    // 判断是否有选中过节点
    if (curSelectNode.value) {
      // 移除选中状态
      curSelectNode.value.removeTools()
      // 判断两次选中节点是否相同
      if (curSelectNode.value !== node) {
        node.addTools([
          {
            name: 'boundary',
            args: {
              attrs: {
                fill: '#16B8AA',
                stroke: '#2F80EB',
                strokeWidth: 1,
                fillOpacity: 0.1
              }
            }
          },
          {
            name: 'button-remove',
            args: {
              x: '100%',
              y: 0,
              offset: {
                x: 0,
                y: 0
              }
            }
          }
        ])
        curSelectNode.value = node
      } else {
        curSelectNode.value = null
      }
    } else {
      curSelectNode.value = node
      node.addTools([
        {
          name: 'boundary',
          args: {
            attrs: {
              fill: '#16B8AA',
              stroke: '#2F80EB',
              strokeWidth: 1,
              fillOpacity: 0.1
            }
          }
        },
        {
          name: 'button-remove',
          args: {
            x: '100%',
            y: 0,
            offset: {
              x: 0,
              y: 0
            }
          }
        }
      ])
    }
  })

  // 删除链接节点的线
  // 连线绑定悬浮事件
  graph.value.on('cell:mouseenter', ({ cell }) => {
    if (cell.shape == 'edge') {
      cell.addTools([
        {
          name: 'button-remove',
          args: {
            x: '100%',
            y: 0,
            offset: {
              x: 0,
              y: 0
            }
          }
        }
      ])
      cell.setAttrs({
        line: {
          stroke: '#409EFF'
        }
      })
      cell.zIndex = 99 // 保证当前悬停的线在最上层,不会被遮挡
    }
  })
  graph.value.on('cell:mouseleave', ({ cell }) => {
    if (cell.shape === 'edge') {
      cell.removeTools()
      cell.setAttrs({
        line: {
          stroke: 'black'
        }
      })
      cell.zIndex = 1 // 保证未悬停的线在下层,不会遮挡悬停的线
    }
  })
}

//保存画布,并提交
const save = () => {
  console.log(graph.value.toJSON(), 'graph')
  console.log(graph.value.getNodes(), 'node')
}
onMounted(() => {
  initGraph()
})
</script>
<style lang="scss" scoped>
/* @use ''; 引入css类 */
.dashboard-container {
  .antvBox {
    display: flex;
    width: 100%;
    height: 100%;
    color: black;
    padding-top: 20px;
    .menu-list {
      height: 100%;
      width: 300px;
      padding: 0 10px;
      box-sizing: border-box;
      display: flex;
      justify-content: space-between;
      align-content: flex-start;
      flex-wrap: wrap;
      > div {
        margin-bottom: 10px;
        border-radius: 5px;
        padding: 0 10px;
        box-sizing: border-box;
        cursor: pointer;
        color: black;
        width: 105px;
        display: flex;
        flex-wrap: wrap;

        justify-content: center;
        img {
          height: 50px;
          width: 50px;
        }
        P {
          width: 90px;
          text-align: center;
        }
      }
    }
    .canvas-card {
      width: 1700px;
      height: 750px;
      box-sizing: border-box;
      > div {
        width: 1400px;
        height: 750px;
        border: 2px dashed #2149ce;
      }
    }
  }
}
</style>

借鉴https://blog.csdn.net/wzy_PROTEIN/article/details/136305034

标签:const,name,value,antvX6,cell,源码,vue3,container,节点
From: https://www.cnblogs.com/mengqc1995/p/18464558

相关文章