当前位置: 首页 > news >正文

vue3+vite+Ts 基于Antv/x6 绘制流程图

需求效果:

 

 

需求:

实现一个流程图,双击可对相应的组件进行一些功能操作;

工具栈:

这里使用@antv/x6, 基于vue3+vite+ts进行开发

官网地址:

 https://x6.antv.antgroup.com/examples/showcase/practices/#flowchart

代码:

<template><div id="container"><router-view /></div>
</template><script lang="ts" setup>
import { Graph, Shape } from '@antv/x6'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'
import insertCss from 'insert-css'import { useRouter } from "vue-router"// 引入本地图片
const getImageUrl = (url: any) => {return new URL(url, import.meta.url).href;
}const router = useRouter()onMounted(() => {// 为了协助代码演示preWork()// #region 初始化画布const graph = new Graph({container: document.getElementById('graph-container')!,grid: true,mousewheel: {enabled: true,zoomAtMousePosition: true,modifiers: 'ctrl',minScale: 0.5,maxScale: 3,},connecting: {router: 'manhattan',connector: {name: 'rounded',args: {radius: 8,},},anchor: 'left',connectionPoint: 'anchor',allowBlank: false,snap: {radius: 20,},createEdge() {return new Shape.Edge({attrs: {line: {stroke: '#A2B1C3',strokeWidth: 2,targetMarker: {name: 'block',width: 12,height: 8,},},},zIndex: 0,//....})},validateConnection({ targetMagnet }) {return !!targetMagnet},},highlighting: {magnetAdsorbed: {name: 'stroke',args: {attrs: {fill: '#5F95FF',stroke: '#5F95FF',},},},},})// #endregion// #region 使用插件graph.use(new Transform({resizing: true,rotating: true,}),).use(new Selection({rubberband: true,showNodeSelectionBox: true,}),).use(new Snapline()).use(new Keyboard()).use(new Clipboard()).use(new History())// #endregion// #region 初始化 stencilconst stencil = new Stencil({title: '流程图',target: graph,stencilGraphWidth: 300,stencilGraphHeight: 180,collapsable: true,groups: [{title: '输入',name: 'group2',graphHeight: 300,layoutOptions: {rowHeight: 70,},},{title: '输出',name: 'group3',graphHeight: 0,layoutOptions: {rowHeight: 70,},},{title: '转换组件',name: 'group1',graphHeight: 300,layoutOptions: {rowHeight: 70,},},],layoutOptions: {columns: 2,columnWidth: 80,rowHeight: 55,},})document.getElementById('stencil')!.appendChild(stencil.container)// #endregion// #region 快捷键与事件graph.bindKey(['meta+c', 'ctrl+c'], () => {const cells = graph.getSelectedCells()if (cells.length) {graph.copy(cells)}return false})graph.bindKey(['meta+x', 'ctrl+x'], () => {const cells = graph.getSelectedCells()if (cells.length) {graph.cut(cells)}return false})graph.bindKey(['meta+v', 'ctrl+v'], () => {if (!graph.isClipboardEmpty()) {const cells = graph.paste({ offset: 32 })graph.cleanSelection()graph.select(cells)}return false})// undo redograph.bindKey(['meta+z', 'ctrl+z'], () => {if (graph.canUndo()) {graph.undo()}return false})graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {if (graph.canRedo()) {graph.redo()}return false})// select allgraph.bindKey(['meta+a', 'ctrl+a'], () => {const nodes = graph.getNodes()if (nodes) {graph.select(nodes)}})// deletegraph.bindKey('backspace', () => {const cells = graph.getSelectedCells()if (cells.length) {graph.removeCells(cells)}})// zoomgraph.bindKey(['ctrl+1', 'meta+1'], () => {const zoom = graph.zoom()if (zoom < 1.5) {graph.zoom(0.1)}})graph.bindKey(['ctrl+2', 'meta+2'], () => {const zoom = graph.zoom()if (zoom > 0.5) {graph.zoom(-0.1)}})// 控制连接桩显示/隐藏const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {for (let i = 0, len = ports.length; i < len; i += 1) {ports[i].style.visibility = show ? 'visible' : 'hidden'}}graph.on('node:mouseenter', () => {const container = document.getElementById('graph-container')!const ports = container.querySelectorAll('.x6-port-body',) as NodeListOf<SVGElement>showPorts(ports, true)})graph.on('node:mouseleave', () => {const container = document.getElementById('graph-container')!const ports = container.querySelectorAll('.x6-port-body',) as NodeListOf<SVGElement>showPorts(ports, false)})// #endregion// #region 初始化图形const ports = {groups: {top: {position: 'top',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},right: {position: 'right',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},bottom: {position: 'bottom',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},left: {position: 'left',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},},items: [{group: 'top',},{group: 'right',},{group: 'bottom',},{group: 'left',},],}Graph.registerNode('custom-rect',{inherit: 'rect',width: 66,height: 36,attrs: {body: {strokeWidth: 1,stroke: '#5F95FF',fill: '#EFF4FF',},text: {fontSize: 12,fill: '#262626',},},ports: { ...ports },},true,)Graph.registerNode('custom-polygon',{inherit: 'polygon',width: 66,height: 36,attrs: {body: {strokeWidth: 1,stroke: '#5F95FF',fill: '#EFF4FF',},text: {fontSize: 12,fill: '#262626',},},ports: {...ports,items: [{group: 'top',},{group: 'bottom',},],},},true,)Graph.registerNode('custom-circle',{inherit: 'circle',width: 45,height: 45,attrs: {body: {strokeWidth: 1,stroke: '#5F95FF',fill: '#EFF4FF',},text: {fontSize: 12,fill: '#262626',},},ports: { ...ports },},true,)Graph.registerNode('custom-image',{inherit: 'rect',width: 65,height: 60,markup: [{tagName: 'rect',selector: 'body',},{tagName: 'image',},{tagName: 'text',selector: 'label',},],attrs: {body: {stroke: '#ccc',fill: '#ccc', //..},image: {width: 28,height: 28,refX: 20,refY: 12,},label: {refX: 1,refY: 48,textAnchor: 'bottom',textVerticalAnchor: 'top',fontSize: 12,fill: '#fff',},},ports: {groups: {top: {position: 'top',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},right: {position: 'right',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},bottom: {position: 'bottom',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},left: {position: 'left',attrs: {circle: {r: 4,magnet: true,stroke: '#5F95FF',strokeWidth: 1,fill: '#fff',style: {visibility: 'hidden',},},},},},},},true,)//转换组件const convertDataList = [{label: '添加默认值',path: "addDefault",image: getImageUrl("../../assets/tool_image/information_add.svg"),},{label: '基本运算',path: "basicoPerations",image:getImageUrl("../../assets/tool_image/calculator.svg"),},{label: '脚本转换',path: "conversionScript",image:getImageUrl("../../assets/tool_image/script.svg"),},{label: '合并/拆分',path: "mergeSplit",image:getImageUrl("../../assets/tool_image/merge.svg"),},{label: '数字类型',path: "numberType",image:getImageUrl("../../assets/tool_image/script_1.svg"),},{label: '简单过滤',path: "simpleFiltering",image:getImageUrl("../../assets/tool_image/filter-records-fill.svg"),},{label: '时间格式',path: "timeConversion",image:getImageUrl("../../assets/tool_image/Date_time.svg"),},]const convertNodes = convertDataList.map((item) =>graph.createNode({shape: 'custom-image',label: item.label,data: item.path,attrs: {image: {'xlink:href': item.image,}},ports: {items: [{group: 'right',},{group: 'left',},],}}),graph.on('node:dblclick', ({ cell }) => { // cell 基类对象 view 视图对象// 目标数据logicrouter.push({name: cell.data,query: {}})}))stencil.load(convertNodes, 'group1')//endconst imageShapes = [{label: 'Excel',path: "Excel",image:getImageUrl("../../assets/tool_image/file-excel.svg"),},{label: 'CSV',path: "CSV",image:getImageUrl("../../assets/tool_image/CSV.svg"),},{label: 'JSON',path: "JSON",image:getImageUrl("../../assets/tool_image/json_1.svg"),},{label: 'Kafka',path: "Kafka",image:getImageUrl("../../assets/tool_image/Kafka_1.svg"),},{label: 'OWL文件',path: "OWL",image:getImageUrl("../../assets/tool_image/calculator_1.svg"),},{label: '日志文件',path: "Log",image:getImageUrl("../../assets/tool_image/console2.svg"),},{label: 'mongodb',path: "mongodb",image:getImageUrl("../../assets/tool_image/yunshujukuMongoDB.svg"),},{label: '表输入',path: "outside",image:getImageUrl("../../assets/tool_image/database.svg"),},]const imageNodes = imageShapes.map((item) =>graph.createNode({shape: 'custom-image',label: item.label,data: item.path,attrs: {image: {'xlink:href': item.image,},},ports: {items: [{group: 'right',},],}}),graph.on('node:dblclick', ({ cell }) => { // cell 基类对象 view 视图对象// 目标数据logicconsole.log(cell.data, 'aaa')router.push({name: cell.data,query: {}})}))stencil.load(imageNodes, 'group2')//outputconst outputDataList = [{label: '控制台',path: "consoleoutput",image:getImageUrl("../../assets/tool_image/console.svg"),},{label: 'Kafka',path: "kafkaoutput",image:getImageUrl("../../assets/tool_image/Kafka.svg"),},{label: 'mongodb',path: "mongodboutput",image:getImageUrl("../../assets/tool_image/mongo.svg"),},{label: '表',path: "tableOut",image:getImageUrl("../../assets/tool_image/database.svg"),}]const outputNodes = outputDataList.map((item) =>graph.createNode({shape: 'custom-image',label: item.label,data: item.path,attrs: {image: {'xlink:href': item.image,},},ports: {items: [{group: 'left',},],}}),graph.on('node:dblclick', ({ cell }) => { // cell 基类对象 view 视图对象// 目标数据logicconsole.log(cell.data, 'aaa')router.push({name: cell.data,query: {}})}))stencil.load(outputNodes, 'group3')// #endregionfunction preWork() {// 这里协助演示的代码,在实际项目中根据实际情况进行调整const container = document.getElementById('container')!const stencilContainer = document.createElement('div')stencilContainer.id = 'stencil'const graphContainer = document.createElement('div')graphContainer.id = 'graph-container'container.appendChild(stencilContainer)container.appendChild(graphContainer)insertCss(`#container {display: flex;border: 1px solid #dfe3e8;}#stencil {width: 200px;height: 100%;position: relative;border-right: 1px solid #dfe3e8;}#graph-container {width: calc(100% - 180px);height: 100%;}.x6-widget-stencil  {background-color: #fff;}.x6-widget-stencil-title {background-color: #fff;}.x6-widget-stencil-group-title {background-color: #fff !important;}.x6-widget-transform {margin: -1px 0 0 -1px;padding: 0px;border: 1px solid #239edd;}.x6-widget-transform > div {border: 1px solid #239edd;}.x6-widget-transform > div:hover {background-color: #3dafe4;}.x6-widget-transform-active-handle {background-color: #3dafe4;}.x6-widget-transform-resize {border-radius: 0;}.x6-widget-selection-inner {border: 1px solid #239edd;}.x6-widget-selection-box {opacity: 0;}`)}
})</script><style scoped lang="less">
#container {width: 100%;height: 100vh;overflow: hidden !important;display: flex;justify-content: center;
}
</style>

