创建可交互的图表:AntV X6实现预留空白位置、拖拽吸附与信息修改弹框

这篇具有很好参考价值的文章主要介绍了创建可交互的图表:AntV X6实现预留空白位置、拖拽吸附与信息修改弹框。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用AntV X6

首先用AntV X6官网的一句简介了解一下什么是X6
X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和开箱即用的内置扩展,方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。

知道了X6是什么,那么我们就要开始使用了

首先得确定框架,其次就要安装X6
由于项目是vue2的,所以选择的框架为vue2,当然自己也在vue3中写了一版,如有需要vue3的请私信

1.首先在项目中新建一个xxx.vue

<template>
<div class="container1" style="width=100%; height=100%">
 <div id="container"></div>
</div>
<div v-for="(item, index) in draList" :key="index" class="btn" @mousedown="startDrag(item, $event)">
 <div class="box">{{ item }}</div>
</div>
</template>

2.js部分为

前提安装 npm install @antv/x6 @antv/x6-plugin-snapline @antv/x6-plugin-keyboard

<script>
import { Graph, Shape } from "@antv/x6";
import { Snapline } from "@antv/x6-plugin-snapline";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { startDragToGraph } from "../../utils/drags";
Graph.registerNode(
  "lane",
  {
    inherit: "rect",
    markup: [
      {
        tagName: "rect",
        selector: "body",
      },
      {
        tagName: "rect",
        selector: "name-rect",
      },
      {
        tagName: "text",
        selector: "name-text",
      },
    ],
    attrs: {
      body: {
        fill: "#F8F8F8",
        stroke: "#f8f8f8",
        strokeWidth: 0.5,
      },
      "name-rect": {
        width: 100,
        height: 30,
        fill: "#f8f8f8",
        stroke: "#f8f8f8",
        strokeWidth: 0.5,
        // x: -1,
      },
      "name-text": {
        ref: "name-rect",
        refY: 30,
        refX: 85,
        textAnchor: "middle",
        // fontWeight: "bold",
        fill: "#000",
        fontSize: 17,
      },
    },
  },
  true
);
Graph.registerNode(
  "lane-rect",
  {
    inherit: "rect",
    width: 100,
    height: 60,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: "#5F95FF",
        fill: "#EFF4FF",
      },
      text: {
        fontSize: 12,
        fill: "#262626",
      },
    },
  },
  true
);
Graph.registerNode(
  "lane-polygon",
  {
    inherit: "polygon",
    width: 80,
    height: 80,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: "#5F95FF",
        fill: "#EFF4FF",
        refPoints: "0,10 10,0 20,10 10,20",
      },
      text: {
        fontSize: 12,
        fill: "#262626",
      },
    },
  },
  true
);
Graph.registerEdge(
  "lane-edge",
  {
    inherit: "edge",
    attrs: {
      line: {
        stroke: "#A2B1C3",
        strokeWidth: 2,
      },
    },
    label: {
      attrs: {
        label: {
          fill: "#A2B1C3",
          fontSize: 12,
        },
      },
    },
  },
  true
);

