vue+x6 ER 图对象模型

功能描述 x6

1、对象模型新增、编辑、删除
2、模型字段新增、编辑、删除
3、模型关系新增、编辑、删除
4、点击事件添加工具及选中样式
5、拖拽移动
6、属性的展示与隐藏
7、模型复制

创建拖拽画布
import { Addon } from '@antv/x6'
const dnd = new Addon.Dnd({
    target: this.graph
})

自定义er节点对象模型

import HeaderNode from "./components/HeaderNode.vue";
//注册节点
Graph.registerVueComponent(
  "header",
  {
    template: ``,
    components: {
      HeaderNode,
    },
  },
  true
 );

// 节点类型(attrsList:字段属性)
let limit = 10//设置字段属性个数限制(折叠与隐藏标志)
handleRegisterNode(item) {
  let nodeHeight =
    (item.height || LINE_HEIGHT) *
      (((item.attrsList.length > limit ? limit : item.attrsList.length) || 1) +
        1) +
    3;
  let node = {
    ...item,
    width: item.width || NODE_WIDTH,//节点宽度
    height: nodeHeight,//节点高度
    component: "header",//注册的vue组件
    zIndex: 0,//层级
    data: {//传值数据
      nodeData: {
        ...item,
        show: item.attrsList.length > limit ? false : true,//折叠与隐藏
        hoverId: null,
      },
      height: item.height || LINE_HEIGHT,
    },
    ports: {
      zIndex: -9,
      groups: {
        list: {
          zIndex: -9,
          markup: [
            {
              tagName: "rect",
              attrs: {
                width: NODE_WIDTH,
                height: 10,
                strokeWidth: 0,
                stroke: "transparent",
                fill: "transparent",
              },
            },
          ],
        },
      },
      items: item.portsList || [],//需要属性连线的字段属性集合
    },
  };
  return node;
},

header-node自定义页面



自定义连线

Graph.registerEdge(
  "complex-edge-label",
  {
    inherit: "edge",
    attrs: {
      line: {
        stroke: "#A2B1C3",
        strokeWidth: 2,
        targetMarker: {
          name: "classic",
          fill: "#A2B1C3", // 使用自定义填充色
        },
      },
    },
    connector: {
      name: "rounded",
      args: { radius: 10 },
    },
    labels: [
      // label1
      {
        markup: [
          {
            tagName: "circle",
            selector: "labelBody",
          },
          {
            tagName: "image",
            selector: "label",
          },
        ],
        attrs: {
          label: {
            width: 16,
            height: 16,
            x: -8,
            y: -8,
            cursor: "pointer",
          },
          labelBody: {
            ref: "label",
            r: 12,
            fill: "#fff",
            cursor: "pointer",
            stroke: "#A2B1C3",
          },
        },
        position: {
          distance: 0.2,
          args: {
            keepGradient: true,
            ensureLegibility: true,
          },
        },
      },
      // label 2
      {
        markup: [
          {
            tagName: "rect",
            selector: "labelBody",
          },
          {
            tagName: "text",
            selector: "label",
          },
        ],
        attrs: {
          label: {
            fill: "#808695",
            textAnchor: "middle",
            textVerticalAnchor: "middle",
            cursor: "pointer",
          },
          labelBody: {
            ref: "label",
            refX: -8,
            refY: -5,
            refWidth: "100%",
            refHeight: "100%",
            refWidth2: 16,
            refHeight2: 10,
            // stroke: "#ffa940",
            strokeWidth: 1,
            rx: 5,
            ry: 5,
            cursor: "pointer",
            stroke: "#A2B1C3",
          },
        },
        position: {
          distance: 0.5,
        },
      },
      // label3
      {
        markup: [
          {
            tagName: "circle",
            selector: "labelBody",
          },
          {
            tagName: "image",
            selector: "label",
          },
        ],
        attrs: {
          label: {
            width: 16,
            height: 16,
            x: -8,
            y: -8,
            cursor: "pointer",
          },
          labelBody: {
            ref: "label",
            refY: "100%",
            refY2: -0,
            r: 12,
            fill: "#fff",
            cursor: "pointer",
            stroke: "#A2B1C3",
          },
        },
        position: {
          distance: 0.8,
          args: {
            keepGradient: true,
            ensureLegibility: true,
          },
        },
      },
    ],
  },
  true
  );

