岳阳网站开发建设,网站域名注册申请,天元建设集团有限公司青岛分公司,深圳 网站建设设计前言#xff1a;
之前分别做了vue2和vue3项目里的网络拓扑图功能#xff0c;发现对antv X6的讲解博客比较少#xff0c;最近终于得闲码一篇了#xff01;
需求#xff1a;
用户可以自己拖拽节点#xff0c;节点之间可以随意连线#xff0c;保存拓扑图数据后传给后端
之前分别做了vue2和vue3项目里的网络拓扑图功能发现对antv X6的讲解博客比较少最近终于得闲码一篇了
需求
用户可以自己拖拽节点节点之间可以随意连线保存拓扑图数据后传给后端然后在另一个页面拿到之前的数据进行渲染展示。
最终成品如下图 一、准备工作
1、装依赖
npm install --save antv/x6 2、布局样式
首先我们先规划两块地方左边用来放可以拖的节点右边是antv X6的画布如下图随意做的demo比较丑哈 布局代码
templatediv classdashboard-containerp选择节点/pdiv classantvBoxdiv classmenu-listdiv v-foritem in moduleList :keyitem.idimg :srcitem.image alt /p{{ item.name }}/p/div/divdiv classcanvas-carddiv idcontainer //div/div/div
/templatescript
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 langscss 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、添加拖拽事件
我们要先给左侧图标加一个拖拽结束的事件 代码如下
draggabletrue
dragendhandleDragEnd($event, item)
在methods定义handleDragEnd函数
// 拖动后松开鼠标触发事件handleDragEnd(e, item) {console.log(e, item); // 可以获取到最后拖动后松开鼠标时的坐标和拖动的节点相关信息},
效果
这个时候我们可以去页面试着拖动一个左边的图标在鼠标松开时会看到控制台输出了节点相关信息如下图 以上就是准备工作了
二、使用antv X6
1、引入antv X6
import { Graph } from antv/x6;2、初始化画布
先在data{}定义graph做画布示例对象 定义一个初始化函数并且在mounted里面调用如下
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, // 网格大小 10pxvisible: true, // 渲染网格背景args: {color: #a0a0a0, // 网格线/点颜色thickness: 2, // 网格线宽度/网格点大小},},});}, mounted() {this.initGraph();},
这里就是一些对画布的配置多数我都加了注释如有部分配置不懂可以评论区问我或者查官方文档
3、画布添加节点
代码如下 //添加节点到画布addHandleNode(x, y, id, image, name) {this.graph.addNode({id: id,shape: image, // 指定使用何种图形默认值为 rectx: 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里面去调用上面那个函数代码如下
// 拖动后松开鼠标触发事件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代码如下
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函数里加入以下代码
// 节点绑定点击事件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函数里加入以下代码 // 连线绑定悬浮事件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、输出拓扑图信息
可以写一个按钮来保存拓扑图信息这里介绍以下两个个人感觉常用的函数
//保存画布并提交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