使用 AntV X6 + vue 实现单线流程图

使用 AntV X6 + vue 实现单线流程图

X6 是 AntV 旗下的图编辑引擎,提供了一系列开箱即用的交互组件和简单易用的节点定制能力,方便我们快速搭建 DAG 图、ER 图、流程图等应用。

在这里插入图片描述

官方文档

安装

yarn add  @antv/x6@1.34.6

Tips: 目前 X6 有 1.x 和 2.x 两个版本,因为官方文档的示例代码都是 1.x 版本的,所以本文档也是基于 1.x 版本的,如果你使用的是 2.x 版本,可以参考官方文档。

常用 API

API说明使用方法
Graph图实例const graph=new Graph()
graph.zoomTo缩放图形graph.zoomTo(0.8)
graph.centerContent图形居中graph.centerContent()
graph.getCell获取节点graph.getCell(node.id)
graph.addCell新增节点graph.addCell([node1,edge1,node2,node3])
graph.removeCells删除节点graph.removeCells(cell)
graph.createEdge创建连接线graph.createEdge(node1,node2)
graph.removeEdge删除连接线graph.removeEdge(edge.id)
graph.getNodes获取所有节点graph.getNodes()
graph.getEdges获取所有连接线graph.getEdges()
Graph.registerNod自定义元素样式可查看文档

demo 代码(以下为 vue 实现单线流程图示例)

实现效果

在这里插入图片描述

vue 代码

Tips: 示例代码需安装 dagre 和 insert-css 依赖

<template><div id="container"></div>
</template>
<script setup lang="ts">import { Graph, Cell, Node, Color, Dom } from '@antv/x6'import dagre from 'dagre'import insertCss from 'insert-css'import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue'const male ='https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ'const female ='https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*f6hhT75YjkIAAAAAAAAAAAAAARQnAQ'let graph, nodes, edges// 自定义节点,使用的是 svg格式Graph.registerNode('org-node',{width: 260,height: 88,markup: [{tagName: 'rect',attrs: {class: 'card',},},{tagName: 'image',attrs: {class: 'image',},},{tagName: 'text',attrs: {class: 'rank',},},{tagName: 'text',attrs: {class: 'name',},},{tagName: 'g',attrs: {class: 'btn add',},children: [{tagName: 'circle',attrs: {class: 'add',},},{tagName: 'text',attrs: {class: 'add',},},],},{tagName: 'g',attrs: {class: 'btn del',},children: [{tagName: 'circle',attrs: {class: 'del',},},{tagName: 'text',attrs: {class: 'del',},},],},],attrs: {'.card': {rx: 10,ry: 10,refWidth: '100%',refHeight: '100%',fill: '#5F95FF',stroke: '#5F95FF',strokeWidth: 1,pointerEvents: 'visiblePainted',},'.image': {x: 16,y: 16,width: 56,height: 56,opacity: 0.7,},'.rank': {refX: 0.95,refY: 0.5,fill: 'blue',fontFamily: 'Courier New',fontSize: 13,textAnchor: 'end',textVerticalAnchor: 'middle',},'.name': {refX: 0.95,refY: 0.7,fill: '#fff',fontFamily: 'Arial',fontSize: 14,fontWeight: '600',textAnchor: 'end',},'.btn.add': {refDx: -16,refY: 16,event: 'node:add',},'.btn.del': {refDx: -44,refY: 16,event: 'node:delete',},'.btn > circle': {r: 10,fill: 'transparent',stroke: '#fff',strokeWidth: 1,},'.btn.add > text': {fontSize: 20,fontWeight: 800,fill: '#fff',x: -5.5,y: 7,fontFamily: 'Times New Roman',text: '+',},'.btn.del > text': {fontSize: 28,fontWeight: 500,fill: '#fff',x: -4.5,y: 6,fontFamily: 'Times New Roman',text: '-',},},},true,)// 自定义边Graph.registerEdge('org-edge',{zIndex: -1,attrs: {line: {strokeWidth: 2,stroke: '#A2B1C3',sourceMarker: null,targetMarker: null,},},},true,)let i = 1// 监听自定义事件function setup() {graph.on('node:add', ({ e, node }) => {e.stopPropagation()const member = createNode('新建字段' + i, '新建字段' + i, Math.random() < 0.5 ? male : female)i++graph.freeze()const { preEdge, nextEdge, preNode, nextNode } = getPreAndNextNodeEdge(node.id)if (nextEdge) {graph.removeEdge(nextEdge.id)graph.addCell([createEdge(member, nextNode)])}graph.addCell([member, createEdge(node, member)])layout()})graph.on('node:delete', ({ e, node }) => {e.stopPropagation()graph.freeze()const { preEdge, nextEdge, preNode, nextNode } = getPreAndNextNodeEdge(node.id)if (preEdge) {graph.removeEdge(preEdge.id)}if (nextEdge) {graph.removeEdge(nextEdge.id)}if (preEdge && nextEdge) {graph.addCell([createEdge(preNode, nextNode)])}graph.removeNode(node.id)layout()})}function updateEdges() {edges = nodes.reduce((arr, node, index) => {if (index === 0) {return []}arr.push(createEdge(nodes[index - 1], node))return arr}, [])console.log('edges', edges)}function getPreAndNextNodeEdge(id: string) {let preEdge, nextEdge, preNode, nextNodeconst edges = graph.getEdges()edges.forEach(edge => {const _preId = edge.store.previous.source.cellconst _nextId = edge.store.previous.target.cellif (_preId === id) {nextEdge = edgenextNode = graph.getCell(_nextId)}if (_nextId === id) {preEdge = edgepreNode = graph.getCell(_preId)}})return { preEdge, nextEdge, preNode, nextNode }}// 自动布局function layout() {const nodes = graph.getNodes()const edges = graph.getEdges()const g = new dagre.graphlib.Graph()g.setGraph({ nodesep: 16, ranksep: 16 })g.setDefaultEdgeLabel(() => ({}))const width = 260const height = 90nodes.forEach(node => {g.setNode(node.id, { width, height })})edges.forEach(edge => {const source = edge.getSource()const target = edge.getTarget()g.setEdge(source.cell, target.cell)})dagre.layout(g)graph.freeze()g.nodes().forEach(id => {const node = graph.getCell(id) as Nodeif (node) {const pos = g.node(id)node.position(pos.x, pos.y)}})edges.forEach(edge => {const source = edge.getSourceNode()!const target = edge.getTargetNode()!const sourceBBox = source.getBBox()const targetBBox = target.getBBox()console.log(sourceBBox, targetBBox)if (sourceBBox.x !== targetBBox.x) {const gap = targetBBox.y - sourceBBox.y - sourceBBox.heightconst fix = sourceBBox.heightconst y = sourceBBox.y + fix + gap / 2edge.setVertices([{ x: sourceBBox.center.x, y },{ x: targetBBox.center.x, y },])} else {edge.setVertices([])}})graph.unfreeze()}function createNode(rank: string, name: string, image: string) {return graph.createNode({shape: 'org-node',attrs: {'.image': { xlinkHref: image },'.rank': {text: Dom.breakText(rank, { width: 160, height: 45 }),},'.name': {text: Dom.breakText(name, { width: 160, height: 45 }),},},})}function createEdge(source: Cell, target: Cell) {return graph.createEdge({shape: 'org-edge',source: { cell: source.id },target: { cell: target.id },})}onMounted(() => {// 定义样式// 我们用 insert-css 演示引入自定义样式// 推荐将样式添加到自己的样式文件中// 若拷贝官方代码,别忘了 npm install insert-cssinsertCss(`    .x6-cell {cursor: default;}.x6-node .btn {cursor: pointer;}`)// 创建画布graph = new Graph({container: document.getElementById('container')!,scroller: true,interacting: false,width: 800,height: 600,})nodes = [createNode('董事长', '审批', male),createNode(' CEO', '呵呵', female),createNode('小李', '描述', male),]updateEdges()graph.resetCells([...nodes, ...edges])layout()graph.zoomTo(0.8)graph.centerContent()setup()})onUnmounted(() => {graph.dispose()})
</script><style scoped></style>

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

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