数据渲染

let data = [
    //对象模型数据格式
    { 
        "shape": "vue-shape",//vue类型shape
        "width": 200,
        "position": {
            "x": 35,
            "y": 200
        },
        "bgcolor": "rgb(255,243,203)",
        "color": "rgb(253,226,130)",
        "height": 30,
        "id": "1",
        "label": "学生",
        "attrsList": [//er属性
            {
                "attrName": "attr1(属性1)",
                "attrType": "String",
                "id": "1-1",
                "type": "1"
            },
            {
                "attrName": "attr2(属性2)",
                "attrType": "String",
                "id": "1-2",
                "type": "1"
            },
            {
                "attrName": "attr3(属性3)",
                "attrType": "String",
                "id": "1-3",
                "type": "1"
            }
        ],
        //er关系的关联属性集合
        "portsList": [
            {
                "id": "1-1",
                "group": "list"
            }
        ],
    },
    //关系线数据格式
    {
        "id": "edge1",
        "shape": "complex-edge-label",
        "labels": [
            {
                "attrs": {
                    "xlink:href": "/svg/star.svg"
                }
            },
            {
                "attrs": {
                    "text": "关系表"
                }
            },
            {
                "attrs": {
                    "xlink:href": "/svg/1.svg"
                }
            }
        ],
        "source": {
            "port": "200-1",
            "cell": "200"
        },
        "target": {
            "port": "1-1",
            "cell": "1"
        },
        "zIndex": 0
    }

]
let cells = []
data.map(item=>{
    if(item.shape == 'vue-shape'){
        cells.push(this.handleRegisterNode(item))
    }else{
        cells.push(this.graph.createEdge(item))
    }
})
this.graph.resetCells(cell)

模型ER新增

//监听节点新增
this.graph.on('node:added',({node})=>{
    const {x,y} = node.position()
})

let newModel = this.graph.handleRegisterNode(data)
this.graph.addCell(newModel)

点击模型

this.graph.on('node:click',()=>{
     this.currentModel.setZIndex(9);
    this.currentModel.addTools([
      { name: "boundary" },
      {
        name: "button-remove", // 工具名称
        args: { x: 10, y: 10 }, // 工具对应的参数
      },
    ]);
})

更改模型数据

let { nodeData } = view.cell.getData();
nodeData.attrsList = []
view.cell.setData(
  { nodeData },
  {
    overwrite: true,
    silent: true,
  }
);

更改模型高度

this.currentModel.setProp(
    {
        size:{height:height},
        {
            overwrite: true,
            silent: true,
         }
    }
)

删除模型

this.graph.removeCell(this.currentModel)

清空模型选中

this.graph.cleanSelection()

设置模型选中

let newNode = this.handleRegisterNode(data)
this.graph.select(newNode)

新增关联线

//先判断模型上是否有关联属性的port节点
let {source,target} = data
//不同模型连线
if(source.cell !== target.cell){
    let sourceModel = this.graph.getCellById(source.cell)
    let targetModel = this.graph.getCellById(target.cell)
    if(!sourceModel.hasPort(source.port)){
        sourceModel.addPort({
            id:source.port,
            group:'list'
        })
    }
    if(!targetModel.hasPort(target.port)){
        targetModel.addPort({
            id:target.port,
            group:'list'
        })
    }
}else{
    //同模型连线
    let currentModel = this.graph.getCellById(source.cell)
    if(!currentModel.hasPort(source.port)){
        currentModel.addPort({
            id:source.port,
            group:'list'
        })
    }
    if(!currentModel.hasPort(target.port)){
        currentModel.addPort({
            id:target.port,
            group:'list'
        })
    }
}

let newEdge = this.graph.createEdge(data)
this.graph.addCell(newEdge)

模型移动

this.graph.on('node.moved',({view,node})=>{
    const {x,y} = node.position()
    let params = {
        id:view.cell.id,
        positionX:x,
        positionY:y
    }
})

模型复制

this.graph.bindKey('ctrl+c',()=>{
    const cells = this.graph.getSelectedCells();
    if(cells.length){
        this.graph.copy(cells)
    }
})
this.graph.bindKey('ctrl+v',()=>{
    if(!this.graph.isClipboardEmpty){
        this.graph.paste({offset:{dx:220,dy:0}})
    }
})

你可能感兴趣的:(x6)