export default {
data() {
    return {
      delCell: {},
      json: "",
      graph: {},
      celll: "",
      draList: ["xxxx艺", "xxxx运"],
      ruleForm: { name: "", count: "" },
      dataPlacer: [
        {
          id: "1",
          shape: "lane",
          width: 170,
          height: 680,
          pointerEvents: "none",
          position: {
            x: 15,
            y: 0,
          },
          label: "主线程",
        },
        {
          id: "2",
          shape: "lane",
          width: 170,
          height: 680,
          position: {
            x: 230,
            y: 0,
          },
          data: {
            disableMove: false,
          },
          label: "并行路线",
        },
        {
          id: "3",
          shape: "lane",
          width: 170,
          height: 680,
          position: {
            x: 450,
            y: 0,
          },
          data: {
            disableMove: false,
          },
          label: "并行路线",
        },
        {
          id: "4",
          shape: "lane",
          width: 170,
          height: 680,
          position: {
            x: 670,
            y: 0,
          },
          data: {
            disableMove: false,
          },
          label: "并行路线",
        },
        {
          id: "4.5",
          shape: "lane",
          width: 170,
          height: 680,
          position: {
            x: 890,
            y: 0,
          },
          data: {
            disableMove: false,
          },
          label: "并行路线",
        },
        // 开始预留空位
        {
          id: "5",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 30,
            y: 90,
          },
          data: {
            disableMove: false,
          },
          label: "起点",
          fontSize: 20,
          attrs: {
            magnet: false,
            body: {
              stroke: "#d9d9d9",
              magnet: false,
              nodeMovable: false,
              strokeDasharray: "5,5",
            },
          },
          parent: "1",
        },
        {
          id: "6",
          shape: "rect",
          width: 140,
          height: 42,

          position: {
            x: 30,
            y: 190,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "1",
        },
        {
          id: "7",
          shape: "rect",
          width: 140,
          height: 42,

          position: {
            x: 30,
            y: 290,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "1",
        },
        {
          id: "8",
          shape: "rect",
          width: 140,
          height: 42,

          position: {
            x: 30,
            y: 390,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "1",
        },
        // 预留结束
        // 第二列预留
        {
          id: "10",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 245,
            y: 90,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "2",
        },
        {
          id: "11",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 245,
            y: 190,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "2",
        },
        {
          id: "12",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 245,
            y: 290,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "2",
        },
        {
          id: "13",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 245,
            y: 390,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "2",
        },
        // 第二列预留结束

        // 第三列预留开始
        {
          id: "15",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 465,
            y: 90,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "3",
        },
        {
          id: "16",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 465,
            y: 190,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "3",
        },
        {
          id: "17",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 465,
            y: 290,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "3",
        },
        {
          id: "18",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 465,
            y: 390,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "3",
        },
        // 点三列预留结束

        // 第四列预留开始
        {
          id: "20",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 685,
            y: 90,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "4",
        },
        {
          id: "21",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 685,
            y: 190,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "4",
        },
        {
          id: "22",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 685,
            y: 290,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "4",
        },
        {
          id: "23",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 685,
            y: 390,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "4",
        },
        // 第四列预留结束

        // 第五列预留开始
        {
          id: "25",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 905,
            y: 90,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "5",
        },
        {
          id: "26",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 905,
            y: 190,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "5",
        },
        {
          id: "27",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 905,
            y: 290,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "5",
        },
        {
          id: "28",
          shape: "rect",
          width: 140,
          height: 42,
          position: {
            x: 905,
            y: 390,
          },
          data: {
            disableMove: false,
          },
          label: "空位",
          attrs: {
            body: {
              stroke: "#d9d9d9",
              strokeDasharray: "5,5",
            },
          },
          parent: "5",
        },
      ],
    };
  },
	 methods: {
		init() {
      let container = document.getElementById("container");
      this.graph = new Graph({
        container: container,
        autoResize: true,
        width: 900,
        height: 480,
        translating: {
          useLocalCoordinates: true,
          restrict(cellView) {
            //#region 
            let cell = cellView ? cellView.cell : false;
            if (!cell) return false;
            let yuliu = cell.label
              ? cell.label.includes("点") || cell.label.includes("空")
              : false;
            if (yuliu) {
              return false;
            }
            let temp = cell.label ? cell.label.includes("线") : false;
            if (temp) {
              return false;
            }
           //#endregion
            if (!cellView || !cellView.model) {
              return;
            }
            if (cellView.model.isLink()) {
              // 连线不受限制
              return undefined;
            }
            return cellView.model.getBBox();
          },
        },
        connecting: {
          router: "manhattan",
          connector: {
            name: "normal",
            args: {
              radius: 8,
            },
          },
          anchor: "center",
          connectionPoint: "anchor",
          allowBlank: false,
          snap: {
            radius: 20,
          },
          createEdge() {
            return new Shape.Edge({
              connector: "normal",
              attrs: {
                line: {
                  stroke: "#2d8cf0",
                  strokeWidth: 1,
                  targetMarker: {
                    name: "classic",
                    size: 8,
                  },
                },
              },
              router: {
                name: "orth",
              },
              // zIndex: 0,
            });
          },
          validateConnection({
            sourceView,
            targetView,
            sourceMagnet,
            targetMagnet,
          }) {
            if (sourceView === targetView) {
              return false;
            }
            if (!sourceMagnet) {
              return false;
            }
            if (!targetMagnet) {
              return false;
            }
            return true;
          },
        },
        interacting: function (cellView) {
          if (
            cellView.cell.getData() != undefined &&
            !cellView.cell.getData().disableMove
          ) {
            return { nodeMovable: false };
          }
          return true;
        },
      });
      // 对齐线
      this.graph.use(
        new Snapline({
          enabled: true,
        })
      );
      // 框选
      // this.graph.use(
      //   new Selection({
      //     enabled: true,
      //     showNodeSelectionBox: true,
      //   })
      // );
      this.graph.use(
        new Keyboard({
          enabled: true,
          global: true,
        })
      );

      this.graph.on("cell:mouseenter", ({ cell }) => {
        let temp = cell.label ? cell.label.includes("线") : false;
        if (temp) {
          return {
            selectable: false,
          };
        }
        let yuliu = cell.label
          ? cell.label.includes("点") || cell.label.includes("空")
          : false;
        if (yuliu) {
          return {
            selectable: false,
          };
        }
        
        if (cell.isNode()) {
          let ports = container.querySelectorAll(".x6-port-body");
          let show = true;
          for (let i = 0, len = ports.length; i < len; i = i + 1) {
            ports[i].style.visibility = show ? "visible" : "hidden";
          }
          cell.addTools([
            {
              name: "button-remove",
              args: {
                x: 0,
                y: 0,
                offset: { x: 20, y: 10 },
              },
            },
          ]);
        } else {
          cell.addTools([
            {
              name: "vertices",
              args: {
                stopPropagation: false,
              },
            },
            { name: "segments" }, //添加线上的平移
            {
              name: "button",
              args: {
                markup: [
                  {
                    tagName: "circle",
                    selector: "button",
                    attrs: {
                      r: 16,
                      stroke: "#3d85f2",
                      "stroke-width": 3,
                      fill: "#3d85f2",
                      cursor: "pointer",
                    },
                  },
                  {
                    tagName: "text",
                    textContent: "🗑︎",
                    selector: "icon",
                    attrs: {
                      fill: "#fff",
                      "font-size": 25,
                      "text-anchor": "middle",
                      "pointer-events": "none",
                      y: "0.3em",
                    },
                  },
                ],
                distance: 40,
                onClick({ view }) {
                  const node = view.cell;
                  node.remove();
                },
              },
            },
          ]);
        }
      });

      this.graph.on("cell:mouseleave", ({ cell }) => {
        cell.removeTools();
        let ports = container.querySelectorAll(".x6-port-body");
        let show = false;
        for (let i = 0, len = ports.length; i < len; i = i + 1) {
          ports[i].style.visibility = show ? "visible" : "hidden";
        }
      });
      this.graph.on("node:click", ({ cell }) => {
        let yuliu = cell.label
          ? cell.label.includes("点") || cell.label.includes("空")
          : false;
        if (yuliu) {
          return false;
        }
        let temp = cell.label ? cell.label.includes("线") : false;
        if (temp) {
          return false;
        }
        this.delCell = cell;

        let textClick = cell.store.data.attrs.label;
        if (textClick.text.includes("xxxx艺")) {
          this.flag1 = true;
        } else {
          this.flag = true;
        }
        this.celll = cell;
        if (cell.form) {
          this.ruleForm.name = cell.form.name;
          this.ruleForm.count = cell.form.count;
        }
      });
      this.graph.on("cell:mousedown", ({ cell }) => {
        let yuliu = cell.label
          ? cell.label.includes("点") || cell.label.includes("空")
          : false;
        if (yuliu) {
          return false;
        }
        let temp = cell.label ? cell.label.includes("线") : false;
        if (temp) {
          return false;
        }
        this.delCell = cell;
      });
      this.graph.bindKey("delete", () => {
        if (this.delCell) {
          this.graph.removeNode(this.delCell);
        }
        // const cells = this.graph.getSelectedCells();
        return false;
      });

      this.graph.on("node:mousemove", ({ cell }) => {
        //#region 过滤
        let temp = cell.label ? cell.label.includes("线") : false;
        if (temp) {
          return {
            selectable: false,
          };
        }
        let yuliu = cell.label
          ? cell.label.includes("点") || cell.label.includes("空")
          : false;
        if (yuliu) {
          return {
            selectable: false,
          };
        }
        //#endregion
        //#region 吸附
        const snapThreshold = 100; 
        const snapSegmentLength = 1;
        let x1 = 30,x2 = 245,x3 = 465,x4 = 685,x5 = 905;
        let y1 = 90,y2 = 190,y3 = 290,y4 = 390;
        const targetPoints = [
                { x: x1, y: y1 },
                { x: x1, y: y2 },
                { x: x1, y: y3 },
                { x: x1, y: y4 },
                // { x: x1, y: y5 },

                { x: x2, y: y1 },
                { x: x2, y: y2 },
                { x: x2, y: y3 },
                { x: x2, y: y4 },
                // { x: x2, y: y5 },

                { x: x3, y: y1 },
                { x: x3, y: y2 },
                { x: x3, y: y3 },
                { x: x3, y: y4 },
                // { x: x3, y: y5 },

                { x: x4, y: y1 },
                { x: x4, y: y2 },
                { x: x4, y: y3 },
                { x: x4, y: y4 },
                // { x: x4, y: y5 },

                { x: x5, y: y1 },
                { x: x5, y: y2 },
                { x: x5, y: y3 },
                { x: x5, y: y4 },
                // { x: x5, y: y5 },
        ];
        
        let node = cell.position();
        for (let i = 0; i < targetPoints.length; i++) {
            const point = targetPoints[i];
            if (node.x <= point.x &&node.x <= point.y &&
            node.y > point.x &&node.y <= point.y) 
              {
                cell.position(point.x, point.y);
              }
              const distX = Math.abs(point.x - node.x);
              const distY = Math.abs(point.y - node.y);
              // 如果距离小于吸附区域,则进行吸附
              if (distX < snapThreshold && distY < snapThreshold) {
                // 计算吸附点,使其对齐到网格
                const snapX =
                  Math.round(point.x / snapSegmentLength) * snapSegmentLength;
                const snapY =
                  Math.round(point.y / snapSegmentLength) * snapSegmentLength;
                cell.position(snapX, snapY, cell); // 更新图形位置
                return false; // 跳出循环,只对第一个目标位置进行吸附
              }
        }
        //#endregion
      });
    },
    reservePlace() {
      this.graph.fromJSON(this.dataPlacer);
     
      // let cells = [];
      // this.dataPlacer.forEach((item) => {
      //   if (item.shape === "lane-edge") {
      //     cells.push(this.graph.createEdge(item));
      //   } else {
      //     cells.push(this.graph.createNode(item));
      //   }
      //   this.graph.resetCells(cells);
      //   this.graph.zoomToFit({ padding: 10, maxScale: 1 });
      // });
    },
    // 拖
    startDrag(type, e) {
      if (type.includes("xxx艺")) {
        type = "艺名称";
      } else {
        type = "运名称";
      }
      let temp = this.graph;
      let arr = [];
      let nam = "";
      let tt = temp.container.innerText.split("\n");
      if (tt) {
        for (let j = 0; j < tt.length; j++) {
          const dd = tt[j];
          if (dd != "") {
            arr.push(dd.trim());
          }
        }
        for (let i = 0; i < arr.length + 1; i++) {
          const name = arr[i];
          nam = `${type}${arr.length - 25 + 1}`;
          // console.log(nam);
          if (name == type) {
            nam = `${type}${i + 1}`;
            arr.push(nam);
          }
        }
      }
		// 以上代码可以根据自己的实际情况来写,也可以不写以上代码
		// 如果不写上面的代码,把下面括号中的nam换成type
      startDragToGraph(this.graph, nam, e);
    },
	}mounted() {
    this.init();
    this.reservePlace();
  },
}
</script>

3.在utils文件夹中新建一个drags.js来实现拖拽

安装npm i @antv/x6-plugin-dnd文章来源地址https://www.toymoban.com/news/detail-568510.html

import { Dnd } from "@antv/x6-plugin-dnd";
export const startDragToGraph = (graph, type, e) => {
  const node = graph.createNode({
    shape: "rect",
    width: 140,
    height: 42,
    attrs: {
      label: {
        text: type,
        fill: "#00539a",
        textAnchor: "middle",
        verticalAnchor: "middle",
        fontSize: 20,
        ellipsis: true,
        breakWord: true,
        textWrap: {
          width: -10,
          height: -10,
          ellipsis: true,
        },
      },
      body: {
        stroke: "#00539a",
        strokeWidth: 2,
        fill: "#ffffff",
      },
    },
    tools: [   // 使拖拽的元素具有删除的图标
      {
        name: "button-remove",
        args: {
          x: 20,
          y: 10,
        },
      },
    ],
    ports: ports,
  });
  graph.on('node:added', ({cell}) => {
       const snapThreshold = 100; 
       const snapSegmentLength = 1;
       let x1 = 30,x2 = 245,x3 = 465,x4 = 685,x5 = 905;
       let y1 = 90,y2 = 190,y3 = 290,y4 = 390;
       const targetPoints = [
               { x: x1, y: y1 },
               { x: x1, y: y2 },
               { x: x1, y: y3 },
               { x: x1, y: y4 },

               { x: x2, y: y1 },
               { x: x2, y: y2 },
               { x: x2, y: y3 },
               { x: x2, y: y4 },

               { x: x3, y: y1 },
               { x: x3, y: y2 },
               { x: x3, y: y3 },
               { x: x3, y: y4 },

               { x: x4, y: y1 },
               { x: x4, y: y2 },
               { x: x4, y: y3 },
               { x: x4, y: y4 },

               { x: x5, y: y1 },
               { x: x5, y: y2 },
               { x: x5, y: y3 },
               { x: x5, y: y4 },
       ];
       
       let node = cell.position();
       for (let i = 0; i < targetPoints.length; i++) {
           const point = targetPoints[i];
           if (node.x <= point.x &&node.x <= point.y &&
             node.y > point.x &&node.y <= point.y) 
             {
               cell.position(point.x, point.y);
             }
             const distX = Math.abs(point.x - node.x);
             const distY = Math.abs(point.y - node.y);
             // 如果距离小于吸附区域,则进行吸附
             if (distX < snapThreshold && distY < snapThreshold) {
               // 计算吸附点,使其对齐到网格
               const snapX =
                 Math.round(point.x / snapSegmentLength) * snapSegmentLength;
               const snapY =
                 Math.round(point.y / snapSegmentLength) * snapSegmentLength;
               cell.position(snapX, snapY, cell); // 更新图形位置
               return false; // 跳出循环,只对第一个目标位置进行吸附
             }
       }
       //#endregion
    })

  const dnd = new Dnd({
    target: graph,
  });
  dnd.start(node, e);
};
const ports = {
  groups: {
    top: {
      position: "top",
      zIndex: 1,
      attrs: {
        portBody: {
          "port-type": "ellipse",
          r: 8,
          magnet: true,
          stroke: "#2D8CF0",
          strokeWidth: 2,
          fill: "#2D8CF0",
        },
        portCross: {
          "port-type": "decorator",
          ref: "portBody",
          "ref-x": -4.5,
          "ref-y": 0,
          "ref-dx": 0,
          "ref-dy": 0,
          position: {
            name: "center",
          },
          d: "M 0 0 L 10 0 M 5 -5 L 5 5",
          stroke: "#fff",
          strokeWidth: 1,
          fill: "#fff",
          magnet: true,
          zIndex: 2,
        },
      },
      markup: [
        {
          tagName: "circle",
          selector: "portBody",
        },
        {
          tagName: "path",
          selector: "portCross",
        },
      ],
    },
    bottom: {
      position: "bottom",
      zIndex: 1,
      attrs: {
        portBody: {
          "port-type": "ellipse",
          r: 8,
          magnet: true,
          stroke: "#2D8CF0",
          strokeWidth: 2,
          fill: "#2D8CF0",
        },
        portCross: {
          "port-type": "decorator",
          ref: "portBody",
          "ref-x": -4.5,
          "ref-y": 0,
          "ref-dx": 0,
          "ref-dy": 0,
          position: {
            name: "center",
          },
          d: "M 0 0 L 10 0 M 5 -5 L 5 5",
          stroke: "#fff",
          strokeWidth: 1,
          fill: "#fff",
          magnet: true,
          zIndex: 2,
        },
      },
      markup: [
        {
          tagName: "circle",
          selector: "portBody",
        },
        {
          tagName: "path",
          selector: "portCross",
        },
      ],
    },
    left: {
      position: "left",
      zIndex: 1,
      attrs: {
        portBody: {
          "port-type": "ellipse",
          r: 8,
          magnet: true,
          stroke: "#2D8CF0",
          strokeWidth: 2,
          fill: "#2D8CF0",
        },
        portCross: {
          "port-type": "decorator",
          ref: "portBody",
          "ref-x": -4.5,
          "ref-y": 0,
          "ref-dx": 0,
          "ref-dy": 0,
          position: {
            name: "center",
          },
          d: "M 0 0 L 10 0 M 5 -5 L 5 5",
          stroke: "#fff",
          strokeWidth: 1,
          fill: "#fff",
          magnet: true,
          zIndex: 2,
        },
      },
      markup: [
        {
          tagName: "circle",
          selector: "portBody",
        },
        {
          tagName: "path",
          selector: "portCross",
        },
      ],
    },
    right: {
      position: "right",
      zIndex: 1,
      attrs: {
        portBody: {
          "port-type": "ellipse",
          r: 8,
          magnet: true,
          stroke: "#2D8CF0",
          strokeWidth: 2,
          fill: "#2D8CF0",
        },
        portCross: {
          "port-type": "decorator",
          ref: "portBody",
          "ref-x": -4.5,
          "ref-y": 0,
          "ref-dx": 0,
          "ref-dy": 0,
          position: {
            name: "center",
          },
          d: "M 0 0 L 10 0 M 5 -5 L 5 5",
          stroke: "#fff",
          strokeWidth: 1,
          fill: "#fff",
          magnet: true,
          zIndex: 2,
        },
      },
      markup: [
        {
          tagName: "circle",
          selector: "portBody",
        },
        {
          tagName: "path",
          selector: "portCross",
        },
      ],
    },
  },
  items: [
    {
      id: "port1",
      group: "top",
    },
    {
      id: "port2",
      group: "bottom",
    },
    {
      id: "port3",
      group: "left",
    },
    {
      id: "port4",
      group: "right",
    },
  ],
};

到了这里,关于创建可交互的图表:AntV X6实现预留空白位置、拖拽吸附与信息修改弹框的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • antv x6 神奇的图片边框

    昨天才把html节点中的图片转成base格式的,今天就发现一个用户体验的问题;那么是啥呢?就是我从左侧的树形菜单中拖拽节点的时候(鼠标按下也是同样问题),发现节点的图片区域那里会出现一个边框,持续时间不是很长,就几毫秒的时间,但是当你连续拖拽几个不同节

    2023年04月27日
    浏览(29)
  • vue3+ts使用antv/x6

    使用 2.x 版本 x6.antv 新官网: 项目结构 1、初始化画布 index.vue 2、注册节点 渲染 Vue 节点,这个文档完全够用 节点node.vue 3、在画布引入并注册自定义节点,配置节点信息 主画布:index.vue 展示 小小预告: 下一篇 自定义节点样式 再下一篇 vue3 + antv/x6 实现拖拽侧边栏节点到画布

    2024年02月13日
    浏览(34)
  • Vue使用AntV X6绘制流程图(组态呈现)

    先上几个网址 AntV | 蚂蚁数据可视化 AntV X6 图编辑引擎 AntV X6文档 AntV X6 API AntV X6图表示例 上面是一些用到的网址,先说下我项目中的需求,就是要自己绘制出一个我们想要的图,组态化呈现出来,然后这个图中会有很多节点,每个节点都会有自己的状态 ,状态会实时改变,

    2024年02月06日
    浏览(64)
  • 「AntV」X6开发实践:踩过的坑与解决方案

    长期更新版文档请移步语雀(「AntV」X6开发实践:踩过的坑与解决方案 (yuque.com)) --Recent update:2024-01-05 相信你们在开发中更多的需求是需要自定义拖拽源,毕竟自定义的功能扩展性高一些,而且可以根据你的业务需求灵活设置。自定义拖拽的优点就是:万物皆可成为拖拽源,

    2024年02月08日
    浏览(104)
  • vue3+ts使用antv/x6 + 自定义节点

    使用 2.x 版本 x6.antv 新官网: 项目结构 1、初始化画布 index.vue 2、注册节点 渲染 Vue 节点,这个文档完全够用 节点node.vue 3、在画布引入并注册自定义节点,配置节点信息 主画布:index.vue 展示 小小预告: 下一篇 自定义节点样式 再下一篇 vue3 + antv/x6 实现拖拽侧边栏节点到画布

    2024年02月12日
    浏览(40)
  • 在vue3中浅尝antv X6 2.0 demo(三)

    终于抽空把antv X6 2.0这个版本的demo抽出来了,原以为项目会一直使用vue3去做这个流程,结果最近项目经理说antv X6的菜单功能只有react才能用...然鹅...写到菜单模块的时候,发现都可以用的... 目前我项目里面react版本的多一些功能(如:新增节点时自动布局、右键菜单,如图)

    2024年02月05日
    浏览(36)
  • Dash,方便创建「交互式」Web图表!

    你好,我是郭震 这篇文章,探讨 Dash —— 一个由 Plotly 开发的优秀 Python 框架,专为构建丰富的网络分析应用而设计。 推荐使用这个Python工具包! Dash 使得数据分析师能够使用 Python 创建互动式的 web 应用,而无需深入了解复杂的前端技术如 HTML 或 JavaScript。 要开始使用 Das

    2024年02月22日
    浏览(61)
  • 自定义QChartView实现鼠标放在图表时,显示鼠标位置坐标值(x,y)

    前言: 因为需要一次性从文件中加载大量数据到图表中显示,所以打算使用qchartview+qscrollarea,当横坐标数据超出默认设定的显示范围之后,重新设置chartview的宽度和scrollarea内容区域(scrollAreaWidgetContents)的宽度,从而实现一次性显示所有数据的目的。因为这样显示之后,如果

    2024年02月05日
    浏览(40)
  • antv/g6 交互与事件及自定义Behavior

    在 G6 中,提供了直接的单机事件、还有监听时机的方法。可以监听画布、节点、边、以及各函数被调用的时机等: 1. 绑定事件 要绑定事件,首先需要获得图表实例( Graph 实例),然后使用 on 方法来绑定事件。 分为三类:全局事件、canvas事件、节点/边/combo事件; eventName 是

    2024年02月04日
    浏览(43)
  • 用Python实现创建十二星座数据分析图表

    下面小编提供的代码中,您已经将 pie.render() 注释掉,并使用了 pie.render_to_file(\\\'十二星座.svg\\\') 来将饼状图渲染到一个名为 十二星座.svg 的文件中。这是一个正确的做法,如果您想在文件中保存图表而不是在浏览器中显示它。 成功创建图表: 问题分析: 要确保代码能够正常工

    2024年02月21日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包