相关文章:

vue3+vite+Ts 基于Antv/x6 绘制流程图

需求效果&#xff1a; 需求&#xff1a; 实现一个流程图&#xff0c;双击可对相应的组件进行一些功能操作&#xff1b; 工具栈&#xff1a; 这里使用antv/x6&#xff0c; 基于vue3vitets进行开发 官网地址&#xff1a; https://x6.antv.antgroup.com/examples/showcase/pra…...

sys V 进程间通信之消息队列

note msgget获取内核消息队列实例 msgctl可以删除内核消息队列实例 msgsnd\msgrcv函数注意struct msgbuf字段的填充 code #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include &l…...

Android 报错,闪退(错误)日志保存到手机内存中,以文本文件的形式保存

1.直接贴代码 import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Environment; import android.util.Log;import com.nuotu.atmBookClient.App;import java.io.File; i…...

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel 在之前实现了flutter聊天界面的自定义表情的展示&#xff0c;这里记录一下更多操作展开的相机、相册等操作功能实现。 一、查看效果 更多操作展开的相机、相册等操作功能实现。 二、代码实现 展开的操作按钮可能比…...

浅析泵站自动化技术的发展趋势

摘要&#xff1a;基于泵站对我国水利及水务事业的重要性&#xff0c;文章以城市供水行业大型泵站为对象&#xff0c;分析了泵站自动化技术 发展现状&#xff0c;结合泵站自动化技术的发展需求&#xff0c;从管控一体化、系统自诊断、运行信息实时化管理等方面展望了泵 站自动化…...

