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


    前言:

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

    需求:

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

    最终成品如下图:

    一、准备工作: 

    1、装依赖

    npm install --save @antv/x6

    2、布局样式

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

    布局代码:
    1. <template>
    2. <div class="dashboard-container">
    3. <p>选择节点p>
    4. <div class="antvBox">
    5. <div class="menu-list">
    6. <div v-for="item in moduleList" :key="item.id">
    7. <img :src="item.image" alt="" />
    8. <p>{{ item.name }}p>
    9. div>
    10. div>
    11. <div class="canvas-card">
    12. <div id="container" />
    13. div>
    14. div>
    15. div>
    16. template>
    17. <script>
    18. export default {
    19. name: "antvX6",
    20. data() {
    21. return {
    22. moduleList: [
    23. {
    24. id: 1,
    25. name: "节点1",
    26. image: require("@/assets/img/1.png"),
    27. },
    28. {
    29. id: 8,
    30. name: "节点2",
    31. image: require("@/assets/img/2.png"),
    32. },
    33. {
    34. id: 2,
    35. name: "节点3",
    36. image: require("@/assets/img/3.png"),
    37. },
    38. {
    39. id: 3,
    40. name: "节点4",
    41. image: require("@/assets/img/4.png"),
    42. },
    43. ],
    44. };
    45. },
    46. };
    47. script>
    48. <style lang="scss" scoped>
    49. .dashboard-container {
    50. .antvBox {
    51. display: flex;
    52. width: 100%;
    53. height: 100%;
    54. color: black;
    55. padding-top: 20px;
    56. .menu-list {
    57. height: 100%;
    58. width: 300px;
    59. padding: 0 10px;
    60. box-sizing: border-box;
    61. display: flex;
    62. justify-content: space-between;
    63. align-content: flex-start;
    64. flex-wrap: wrap;
    65. > div {
    66. margin-bottom: 10px;
    67. border-radius: 5px;
    68. padding: 0 10px;
    69. box-sizing: border-box;
    70. cursor: pointer;
    71. color: black;
    72. width: 105px;
    73. display: flex;
    74. flex-wrap: wrap;
    75. justify-content: center;
    76. img {
    77. height: 50px;
    78. width: 50px;
    79. }
    80. P {
    81. width: 90px;
    82. text-align: center;
    83. }
    84. }
    85. }
    86. .canvas-card {
    87. width: 1700px;
    88. height: 750px;
    89. box-sizing: border-box;
    90. > div {
    91. width: 1400px;
    92. height: 750px;
    93. border: 2px dashed #2149ce;
    94. }
    95. }
    96. }
    97. }
    98. style>

    3、添加拖拽事件

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

    代码如下:
    1. draggable="true"
    2. @dragend="handleDragEnd($event, item)"

    在methods定义handleDragEnd函数: 

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

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

     以上就是准备工作了

    二、使用antv X6

    1、引入antv X6

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

    2、初始化画布

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

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

    1. initGraph() {
    2. const container = document.getElementById("container");
    3. this.graph = new Graph({
    4. container: container, // 画布容器
    5. width: container.offsetWidth, // 画布宽
    6. height: container.offsetHeight, // 画布高
    7. background: false, // 背景(透明)
    8. snapline: true, // 对齐线
    9. // 配置连线规则
    10. connecting: {
    11. snap: true, // 自动吸附
    12. allowBlank: false, // 是否允许连接到画布空白位置的点
    13. allowMulti: true, // 是否允许在相同的起始节点和终止之间创建多条边
    14. allowLoop: true, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点
    15. highlight: true, // 拖动边时,是否高亮显示所有可用的节点
    16. highlighting: {
    17. magnetAdsorbed: {
    18. name: "stroke",
    19. args: {
    20. attrs: {
    21. fill: "#5F95FF",
    22. stroke: "#5F95FF",
    23. },
    24. },
    25. },
    26. },
    27. router: {
    28. // 对路径添加额外的点
    29. name: "orth",
    30. },
    31. connector: {
    32. // 边渲染到画布后的样式
    33. name: "rounded",
    34. args: {
    35. radius: 8,
    36. },
    37. },
    38. },
    39. panning: {
    40. enabled: false,
    41. },
    42. mousewheel: {
    43. enabled: true, // 支持滚动放大缩小
    44. zoomAtMousePosition: true,
    45. modifiers: "ctrl",
    46. minScale: 0.5,
    47. maxScale: 3,
    48. },
    49. grid: {
    50. type: "dot",
    51. size: 20, // 网格大小 10px
    52. visible: true, // 渲染网格背景
    53. args: {
    54. color: "#a0a0a0", // 网格线/点颜色
    55. thickness: 2, // 网格线宽度/网格点大小
    56. },
    57. },
    58. });
    59. },
    1. mounted() {
    2. this.initGraph();
    3. },

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

    3、画布添加节点

    代码如下:

    1. //添加节点到画布
    2. addHandleNode(x, y, id, image, name) {
    3. this.graph.addNode({
    4. id: id,
    5. shape: "image", // 指定使用何种图形,默认值为 'rect'
    6. x: x,
    7. y: y,
    8. width: 60,
    9. height: 60,
    10. imageUrl: image,
    11. attrs: {
    12. body: {
    13. stroke: "#ffa940",
    14. fill: "#ffd591",
    15. },
    16. label: {
    17. textWrap: {
    18. width: 90,
    19. text: name,
    20. },
    21. fill: "black",
    22. fontSize: 12,
    23. refX: 0.5,
    24. refY: "100%",
    25. refY2: 4,
    26. textAnchor: "middle",
    27. textVerticalAnchor: "top",
    28. },
    29. },
    30. ports: {
    31. groups: {
    32. group1: {
    33. position: [30, 30],
    34. },
    35. },
    36. items: [
    37. {
    38. group: "group1",
    39. id: "port1",
    40. attrs: {
    41. circle: {
    42. r: 6,
    43. magnet: true,
    44. stroke: "#ffffff",
    45. strokeWidth: 2,
    46. fill: "#5F95FF",
    47. },
    48. },
    49. },
    50. ],
    51. },
    52. zIndex: 10,
    53. });
    54. },

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

    4、调用addHandleNode函数

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

    1. // 拖动后松开鼠标触发事件
    2. handleDragEnd(e, item) {
    3. console.log(e, item); // 可以获取到最后拖动后松开鼠标时的坐标和拖动的节点相关信息
    4. this.addHandleNode(
    5. e.pageX - 500,
    6. e.pageY - 200,
    7. new Date().getTime(),
    8. item.image,
    9. item.name
    10. );
    11. },

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

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

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

    • 节点无法删除

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

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

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

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

    1. nodeAddEvent() {
    2. const { graph } = this;
    3. const container = document.getElementById("container");
    4. const changePortsVisible = (visible) => {
    5. const ports = container.querySelectorAll(".x6-port-body");
    6. for (let i = 0, len = ports.length; i < len; i = i + 1) {
    7. ports[i].style.visibility = visible ? "visible" : "hidden";
    8. }
    9. };
    10. this.graph.on("node:mouseenter", () => {
    11. changePortsVisible(true);
    12. });
    13. this.graph.on("node:mouseleave", () => {
    14. changePortsVisible(false);
    15. });
    16. },

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

    效果如下:

     

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

    想要的效果如下图:

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

    1. // 节点绑定点击事件
    2. this.graph.on("node:click", ({ e, x, y, node, view }) => {
    3. console.log("点击!!!", node);
    4. // 判断是否有选中过节点
    5. if (this.curSelectNode) {
    6. // 移除选中状态
    7. this.curSelectNode.removeTools();
    8. // 判断两次选中节点是否相同
    9. if (this.curSelectNode !== node) {
    10. node.addTools([
    11. {
    12. name: "boundary",
    13. args: {
    14. attrs: {
    15. fill: "#16B8AA",
    16. stroke: "#2F80EB",
    17. strokeWidth: 1,
    18. fillOpacity: 0.1,
    19. },
    20. },
    21. },
    22. {
    23. name: "button-remove",
    24. args: {
    25. x: "100%",
    26. y: 0,
    27. offset: {
    28. x: 0,
    29. y: 0,
    30. },
    31. },
    32. },
    33. ]);
    34. this.curSelectNode = node;
    35. } else {
    36. this.curSelectNode = null;
    37. }
    38. } else {
    39. this.curSelectNode = node;
    40. node.addTools([
    41. {
    42. name: "boundary",
    43. args: {
    44. attrs: {
    45. fill: "#16B8AA",
    46. stroke: "#2F80EB",
    47. strokeWidth: 1,
    48. fillOpacity: 0.1,
    49. },
    50. },
    51. },
    52. {
    53. name: "button-remove",
    54. args: {
    55. x: "100%",
    56. y: 0,
    57. offset: {
    58. x: 0,
    59. y: 0,
    60. },
    61. },
    62. },
    63. ]);
    64. }
    65. });

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

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

     想要的效果如下:

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

    1. // 连线绑定悬浮事件
    2. this.graph.on("cell:mouseenter", ({ cell }) => {
    3. if (cell.shape == "edge") {
    4. cell.addTools([
    5. {
    6. name: "button-remove",
    7. args: {
    8. x: "100%",
    9. y: 0,
    10. offset: {
    11. x: 0,
    12. y: 0,
    13. },
    14. },
    15. },
    16. ]);
    17. cell.setAttrs({
    18. line: {
    19. stroke: "#409EFF",
    20. },
    21. });
    22. cell.zIndex = 99; // 保证当前悬停的线在最上层,不会被遮挡
    23. }
    24. });
    25. this.graph.on("cell:mouseleave", ({ cell }) => {
    26. if (cell.shape === "edge") {
    27. cell.removeTools();
    28. cell.setAttrs({
    29. line: {
    30. stroke: "black",
    31. },
    32. });
    33. cell.zIndex = 1; // 保证未悬停的线在下层,不会遮挡悬停的线
    34. }
    35. });

    6、输出拓扑图信息

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

    1. //保存画布,并提交
    2. save() {
    3. console.log(this.graph.toJSON(), "graph");
    4. console.log(this.graph.getNodes(), "node");
    5. },

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

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

    四、总结

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

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

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

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

    api文档:Graph | X6 

  • 相关阅读:
    MYSQL高级(二)---索引
    C++ 实用指南
    【数据结构与算法】二叉排序树&平衡二叉树&哈夫曼树
    拓扑排序基础详解,附有练习题
    TDengine数据迁移
    Spring Boot 简介与入门
    jira流转issue条目状态transitions的rest实用脚本,issue状态改变调整
    DOM—节点操作
    ubuntu安装electerm
    转载-Troubleshooting .NET Blazor WASM Debugging
  • 原文地址:https://blog.csdn.net/wzy_PROTEIN/article/details/136305034