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>

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

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

相关文章

代码随想录算法训练营第六十二天—图论补充

理论基础&#xff1a; 第一题、所有可能的路径 力扣题目链接 class Solution { private:vector<vector<int>> result;vector<int> path;void dfs(vector<vector<int>>& graph, int x){if(x graph.size() - 1){result.push_back(path);retu…

科技资讯|苹果Vision Pro手部追踪和手势相关新专利曝光

近日&#xff0c;美国专利商标局正式授予苹果一项与 Apple Vision Pro 主要功能相关的专利&#xff1a;手部追踪和手指手势。 苹果专利指出&#xff0c;沉浸感的质量取决于几个重要因素。例如&#xff0c;显示器的特性&#xff0c;如图像质量、帧率、像素分辨率、高动态范围 …

vue3+mapboxgl鼠标浮动显示cgcs2000

一、需求 鼠标在地图中浮动展示地图的经纬度&#xff0c;cgcs2000 xy 还有显示带号 二、实现效果 展示经度&#xff0c;纬度&#xff0c;x值&#xff0c;y值显示的是带号和y值 三、思路 3.1、mapbox获取经纬度方法 初始化地图后.on方法中有个mousemove方法 mapboxUtil._m…

2023年31个最适合博主的WordPress主题

自从我最初开始写博客以来&#xff0c;在近十年的经验中&#xff0c;我已经出于各种目的在多个博客中测试和使用了数十种不同的 WordPress 主题。 以下是我挑选的绝对最佳WordPress主题&#xff0c;专门针对不想编写一行代码的博主。 无论您是想创建个人理财博客、撰写时尚、…

[RocketMQ] Broker asyncPutMessage处理消息以及存储的高性能设计措施 (十一)

asyncPutMessage方法真正的用来存储消息。 文章目录 1.asyncPutMessage存储普通消息1.1 checkStoreStatus检查存储状态1.2 checkMessage检查消息 2.CommitLog#asyncPutMessage异步存储消息2.1 处理延迟消息2.2 获取最新mappedFile2.2.1 tryCreateMappedFile创建新的MappedFile2…

【LeetCode热题100】打卡第33天:环形链表LRU缓存

文章目录 【LeetCode热题100】打卡第33天&#xff1a;环形链表&LRU缓存⛅前言 环形链表&#x1f512;题目&#x1f511;题解 LRU缓存&#x1f512;题目&#x1f511;题解 【LeetCode热题100】打卡第33天&#xff1a;环形链表&LRU缓存 ⛅前言 大家好&#xff0c;我是知…

Vue 组件化开发

文章目录 前言组件化开发父子组件相互传数据父传子&#xff1a;自定义属性子传父&#xff1a;自定义事件父子组件互传案例 插槽 slot多个插槽 总结组件化开发总结Vue组件的基本组成子组件使用的三个步骤父子组件相互传递数据 前言 提示&#xff1a;这里可以添加本文要记录的大…

Android-jar包方式连接本地sqlite并操作返回数据

背景: 数据库的创建及字段都是后端人员维护,Android端只是映射相关数据库到本地来操作。为了统一管理操作方式方法,所以提出,后端打jar包的方式封装对Android端数据库sqllite的连接、操作。 说明: 因为之前是后端打jar包,JDBC连接的驱动及方法有差异,导致连接Android…

VMware将虚拟机网络设置为NAT模式

虚拟机有vmware和desktop&#xff0c;本人一直使用的是vmware。安装好vmware并激活后&#xff0c;创建完虚拟机。(需要vmware和激活码的可留言) 进入虚拟机设置&#xff0c;网络适配器选择NAT模式 在虚拟机工具栏->菜单栏点击编辑&#xff0c;选择“虚拟网络编辑器”。 选择…

[C语言][小游戏][猜拳游戏]

C语言的奇妙旅行 一、模块化编程二、游戏基本设计2.1 确定计算机要出的手势2.2 显示“石头剪刀布”&#xff0c;然后玩家输入自己要出的手势2.3进行输赢判断&#xff0c;显示结果2.4询问是否继续2.5 基本程序 三、游戏实现的过程3.1将玩家的手势和电脑的手势显示出来 三、总代码…

metersphere主从节点部署

metersphere主从节点关系 环境搭建 docker 环境准备 检查内存是否大于8G free -m 安装docker服务 安装docker&#xff0c;使用yum -y install docker&#xff1b; 启动docker&#xff0c;使用systemctl start docker&#xff1b; 设置开机启动&#xff0c;使用systemctl en…

基于SpringBoot的网上订餐系统【附ppt和开题|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a;前台登录&#xff1a; ①首页&#xff1a;菜品信息推荐、菜品信息展示、查看更多 ②菜品信息&#xff1a;菜品分类、菜品名称查询、食材查询、菜品详情、下单提交 ③个人中心&#xff1a;可以查看自己的信息、我的订单、我的地址 后台登录&#…