相关文章

二叉树迭代遍历

PS:以下代码均为C实现 1.二叉树前序遍历 力扣 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 class Solution { public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> str;TreeNode* curroot;whil…

python面试题【题目+答案】

最近遇到了一份python的面试题&#xff0c;题目比较简单&#xff0c;时间控制在一个小时之内。以下是面试的题目跟答案&#xff0c;答案不代表最优解&#xff0c;只是当时所想到的一些思路&#xff0c;接下来将分享给大家。 目录 1. 给出下面打印结果 2.字典如何删除键、如何…

陕西省副高工程师职称条件

一、继续教育 申报职称&#xff0c;继续教育是首要条件&#xff0c;按照陕西省职称评审对继续教育的要求是&#xff0c;每年公需课不少于24小时&#xff0c;专业课不少于56小时。累计不少于400学时。 二、学历要求 博士学位、取得中级工程师职称资格满2年。 硕士、研究生、统招…

PySpark介绍与安装

Spark是什么 定义&#xff1a;Apache Spark是用于大规模数据&#xff08;large-scala data&#xff09;处理的统一&#xff08;unified&#xff09;分析引擎。 简单来说&#xff0c;Spark是一款分布式的计算框架&#xff0c;用于调度成百上千的服务器集群&#xff0c;计算TB、…

无涯教程-Lua - for语句函数

for 循环是一种重复控制结构&#xff0c;可让您有效地编写需要执行特定次数的循环。 for loop - 语法 Lua编程语言中 for 循环的语法如下- for init,max/min value, increment dostatement(s) end 这是 for 循环中的控制流程- 首先执行 init 步骤&#xff0c;并且仅执行一…

yolov8训练心得 持续更新

目录 优化器 lion优化器,学习率0.0001,训练效果: 学习率衰减 600个batch衰减0.7,发现效果较好

跨境电商与隐擎fox指纹浏览器:保障安全与效率的完美结合

随着全球化的发展&#xff0c;跨境电商已成为各国贸易的重要组成部分。然而&#xff0c;随之而来的风险和挑战也日益增多&#xff0c;其中之一就是关联浏览器和多开浏览器可能带来的安全隐患。为了确保跨境电商的顺利运营和数据安全&#xff0c;隐擎fox指纹浏览器作为一种防关联…

NO4 实验四:生成Web工程

1、说明 使用 mvn archetype&#xff1a;generate 命令生成 Web 工程时&#xff0c;需要使用一个专门的 archetype。这个专门生成 Web 工程骨架的 archetype 可以参照官网看到它的用法&#xff1a; 2、操作 注意&#xff1a;如果在上一个工程的目录下执行 mvn archetype&…

spring-bean配置信息重用(继承)和bean创建顺序是什么以及bean 对象的单例和多例讲解

&#x1f600;前言 本章是spring基于XML 配置bean系类中第5篇讲解spring-bean配置信息重用(继承)和bean创建顺序是什么以及bean 对象的单例和多例讲解 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希…

【多线程系列-04】深入理解java中线程间的通信机制

多线程系列整体栏目 内容链接地址【一】深入理解进程、线程和CPU之间的关系https://blog.csdn.net/zhenghuishengq/article/details/131714191【二】java创建线程的方式到底有几种&#xff1f;(详解)https://blog.csdn.net/zhenghuishengq/article/details/127968166【三】深入…

Kafka的零拷贝

传统的IO模型 如果要把磁盘中的某个文件发送到远程服务器需要经历以下几个步骤 (1) 从磁盘中读取文件的内容&#xff0c;然后拷贝到内核缓冲区 (2) CPU把内核缓冲区的数据赋值到用户空间的缓冲区 (3) 在用户程序中调用write方法&#xff0c;把用户缓冲区的数据拷贝到内核下面…

Balanced Multimodal Learning via On-the-fly Gradient Modulation

摘要 多模态学习通过整合不同的感官&#xff0c;有助于全面理解世界。因此&#xff0c;多种输入模式有望提高模型的性能&#xff0c;但我们实际上发现&#xff0c;即使多模态模型优于其单模态模型&#xff0c;它们也没有得到充分利用。具体地说&#xff0c;在本文中&#xff0…

常见的软件测试面试题汇总

一、 你们的测试流程是怎么样的&#xff1f; 答&#xff1a;1.项目开始阶段&#xff0c;BA&#xff08;需求分析师&#xff09;从用户方收集需求并将需求转化为规格说明书&#xff0c;接 下来在项目组领导会组织需求评审。 2.需求评审通过后&#xff0c;BA 会组织项目经理…

H3C交换机如何通过MAC和IP查寻对应ARP信息

环境&#xff1a; H3C S6520-26Q-SI version 7.1.070, Release 6326 问题描述&#xff1a; H3C交换机如何通过MAC 查寻对应IP信息 解决方案&#xff1a; 一、已知设备MAC地址为ac11-b134-d066 通过MAC 查寻对应IP信息 命令 dis arp | in X-X-X [H3C]dis arp | in ac11…

【雕爷学编程】MicroPython动手做(27)——物联网之掌控板小程序

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

聊聊工程化 Docker 的最新趋势以及最佳实践

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Java开发中的------修改密码+忘记密码

目录 1.修改密码 客户端响应 前端vue 后端 controller层 ServiceImpl实现层 2.忘记密码 客户端响应 后端 controller层 serviceImpl实现层 本章需要准备&#xff1a;springcloud项目&#xff0c;依赖&#xff0c;数据库.... 数据库SQL SET FOREIGN_KEY_CHECKS0;-- -…

使用langchain与你自己的数据对话(四):问答(question answering)

之前我已经完成了使用langchain与你自己的数据对话的前三篇博客&#xff0c;还没有阅读这三篇博客的朋友可以先阅读一下&#xff1a; 使用langchain与你自己的数据对话(一)&#xff1a;文档加载与切割使用langchain与你自己的数据对话(二)&#xff1a;向量存储与嵌入使用langc…

Race竞争型漏洞

目录 Race竞争介绍 实验环境配置 安装Cookiecutter 创建基于Django框架的项目 选择配置 创建数据库 加载到环境变量里 数据库的生成 创建一个超级用户&#xff08;superuser&#xff09; 启动一个本地开发服务器 配置文件 Race竞争介绍 竞争型漏洞&#xff08;Race Co…

leetcode(力扣) 剑指 Offer 12. 矩阵中的路径(回溯 DFS)

文章目录 题目描述思路分析完整代码 题目描述 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff…