antd/x6-graph——实现流程图绘制功能——技能提升

效果图:
在这里插入图片描述

解决步骤1:安装"@antv/x6": "^1.35.0"

npm install @antv/x6@1.35.0

安装指定版本的antv/x6插件

解决步骤2:配置tools文件

assets/js中新增一个graphTools.js文件
内容如下:

/* 
antv x6图谱相关工具函数
*/
export default {/* 初始化初始节点(开始,结束节点)x:x轴坐标y:y轴坐标id:开始节点idname:节点内容,默认为空type:节点类型,默认为空*/gongxuNode(x, y, id, name, type) {let node = {shape: 'rect',type: type,id: id, // String,可选,节点的唯一标识x: x, // Number,必选,节点位置的 x 值y: y, // Number,必选,节点位置的 y 值width: 130, // Number,可选,节点大小的 width 值height: 30, // Number,可选,节点大小的 height 值label: "功能模块",attrs: {// 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线body: {strokeWidth: 3, // 边框的粗细magnet: true, // 节点是否可以连线}},extraProperties: {IsOutSend: false,IsSkip: false,TimeSpan: 0},// html: `//       <div class="custom_node_initial">//         <div>//           <p title=${name}>${name||''}</p>//         </div>//       </div>//       `,// attrs: {//   // 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线//   body: {//     stroke: 'transparent',//     strokeWidth: 3, // 边框的粗细//     magnet: true, // 节点是否可以连线//   }// },}return node},/* 初始化逻辑节点x:x轴坐标y:y轴坐标id:开始节点idname:节点内容,默认为空type:节点类型,默认为空*/tiaojianNode(x, y, id, name, type) {let node = {shape: 'rect',type: type, // 动作所属类型id: id, // String,可选,节点的唯一标识x: x, // Number,必选,节点位置的 x 值y: y, // Number,必选,节点位置的 y 值width: 190, // Number,可选,节点大小的 width 值height: 30, // Number,可选,节点大小的 height 值label: "条件模块",attrs: {// 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线body: {stroke: '#f90',fill: 'rgba(255, 172, 50, 0.2)',strokeWidth: 3, // 边框的粗细magnet: true, // 节点是否可以连线}},extraProperties: {IsOutSend: false,IsSkip: false,TimeSpan: 0},// html: `//         <div class="custom_node_logic">//           <div>//             <p title=${name}>${name||''}</p>//           </div>//         </div>//       `,// attrs: {//   body: {//     stroke: 'transparent',//     strokeWidth: 3,//     magnet: true,//   }// },}return node}
}

解决步骤3:页面引入及dom节点

import { Graph } from "@antv/x6";
import Tools from "@/assets/js/graphTools.js";

页面初始化:

 <!-- 画布部分 -->
<div class="canvas-card"><div id="container" @dragover="dragoverDiv"></div>
</div>

解决步骤4:data配置字段

model: {// 节点nodes: [{id: "start", // String,可选,节点的唯一标识x: 10, // Number,必选,节点位置的 x 值y: 10, // Number,必选,节点位置的 y 值width: 130, // Number,可选,节点大小的 width 值height: 30, // Number,可选,节点大小的 height 值label: "开始",type: "0", // 开始类型extraProperties: {IsOutSend: false,IsSkip: false,TimeSpan: 0},attrs: {// 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线body: {strokeWidth: 3, // 边框的粗细magnet: true // 节点是否可以连线}}},{id: "end", // String,可选,节点的唯一标识x: 1220, // Number,必选,节点位置的 x 值y: 600, // Number,必选,节点位置的 y 值width: 130, // Number,可选,节点大小的 width 值height: 30, // Number,可选,节点大小的 height 值label: "结束",type: "100", // 动作所属类型extraProperties: {IsOutSend: false},attrs: {// 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线body: {strokeWidth: 3, // 边框的粗细magnet: true // 节点是否可以连线}}}],// 边edges: [// {//   source: "node1", // String,必须,起始节点 id//   target: "node2", // String,必须,目标节点 id//   extraProperties: {//     IsOutSend: 11//   }// },// {//   source: "node1", // String,必须,起始节点 id//   target: "node3", // String,必须,目标节点 id//   extraProperties: {//     IsOutSend: 2222222222222222222//   } // String,必须,目标节点 id// }]},

解决步骤5:初始化画布

// 初始化流程图画布initGraph() {let 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: false, //是否允许在相同的起始节点和终止之间创建多条边allowLoop: false, //是否允许创建循环连线,即边的起始节点和终止节点为同一节点highlight: true, //拖动边时,是否高亮显示所有可用的节点validateEdge({ edge, type, previous }) {// 连线时设置折线edge.setRouter({name: "er"});// 设置连线样式// edge.setAttrs({//   line: {//     stroke: "#275da3",//     strokeWidth: 4//   }// });return true;}},panning: {enabled: true},mousewheel: {enabled: true // 支持滚动放大缩小},grid: {type: "mesh",size: 10, // 网格大小 10pxvisible: true, // 渲染网格背景args: {color: "#eeeeee", // 网格线/点颜色thickness: 2 // 网格线宽度/网格点大小}}});//有ID说明是编辑if (this.$route.query.id) {plantflowSet_get(this.$route.query.id).then(res => {this.name = res.data.name;this.remark = res.data.remark;var nodesArr = []; //点var edgesArr = []; //线res.data.elements.map(item => {nodesArr.push({id: item.code, // String,节点的唯一标识x: item.xCoordinate, // Number,必选,节点位置的 x 值y: item.yCoordinate, // Number,必选,节点位置的 y 值width: item.width, // Number,可选,节点大小的 width 值height: item.height, // Number,可选,节点大小的 height 值label: item.name,extraProperties: {...item.extraProperties},type: item.type, // 条件类型attrs: {// 这里给生成的节点的body加上透明的边框,一定要给边框宽度加上>0的值,否则节点将不能连线body: {fill:item.type == 20? "rgba(255, 172, 50, 0.2)": "rgba(255, 172, 50, 0)",stroke: item.type == 20 ? "#f90" : "#000",strokeWidth: 3, // 边框的粗细magnet: true // 节点是否可以连线}}});});res.data.connections.map(item => {edgesArr.push({source: item.startElementCode, // String,必须,起始节点 idtarget: item.endElementCode, // String,必须,目标节点 id...item// extraProperties: {//   IsOutSend: 11// }});});this.model.nodes = nodesArr;this.model.edges = edgesArr;this.graph.fromJSON(this.model);this.nodeAddEvent();});} else {this.graph.fromJSON(this.model);this.nodeAddEvent();}},

解决步骤6:生成节点

// 生成节点函数  0--开始节点, 10--工序节点, 20--条件节点, 100--结束节点
addHandleNode(x, y, id, name, type) {type == "20"? this.graph.addNode(Tools.tiaojianNode(x, y, id, name, type)): this.graph.addNode(Tools.gongxuNode(x, y, id, name, type));
},

解决步骤7:节点点击

//节点事件nodeAddEvent() {// 节点绑定点击事件this.graph.on("node:click", ({ e, x, y, node, view }) => {if(node.label === '开始'||node.label === '结束'){return false}// 判断是否有选中过节点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}}}]);}let isNewNode = true;if (this.curSelectNode && this.curSelectNode.id) {this.graph.toJSON().cells.map(item => {if (item.id == this.curSelectNode.id) {this.editNode = item.label;this.nodeDataForm = item.extraProperties;this.formData1 = {...this.nodeDataForm};this.formData1.StepKey = item.label;isNewNode = false;//点击的节点类型this.clickType = item.type;//点击条件if (item.type == "20") {this.$refs.tiaojianModalRef.openModules(item);}}});this.editNodeId = this.curSelectNode.id;// 如果点击是新节点if (isNewNode) {this.editNode = node.label;this.formData1.StepKey = node.label;this.nodeDataForm = node.extraProperties;//点击的节点类型this.clickType = node.type;}}});// 连线绑定悬浮事件this.graph.on("cell:mouseenter", ({ cell }) => {if (cell.shape == "edge") {cell.addTools([{name: "button-remove",label: "999999",args: {x: "100%",y: 0,offset: {x: 0,y: 0}}}]);cell.setAttrs({line: {stroke: "#409EFF"}});cell.zIndex = 99;}});//点击连接线this.graph.on("cell:click", ({ cell }) => {var newArredge = [];this.graph.toJSON().cells.map(item => {if (item.shape == "edge") {newArredge.push(item);}});if (cell.shape == "edge") {this.xianVisible = true;//遍历获取点击的线newArredge.map(item => {if ((item.source == cell.source.cell &&item.target == cell.target.cell) ||(item.source.cell == this.itemSource &&item.target.cell == this.itemTarget) ||(item.source.cell == cell.source.cell &&item.target.cell == cell.target.cell)) {this.itemSource = cell.source.cell; //点击线的起止this.itemTarget = cell.target.cell; //点击线的起止if (item.conditionExpression!=undefined && item.conditionExpression == "false"){this.clickTypeCheck = false;} else {this.clickTypeCheck = true;}}});// this.clickTypeCheck=true;}});this.graph.on("cell:mouseleave", ({ cell }) => {if (cell.shape === "edge") {cell.removeTools();cell.setAttrs({line: {stroke: "#275da3"}});cell.zIndex = 1;}});},

解决步骤8:线条编辑

//线条件编辑xianhandleOk() {var newArr = [];var newArredge = [];this.graph.toJSON().cells.map(item => {if (item.shape == "edge") {newArredge.push(item);}});newArredge.map(item => {if ((item.source == this.itemSource && item.target == this.itemTarget) ||(item.source.cell == this.itemSource &&item.target.cell == this.itemTarget)) {item.conditionExpression = this.clickTypeCheck+"";}newArr.push(item);});this.setData();this.model.edges = newArr;this.xianVisible = false;this.graph.fromJSON(this.model);},

解决步骤9:新增模块

//新增工序模块
addGXMokuai() {this.addHandleNode(500, 200, new Date().getTime(), "工序模块", "10");
},
//新增条件模块
addTJMokuai() {this.addHandleNode(500, 100, new Date().getTime(), "条件模块", "20");
},

解决步骤10:拖动节点+保存等

// 拖动节点到画布中鼠标样式变为可拖动状态dragoverDiv(ev) {ev.preventDefault();},//单节点保存 不掉接口setData() {let mapArr = this.graph.toJSON().cells;const newNodesModel = [];const newEdgesModel = [];mapArr.map(item => {if (item.shape == "rect") {newNodesModel.push({id: item.id,x: item.position.x,y: item.position.y,type: item.type,width: item.size.width,height: item.size.height,label:item.id == this.editNodeId? this.formData1.StepKey: item.attrs.text.text,extraProperties:this.editNodeId == item.id? { ...this.formData1 }: { ...item.extraProperties },attrs: item.attrs});} else {newEdgesModel.push({source: item.source,target: item.target,...item});}});this.model.nodes = newNodesModel;this.model.edges = newEdgesModel;this.graph.fromJSON(this.model);},//条件保存user_success(data) {let mapArr = this.graph.toJSON().cells;const newNodesModel = [];const newEdgesModel = [];mapArr.map(item => {if (item.shape == "rect") {if (item.id != data.id) {newNodesModel.push({id: item.id,x: item.position.x,y: item.position.y,type: item.type,width: item.size.width,height: item.size.height,label:item.id == this.editNodeId? this.formData1.StepKey: item.attrs.text.text,extraProperties:this.editNodeId == item.id? { ...this.formData1 }: { ...item.extraProperties },attrs: item.attrs});} else {newNodesModel.push(data);}} else {newEdgesModel.push({source: item.source,target: item.target,...item});}});this.model.nodes = newNodesModel;this.model.edges = newEdgesModel;this.graph.fromJSON(this.model);},//整体提交调用接口setDataOk() {if (this.name == "" || this.remark == "") {return this.$message.error("请先填写名称/备注");}const params = {factoryid: "d4882b18-47b0-ca1f-4ad3-3a10cc22976a",name: this.name,expression: "string",sort: 0,remark: this.remark,elements: [// {//   code: "string",//   type: "BeginNode",//   name: "string",//   xCoordinate: 0,//   yCoordinate: 0,//   width: 0,//   height: 0,//   textContent: "string",//   expression: "string",//   parameters: [//     {//       name: "string",//       expressionType: "Constant",//       expression: "string",//       enabled: true,//       sort: 0//     }//   ]// }],connections: [// {//   startElementCode: "string",//   endElementCode: "string",//   connectionType: 0,//   conditionExpression: "string"// }]};this.graph.toJSON().cells.map(item => {//节点if (item.shape == "rect") {params.elements.push({code: item.id.toString(),type: item.type,name: item.attrs.text.text,xCoordinate: item.position.x,yCoordinate: item.position.y,width: item.size.width,height: item.size.height,textContent: "string",expression: item.expression,extraProperties: item.extraProperties,parameters: [{name: "string",expressionType: "Constant",expression: "string",enabled: true,sort: 0}]});} else {//连线params.connections.push({startElementCode: item.source.cell.toString(),endElementCode: item.target.cell.toString(),extraProperties: item.extraProperties,// connectionType: 0,conditionExpression: item.conditionExpression?item.conditionExpression:"true",...item});}});if (this.$route.query.id) {params.id = this.$route.query.id;plantflowSet_edit(params).then(res => {if (res.success == true) {this.$message.success(res.message);} else {this.$message.error(res.message);}});} else {plantflowSet_add(params).then(res => {if (res.success == true) {this.$message.success(res.message);} else {this.$message.error(res.message);}});}},UpdateData() {this.$forceUpdate();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/590055.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习的吸烟检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;本文深入研究了基于YOLOv8/v7/v6/v5等深度学习模型的吸烟行为检测系统&#xff0c;核心采用YOLOv8并整合了YOLOv7、YOLOv6、YOLOv5算法&#xff0c;进行性能指标对比&#xff1b;详述了国内外研究现状、数据集处理、算法原理、模型构建与训练代码&#xff0c;及…

目标跟踪——行人车辆数据集

一、重要性及意义 首先&#xff0c;目标跟踪对于个人和组织的目标实现至关重要。无论是个人职业发展、企业业务增长还是政府的社会发展&#xff0c;目标跟踪都能够帮助我们明确目标&#xff0c;并将其分解为可行的步骤和时间表。这有助于我们保持动力和专注&#xff0c;提高效…

WPF文本框TextEdit不以科学计数法显示

WPF文本框TextEdit不以科学计数法显示 一个float或者double类型的数值&#xff0c;如果小数点后0的个数≥4&#xff0c;在界面上就会自动以科学计数法显示&#xff0c; 比如&#xff1a;0.00003会显示成这样 但是很多时候我并不希望它这样显示&#xff0c;因为这样不方便编辑…

js手持小风扇

文章目录 1. 演示效果2. 分析思路3. 代码实现 1. 演示效果 2. 分析思路 先编写动画&#xff0c;让风扇先转起来。使用 js 控制动画的持续时间。监听按钮的点击事件&#xff0c;在事件中修改元素的animation-duration属性。 3. 代码实现 <!DOCTYPE html> <html lang…

[计算机效率] 格式转换工具:格式工厂

3.14 格式转换工具&#xff1a;格式工厂 格式工厂是一款功能强大的多媒体格式转换软件&#xff0c;可以实现音频、视频、图片等多种格式的转换。它支持几乎所有类型的多媒体格式&#xff0c;包括视频、音频、图片、字幕等&#xff0c;可以轻松实现格式之间的转换&#xff0c;并…

Python基础之pandas:字符串操作与透视表

文章目录 一、字符串操作备注&#xff1a;如果想要全部行都能输出&#xff0c;可输入如下代码 1、字符检索2、字符转换3、字符类型判断4、字符调整5、字符对齐与填充6、字符检索7、字符切割8、字符整理 二、透视表1、pd.pivot_table2、多级透视表 一、字符串操作 备注&#xf…

Flask Python:数据库多条件查询,flask中模型关联

前言 在上一篇Flask Python:模糊查询filter和filter_by&#xff0c;数据库多条件查询中&#xff0c;已经分享了几种常用的数据库操作&#xff0c;这次就来看看模型的关联关系是怎么定义的&#xff0c;先说基础的关联哈。在分享之前&#xff0c;先分享官方文档,点击查看 从文档…

2024阿里云老用户服务器优惠价格99元和199元

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

JAX深度学习库入门

JAX简介 https://www.bilibili.com/video/BV1Sb4y1b7rK/?spm_id_from333.999.0.0&vd_sourceb2549fdee562c700f2b1f3f49065201b JAX is NumPy wiht Autograd , XLA and Composable (function) transformations, brought together for high-performance machine learning …

HarmonyOS NEXT应用开发之状态管理优秀实践

为了帮助应用程序开发人员提高其应用程序质量&#xff0c;特别是在高效的状态管理方面。本章节面向开发者提供了多个在开发ArkUI应用中常见的低效开发的场景&#xff0c;并给出了对应的解决方案。此外&#xff0c;还提供了同一场景下&#xff0c;推荐用法和不推荐用法的对比和解…

八、从0开始卷出一个新项目之瑞萨RZN2L 3.1.7 debug调试和下载

目录 3.1.7 debug调试和下载 3.1.7.1 官方介绍 3.1.7.2 e2studio debug变量实时监控 3.1.7.3 Iar debug变量实时监控 3.1.7.4 debug经验总结 八、从0开始卷出一个新项目之瑞萨RZN2L 3.1.7 debug调试和下载 3.1.7 debug调试和下载 3.1.7.1 官方介绍 官网&#xff1a; d…

MySQL执行流程

MySQL执行流程 在使用MySQL时&#xff0c;你是否有疑惑&#xff0c;当我们提交一条SQL给MySQL时它到底是如何执行的&#xff1f; 通过了解MySQL的执行流程一定能解开你的疑惑&#x1f914; 总体流程 客户端通过连接器连接MySQL查询执行缓存解析器解析SQL执行器执行SQL调用存…