5.4.1 虚拟专用网VPN

5.4.1 虚拟专用网VPN 我们已经学习了因特网的路由协议&#xff08;5.3.1 因特网的路由协议&#xff08;一&#xff09;、5.3.2 因特网的路由协议&#xff08;二&#xff09;基于距离向量算法的RIP协议、5.3.3 因特网的路由协议&#xff08;三&#xff09;OSPF协议、5.3.4 因特…...

第42节:cesium 火焰效果(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><!-- :shouldAnimate="true" 添加动画 --><vc-viewer @ready...

MySQL基础篇第5章(排序与分页)

文章目录 1、排序1.1 排序规则1.2 单列排序1.3 多列排序 2、分页2.1 背景2.2 实现规则2.3 拓展 1、排序 1.1 排序规则 使用 ORDER BY 子句排序 ASC&#xff08;ascend&#xff09;: 升序DESC&#xff08;descend&#xff09;:降序 ORDER BY 子句在SELECT语句的结尾。 1.2 …...

​LeetCode解法汇总2679. 矩阵中的和

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。一开始你的分数为 0 。你需要执行…...

flask-apscheduler实现定时任务

秋风阁-北溪入江流 flask-apscheduler是一个支持apscheduler的flask插件&#xff0c;通过flask-apscheduler可以很方便的定义定时任务。 安装flask-apscheduler pip install flask-apschedulerflask-apscheduler组件 apscheduler库包含有组件&#xff1a; triggers&#xf…...

FPGA纯verilog实现UDP协议栈,sgmii接口SFP光口收发,提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、该UDP协议栈性能4、详细设计方案SFPGMII AXIS接口模块AXIS FIFOUDP协议栈1G/2.5G Ethernet PCS/PMA or SGMII 5、vivado工程详解6、上板调试验证并演示准备工作查看ARPUDP数据回环测试 7、福利&#xff1a;工程代码的获取 1、前言 目前网…...

【Python入门系列】第十五篇:Python数据可视化和图表绘制

文章目录 前言一、可视化与绘图常用库二、Matplotlib1、折线图2、散点图3、柱状图&#xff1a; 三、Seaborn1、散点图2、箱线图3、小提琴图4、热力图 四、Plotly1、折线图2、散点图3、条形图 总结 前言 数据可视化是数据分析和数据科学中非常重要的一部分。通过可视化&#xf…...

isBlank函数和isEmpty函数的区别

StrUtil.isBlank(CharSequence)&#xff1a;该方法用于判断字符串是否为空或仅包含空白字符。如果传入的字符串为null、空字符串(“”)或仅包含空白字符&#xff08;如空格、制表符、换行符等&#xff09;&#xff0c;则返回true&#xff1b;否则返回false。 StrUtil.isEmpty(…...

「SQL面试题库」 No_121 The Most Recent Three Orders

&#x1f345; 1、专栏介绍 「SQL面试题库」是由 不是西红柿 发起&#xff0c;全员免费参与的SQL学习活动。我每天发布1道SQL面试真题&#xff0c;从简单到困难&#xff0c;涵盖所有SQL知识点&#xff0c;我敢保证只要做完这100道题&#xff0c;不仅能轻松搞定面试&#xff0…...

【计算机视觉 | 目标检测 | 图像分割】arxiv 计算机视觉关于目标检测和图像分割的学术速递(7 月 7 日论文合集)

文章目录 一、检测相关(5篇)1.1 Contextual Affinity Distillation for Image Anomaly Detection1.2 Noise-to-Norm Reconstruction for Industrial Anomaly Detection and Localization1.3 MMNet: Multi-Collaboration and Multi-Supervision Network for Sequential Deepfake…...

直流运算放大器-----仪表放大器(三)

详见 模拟电子技术基础 6.4.1 电路图 计算公式 仿真 电流流向...

【Zookeeper】终端操作常用命令

文章目录 服务端常用命令客户端常用命令 zookeeper版本3.7.1 Zookeeper是一个开源的分布式协调服务。 Zookeeper是Apache软件基金会的一个项目&#xff0c;它提供了分布式应用程序协调的通用服务&#xff0c;如分布式同步、命名服务、集群维护等&#xff0c;以简化分布式应用协…...

leetcode 1110. 删点成林

给出二叉树的根节点 root&#xff0c;树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现&#xff0c;我们就把该节点从树上删去&#xff0c;最后得到一个森林&#xff08;一些不相交的树构成的集合&#xff09;。 返回森林中的每棵树。你可以按任意顺序组织答案…...

华为Harmony应用开发初探

HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体…...

电脑应用程序发生异常怎么办?

有时候我们打开电脑上面的某个软件时&#xff0c;会打不开&#xff0c;并且会弹出如下的错误提示“应用程序发生异常 未知的软件异常&#xff08;&#xff58;&#xff58;&#xff58;&#xff09;&#xff0c;位置为&#xff58;&#xff58;”。相信大多数的人在使用电脑的时…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...