vue项目中使用antv X6新手教程,附demo案例讲解(可拖拽流程图、网络拓扑图)

news/2024/5/18 21:30:22 标签: vue.js, 前端, 数据可视化, javascript, 流程图

前言:

之前分别做了vue2和vue3项目里的网络拓扑图功能,发现对antv X6的讲解博客比较少,最近终于得闲码一篇了!

需求:

用户可以自己拖拽节点,节点之间可以随意连线,保存拓扑图数据后传给后端,然后在另一个页面拿到之前的数据进行渲染展示。

最终成品如下图:

一、准备工作: 

1、装依赖

npm install --save @antv/x6

2、布局样式

首先我们先规划两块地方,左边用来放可以拖的节点,右边是antv X6的画布,如下图:(随意做的demo,比较丑哈)

布局代码:
<template>
  <div class="dashboard-container">
    <p>选择节点</p>
    <div class="antvBox">
      <div class="menu-list">
        <div v-for="item in moduleList" :key="item.id">
          <img :src="item.image" alt="" />
          <p>{{ item.name }}</p>
        </div>
      </div>
      <div class="canvas-card">
        <div id="container" />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "antvX6",
  data() {
    return {
      moduleList: [
        {
          id: 1,
          name: "节点1",
          image: require("@/assets/img/1.png"),
        },
        {
          id: 8,
          name: "节点2",
          image: require("@/assets/img/2.png"),
        },
        {
          id: 2,
          name: "节点3",
          image: require("@/assets/img/3.png"),
        },
        {
          id: 3,
          name: "节点4",
          image: require("@/assets/img/4.png"),
        },
      ],
    };
  },
};
</script>
<style lang="scss" scoped>
.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>

3、添加拖拽事件

我们要先给左侧图标加一个拖拽结束的事件:

代码如下:
javascript">draggable="true"
@dragend="handleDragEnd($event, item)"

在methods定义handleDragEnd函数: 

javascript">// 拖动后松开鼠标触发事件
    handleDragEnd(e, item) {
      console.log(e, item); // 可以获取到最后拖动后松开鼠标时的坐标和拖动的节点相关信息
    },
效果 :

这个时候我们可以去页面试着拖动一个左边的图标,在鼠标松开时会看到控制台输出了节点相关信息,如下图:

 以上就是准备工作了

二、使用antv X6

1、引入antv X6

javascript">import { Graph } from "@antv/x6";

2、初始化画布

先在data(){}定义graph做画布示例对象:

定义一个初始化函数,并且在mounted里面调用如下:

javascript">initGraph() {
      const container = document.getElementById("container");
      this.graph = 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, // 网格线宽度/网格点大小
          },
        },
      });
    },
javascript"> mounted() {
    this.initGraph();
  },

这里就是一些对画布的配置,多数我都加了注释,如有部分配置不懂可以评论区问我或者查官方文档

3、画布添加节点

代码如下:

javascript"> //添加节点到画布
    addHandleNode(x, y, id, image, name) {
      this.graph.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,
      });
    },

这里使用了antv X6提供的一个方法addNode,传入的参数分别是:x坐标、y坐标、id节点唯一标识、image图片、name节点名称,我的案例这五种就够了,如果有不同需求可以自己加

4、调用addHandleNode函数

在我们之前写了的拖动节点结束后的函数(handleDragEnd)里面去调用上面那个函数,代码如下:

javascript">// 拖动后松开鼠标触发事件
    handleDragEnd(e, item) {
      console.log(e, item); // 可以获取到最后拖动后松开鼠标时的坐标和拖动的节点相关信息
      this.addHandleNode(
        e.pageX - 500,
        e.pageY - 200,
        new Date().getTime(),
        item.image,
        item.name
      );
    },

以上所有操作做完应该就可以完成节点拖拽、连线功能:

5、上图我们可以发现还差一些需求:

  • 节点上的那个蓝色的连接桩一直显示,有点遮挡图标,也不太好看

  • 节点无法删除

  • 节点之间的连线也无法删除

这些都是需要点击操作的事件,需要了解antv X6的事件系统,官方文档贴图如下

需求1:鼠标移入节点再显示连接桩

定义一个函数nodeAddEvent,代码如下:

javascript">nodeAddEvent() {
      const { graph } = this;
      const container = document.getElementById("container");
      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";
        }
      };
      this.graph.on("node:mouseenter", () => {
        changePortsVisible(true);
      });
      this.graph.on("node:mouseleave", () => {
        changePortsVisible(false);
      });
    },

然后把这个函数在initGraph里面调用一下:

需求2:可以选中并删除节点

想要的效果如下图:

先在data(){}里面定义curSelectNode,然后在nodeAddEvent函数里加入以下代码:

javascript">// 节点绑定点击事件
      this.graph.on("node:click", ({ e, x, y, node, view }) => {
        console.log("点击!!!", node);
        // 判断是否有选中过节点
        if (this.curSelectNode) {
          // 移除选中状态
          this.curSelectNode.removeTools();
          // 判断两次选中节点是否相同
          if (this.curSelectNode !== 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,
                  },
                },
              },
            ]);
            this.curSelectNode = node;
          } else {
            this.curSelectNode = null;
          }
        } else {
          this.curSelectNode = 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,
                },
              },
            },
          ]);
        }
      });

这里使用了antv X6的工具集,官方文档贴图如下:(需求3也使用了工具集)

需求3:可以选中并删除节点间连线

 想要的效果如下:

在nodeAddEvent函数里加入以下代码:

javascript"> // 连线绑定悬浮事件
      this.graph.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; // 保证当前悬停的线在最上层,不会被遮挡
        }
      });
      this.graph.on("cell:mouseleave", ({ cell }) => {
        if (cell.shape === "edge") {
          cell.removeTools();
          cell.setAttrs({
            line: {
              stroke: "black",
            },
          });
          cell.zIndex = 1; // 保证未悬停的线在下层,不会遮挡悬停的线
        }
      });

6、输出拓扑图信息

可以写一个按钮来保存拓扑图信息,这里介绍以下两个个人感觉常用的函数:

javascript">//保存画布,并提交
    save() {
      console.log(this.graph.toJSON(), "graph");
      console.log(this.graph.getNodes(), "node");
    },

如上图所示,点击保存按钮后 ,控制台会输出:

第一个是整个图的信息,有节点有连线,可以自己展开看看里面的数据,第二个只有节点数据

四、总结

antv X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和开箱即用的内置扩展,方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。

这里只是介绍了一种基础拓扑图的案例,也可以将节点image换成react,做一个编辑节点内文字的功能,就变成流程图了。

查看官方文档和示例,也很容易加入其他的功能

antv X6案例链接:https://x6.antv.antgroup.com/examples

api文档:Graph | X6 


http://www.niftyadmin.cn/n/5396916.html

相关文章

【大数据架构(1)】Lambda Architecture – Realtime Data Processing 论文重点翻译

文章目录 1. INTRODUCTION2. LAMBDA ARCHITECTUREA) BATCH LAYERB) SPEED LAYERC) SERVICE LAYER 3. LIMITATIONS OF THE TRADITIONAL LAMBDAARCHITECTURE4. A PROPOSED SOLUTION1. 架构说明2. 前后架构改进对比 1. INTRODUCTION Lambda架构背后的需求是由于虽然MR能够处理大数…

java 大学生社团管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 大学生社团管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5…

高刷显示器 - HKC VG253KM

&#x1f525;&#x1f525; 今天来给大家揭秘一款电竞神器 - HKC VG253KM 高刷电竞显示器&#xff01;这款显示器可是有着雄鹰展翅般的设计灵感&#xff0c;背后的大鹏展翅鹰翼图腾让人过目难忘。那么&#xff0c;这款显示器到底有哪些过人之处呢&#xff1f;一起来看看吧&…

python+vue+django城市公交车辆调度运营管理系统flask-pycharm毕业设计项目lw

本文讲述了城市公交运营管理系统。结合电子管理系统的特点&#xff0c;分析了城市公交运营管理系统的背景&#xff0c;给出了城市公交运营管理系统实现的设计方案。 本论文主要完成不同用户的权限划分&#xff0c;不同用户具有不同权限的操作功能&#xff0c;在公交员模块&…

设置django orm 模型中的字段限制数值的大小

需求如下&#xff1a; 1&#xff1a;使用了django框架中的orm模式来创建数据表 2&#xff1a;限制字段的取值范围 # -------------------- # 因为django的orm没有限制整形字段的取值范围&#xff0c;所以需要django内置的值校验器进行校验 from django.core.validators i…

数据结构 第2章 线性表(一轮习题总结)

第2章 线性表 2.1 线性表的定义和基本操作2.2 线性表的顺序表示2.3 线性表的链式表示 2.1 线性表的定义和基本操作 2.2 线性表的顺序表示 2.3 线性表的链式表示&#xff08;4 7&#xff09; 2.1 线性表的定义和基本操作 2.2 线性表的顺序表示 2.3 线性表的链式表示 T4 顺序存…

关于uniapp小程序的分包问题

开发uniapp小程序时&#xff0c;在打包上传代码时会出现超出2M的打包限制不能上传&#xff0c;那么我们该怎么做呢&#xff1f; 1.对于图片&#xff0c;将图片从后端服务取&#xff0c;尽量不要放在静态资源&#xff0c;图片体积会影响打包大小。 2.使用分包&#xff0c;tabb…

一个可操作PPT的.Net开源库

推荐一个简单易用的.NET库&#xff0c;使得可以方便处理PowerPoint演示文稿。 01 项目简介 ShapeCrawler 是一个专为处理 PowerPoint 演示文稿而设计的 .NET 库。这个库为开发者提供了一组简单易用的 API&#xff0c;以便操作 PowerPoint (.pptx) 文件中的各种元素。 ShapeC…