使用 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.字典如何删除键、如何…

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;并且仅执行一…

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…

【雕爷学编程】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…

redis的事务、redis持久化方案、Java操作redis数据库

五、redis的事务 开启事务&#xff1a; 要等左边的提交事务&#xff0c;右边才能拿到修改后的值 本来name不能增加&#xff0c;会报错&#xff0c;但是事务中没提交不知道错 此时提交数据&#xff1a; redis事务将成功的正常提交&#xff0c;失败的才回滚&#xff0c;所以不具备…

Python简要复习

Python程序设计复习 Python基础知识 python的特点 兼具编译型和解释型特性&#xff0c;兼顾过程式、函数式和面向对象编程范式的通用编程语言 解释型语言无需像编译型需要一次性的编译成机器码&#xff0c;然后运行&#xff0c;而是由名叫解释器的程序动态的将源代码逐句转…

深度学习之反向传播

0 特别说明 0.1 学习视频源于&#xff1a;b站&#xff1a;刘二大人《PyTorch深度学习实践》 0.2 本章内容为自主学习总结内容&#xff0c;若有错误欢迎指正&#xff01; 1 forward&#xff08;前馈运算&#xff09;过程 通过输入相应的x和权重w&#xff08;可能涉及bais偏置…

docker push 报错:unauthorized: unauthorized to access repository: library/xx处理方法

rootmaster:/home/data/harbor# sudo docker login 49.0.241.2 admin Harbor12345 1.报错原因分析 rootmaster:/home/data/harbor# docker push 49.0.241.2/library/nginx:latest #这种报错 The push refers to repository [49.0.241.2/library/nginx] Get "https://49.…

UE5 C++ SplineMesh蓝图函数库实现(小白笔记)

UE5 C SplineMesh的蓝图函数库实现方法 UAAABlueprintFunctionLibrary UAAABlueprintFunctionLibrary.h // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "Components/Spline…