vue2 + antvx6 实现流程图功能

ops/2024/11/15 0:39:36/

导入关键包

 npm install @antv/x6 --save

npm install @antv/x6-vue-shape 

保存插件 (可选)

npm install --save @antv/x6-plugin-clipboard @antv/x6-plugin-history @antv/x6-plugin-keyboard @antv/x6-plugin-selection @antv/x6-plugin-snapline @antv/x6-plugin-stencil @antv/x6-plugin-transform insert-css

写好的组件直接导入即可

<template><div><el-container><el-aside><div id="stencil"><div><div class="dnd-circle dnd-start" @mousedown="startDrag('start',$event)"></div><span>开始</span></div><div><div class="dnd-rect" @mousedown="startDrag('rect',$event)"></div><span>节点1</span></div><div><div class="dnd-polygon" @mousedown="startDrag('polygon',$event)"></div><span>节点2</span></div><div><div class="dnd-circle" @mousedown="startDrag('end',$event)"></div><span>结束</span></div></div></el-aside><el-main><div ref="graphContainer"></div></el-main></el-container><!--  todo drawer 抽屉实现节点内容编辑  --><el-drawertitle="节点属性编辑":visible.sync="drawer":direction="direction":before-close="handleClose"><el-form :data="editNode" :inline="true"><el-form-item label="节点名称" prop="label"><el-input v-model="editNode.label"></el-input></el-form-item><el-form-item label="节点形状" prop="shape"><el-select v-model="editNode.shape"><el-option v-for="(item,index) in shapeList" :key="item.value" :label="item.label":value="item.value"></el-option></el-select></el-form-item><el-button type="primary" @click="saveNode">保存</el-button></el-form></el-drawer></div>
</template><script>
import {Graph} from '@antv/x6'
import '@antv/x6-vue-shape'
// 插件 键盘监听事件
import {Keyboard} from '@antv/x6-plugin-keyboard'
// 拖拽事件
import {Dnd} from '@antv/x6-plugin-dnd'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 {Clipboard} from '@antv/x6-plugin-clipboard'
import {History} from '@antv/x6-plugin-history'
import {register} from '@antv/x6-vue-shape'
import insertCss from 'insert-css'export default {name: 'MindMap',data () {return {graphOut: {},drawer: false,direction: 'rtl',currentNode: {},editNode: {},dnd: {},// 节点形状shapeList: [{label: '矩形',value: 'rect'}, {label: '圆形',value: 'circle'}, {label: '椭圆',value: 'ellipse'}, {label: '多边形',value: 'polygon'}, {label: '折线',value: 'polyline'}, {label: '路径',value: 'path'}, {label: '图片',value: 'image'},],// 连接桩ports: {groups: {top: {position: 'top',attrs: {circle: {magnet: true,stroke: 'black',r: 4,},},},bottom: {position: 'bottom',attrs: {circle: {magnet: true,stroke: 'black',r: 4,},},},left: {position: 'left',attrs: {circle: {magnet: true,stroke: 'black',r: 4,},},},right: {position: 'right',attrs: {circle: {magnet: true,stroke: 'black',r: 4,},},},},items: [{id: 'port_1',group: 'bottom',}, {id: 'port_2',group: 'top',}, {id: 'port_3',group: 'left',}, {id: 'port_4',group: 'right',}]}}},mounted () {this.graphOut = this.initGraph()},methods: {initGraph () {const graph = new Graph({container: this.$refs.graphContainer,// autoResize: true, // 大小自适应height: 400,width: '100%',grid: true,magnetThreshold: 'onleave',panning: {enabled: true,modifiers: 'shift',magnetThreshold: 1,// 鼠标画布移动eventTypes: ['leftMouseDown']},// 开启自动吸附connecting: {// 距离节点或者连接桩 50 px 触发自动吸附snap: true,// 是否允许连接到画布空白位置的点allowBlank: false,// 是否允许创建循环连线allowLoop: false,// 拖动边时,是否高亮显示所有可用连接桩或节点highlight: true,},modes: {default: ['drag-node']},background: {color: '#F2F7FA',},mousewheel: {// 是否开启滚轮缩放交互enabled: true,// 滚动缩放因子 默认 1.2factor: 1.2,// 是否将鼠标位置作为中心缩放、默认为truezoomAtMousePosition: true,// 按下什么键 才会缩放modifiers: ['ctrl', 'meta'],// 判断什么情况下 滚轮事件被处理// guard: false,},connector: {name: 'rounded',args: {radius: 8}}})// 支持拖拽this.dnd = new Dnd({target: graph,scaled: false,})Graph.registerNode('custom-node-width-port',{inherit: 'rect',width: 100,height: 40,attrs: {body: {stroke: '#8f8f8f',strokeWidth: 1,fill: '#fff',rx: 6,ry: 6,},},// 上下左右 四条边都有连接桩ports: this.ports},true,)Graph.registerNode('custom-circle-start',{inherit: 'circle',ports: this.ports},true,)Graph.registerNode('custom-polygon',{inherit: 'polygon',points: '0,10 10,0 20,10 10,20',ports: this.ports},true,)Graph.registerNode('custom-rect',{inherit: 'rect',ports: this.ports},true,)graph.addNode({x: 100,y: 40,width: 180,height: 30,label: '中心主题',shape: 'custom-node-width-port', // 节点形状attrs: {body: {fill: '#f5f5f5',stroke: '#333',},type: 'root'},tools: [{name: 'boundary',args: {attrs: {fill: '#16B8AA',stroke: '#2F80EB',strokeWidth: 1,fillOpacity: 0.1,},},}]})// 添加 plugin 插件graph.use(new Keyboard()) // 键盘事件.use(new Selection({enabled: true,multiple: true,rubberband: true,movable: true,showEdgeSelectionBox: true,showNodeSelectionBox: true,pointerEvents: 'none'})) // 绑定框选.use(new Snapline({enabled: true,sharp: true,})) // 对齐线.use(new Clipboard()).use(new History({enabled: true})) // 绑定撤销// 鼠标事件this.mouseEvent(graph)// 键盘时间this.keyboardEvent(graph)// 添加子节点的逻辑...return graph},addChildNode (nodeId, type) {console.log(nodeId, type)},handleClose (done) {this.$confirm('确认关闭?').then(_ => {done()}).catch(_ => {})},saveNode () {this.$confirm('确认保存?').then(_ => {console.log(this.editNode)this.currentNode['label'] = this.editNode['label']// this.currentNode['shape'] = this.editNode['shape']}).catch(_ => {})// 关闭当前 抽屉 el-drawerthis.drawer = false},startDrag (type, e) {this.startDragToGraph(this.graphOut, type, e)},startDragToGraph (graph, type, e) {const startNode = this.graphOut.createNode({shape: 'custom-circle-start',width: 38,height: 38,attrs: {body: {strokeWidth: 1,stroke: '#000000',fill: '#ffffff',rx: 10,ry: 10,},},})const polygonNode = this.graphOut.createNode({shape: 'custom-polygon',width: 80,height: 60,attrs: {body: {strokeWidth: 1,stroke: '#000000',fill: '#ffffff',rx: 10,ry: 10,},label: {fontSize: 13,fontWeight: 'bold',},},})const rectNode = this.graphOut.createNode({shape: 'custom-rect',width: 80,height: 60,attrs: {body: {strokeWidth: 1,stroke: '#000000',fill: '#ffffff',rx: 10,ry: 10,},label: {fontSize: 13,fontWeight: 'bold',},},})const endNode = this.graphOut.createNode({shape: 'custom-circle-start',width: 38,height: 38,key: 'end',attrs: {body: {strokeWidth: 4,stroke: '#000000',fill: '#ffffff',rx: 10,ry: 10,},label: {text: '结束',fontSize: 13,fontWeight: 'bold',},},})let dragNodeif (type === 'start') {dragNode = startNode} else if (type === 'end') {dragNode = endNode} else if (type === 'rect') {dragNode = rectNode} else if (type === 'polygon') {dragNode = polygonNode}console.log('dnd', dragNode, e, type)this.dnd.start(dragNode, e)},// 删除事件 节点removeNode (node) {this.graphOut.removeNode(node)},// 鼠标事件mouseEvent (graph) {// 鼠标事件// 鼠标 Hover 时添加按钮graph.on('node:mouseenter', ({node}) => {node.addTools({name: 'button',args: {x: 0,y: 0,offset: {x: 18, y: 18},// onClick({ view }) { ... },},})})// 鼠标移开时删除按钮graph.on('node:mouseleave', ({node}) => {node.removeTools() // 删除所有的工具})graph.on('node:dblclick', ({node}) => {// 添加连接桩node.addPort({group: 'top',attrs: {circle: {magnet: true,stroke: '#8f8f8f',r: 5,},},})// 编辑nodethis.currentNode = nodethis.drawer = true})graph.on('edge:mouseenter', ({cell}) => {cell.addTools([{name: 'vertices'},{name: 'button-remove',args: {distance: 20},},])})graph.on('node:click', ({node}) => {this.currentNode = node})},// 键盘事件keyboardEvent (graph) {// 键盘事件graph.bindKey('tab', (e) => {e.preventDefault()const selectedNodes = graph.getCells().filter((item) => item.isNode())console.log(selectedNodes)if (selectedNodes.length) {const node = selectedNodes[0]const type = node.attrs['type']this.addChildNode(node.id, type)}})graph.bindKey('delete', (e) => {this.removeNode(this.currentNode)})graph.bindKey('backspace', (e) => {this.removeNode(this.currentNode)})},},watch: {// currentNode: {//   handler (nwVal, old) {//   },//   immediate: true,//   deep: true// }}
}
</script><style>
/* 样式调整 */
#stencil {width: 100px;height: 100%;position: relative;display: flex;flex-direction: column;align-items: center;border-right: 1px solid #dfe3e8;text-align: center;font-size: 12px;
}.dnd-rect {width: 50px;height: 30px;line-height: 40px;text-align: center;border: 2px solid #000000;border-radius: 6px;cursor: move;font-size: 12px;margin-top: 30px;
}.dnd-polygon {width: 35px;height: 35px;border: 2px solid #000000;transform: rotate(45deg);cursor: move;font-size: 12px;margin-top: 30px;margin-bottom: 10px;
}.dnd-circle {width: 35px;height: 35px;line-height: 45px;text-align: center;border: 5px solid #000000;border-radius: 100%;cursor: move;font-size: 12px;margin-top: 30px;
}.dnd-start {border: 2px solid #000000;
}.x6-widget-stencil {background-color: #f8f9fb;
}.x6-widget-stencil-title {background: #eee;font-size: 1rem;
}.x6-widget-stencil-group-title {font-size: 1rem !important;background-color: #fff !important;height: 40px !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;
}</style>


http://www.ppmy.cn/ops/31094.html

相关文章

QT创造一个新的类(柱状图的类),并关联属性和方法

1.以在UI上添加柱状图的类为例&#xff08;Histogram&#xff09; #ifndef STUDY_HISTOGRAM_H #define STUDY_HISTOGRAM_H#include <QVector> #include <QWidget>// 前向声明 QT_BEGIN_NAMESPACE class QColor; class QRect; class QString; class QPaintDevice; …

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统 系统功能 首页 图片轮播 宾馆信息 饮食美食 休闲娱乐 新闻资讯 论坛 留言板 登录注册 个人中心 后台管理 登录注册 个人中心 用户管理 客房登记管理 客房调整管理 休闲娱乐管理 类型信息管理 论坛管理 系统管理 新闻资讯…

如何Vue.js 结合 Element UI 进行表单验证

Vue.js 结合 Element UI 进行表单验证是一个常见的做法。Element UI 提供了一套丰富的表单组件&#xff0c;并内置了表单验证功能。以下是一个简单的示例&#xff0c;展示如何使用 Vue 和 Element UI 进行表单验证&#xff1a; 首先&#xff0c;确保你已经安装了 Vue 和 Eleme…

华为机考入门python3--(20)牛客20- 密码验证合格程序

分类&#xff1a;字符串 知识点&#xff1a; 遍历字符串的每个字符 for char in my_str: 可以直接比较字符范围 a < char < z 列表统计元素个数 my_list.count(elem) 寻找子串 my_str.find(sub_str) 题目来自【牛客】 import re import sysdef check_…

在M1芯片安装鸿蒙闪退解决方法

在M1芯片安装鸿蒙闪退解决方法 前言下载鸿蒙系统安装完成后&#xff0c;在M1 Macos14上打开闪退解决办法接下来就是按照提示一步一步安装。 前言 重新安装macos系统后&#xff0c;再次下载鸿蒙开发软件&#xff0c;竟然发现打不开。 下载鸿蒙系统 下载地址&#xff1a;http…

MLP手写数字识别(1)-MNIST数据集下载与可视化(tensorflow)

1.下载与查看MNIST数据集 from keras.datasets import mnist(x_train_image,y_train_label),(x_test_image,y_test_label) mnist.load_data() print("train images:",x_train_image.shape) print("test images:",x_test_image.shape) print("train …

Android 学习 鸿蒙HarmonyOS 4.0 第四章(TS中的条件判断语句)

PS&#xff1a;在有关TS的博客中呢&#xff0c;我想声明一点&#xff0c;如果是零基础没有开发经验的小伙伴&#xff0c;直接学鸿蒙会有些吃力&#xff0c;可以先学一下TS&#xff0c;比较好入手一些&#xff0c;鸿蒙主推的开发语音是ArkTS&#xff0c;是TS的超集&#xff0c;先…

论文笔记(四十五)Attention Is All You Need

Attention Is All You Need 文章概括摘要1. 介绍2. 背景3. 模型架构3.1 编码器和解码器堆栈3.2 Attention3.2.1 按比例点积Attention3.2.2 Multi-Head Attention3.2.3 注意力在模型中的应用 3.3 定位前馈网络3.4 嵌入与 Softmax3.5 位置编码 4 为什么 Self-Attention5. Trainin…