antv-g6—在vue项目中实现网格拓扑流程图自定义绘制

news/2024/10/17 23:31:11/

实现效果图

在这里插入图片描述

这个是自己写着玩的,利用@antv/g6自定义绘制流程图,然后保存到localstorage中,在左侧表格展示,还可以通过表格操作来查看对应的流程图以及删除;

这里特别注意一下,@antv/g6版本是1.2.8,vue版本是2.5.x;

下面我会把实现代码全部粘贴出来,不需要需改,开袋即食,放到你的项目中直接可以展示;

代码中我也会加上注释,不懂的可以看注释;

流程图组件

flow.vue

<template><div id="flowChart"><!-- 头部工具栏 --><div class="operating"><div class="btn-group"><div class="btn" @click="addCircle" title="开始节点"><i class="iconfont icon-weixuanzhongyuanquan"></i></div><div class="btn" @click="addRect" title="普通节点"><i class="iconfont icon-gl-square"></i></div><div class="btn" @click="addRhombus" title="条件节点"><i class="iconfont icon-tubiao"></i></div></div><div class="btn-group"><div class="btn" @click="addLine" title="直线"><i class="iconfont icon-line"></i></div><div class="btn" @click="addSmooth" title="曲线"><i class="iconfont icon-byangtiaoquxian"></i></div><div class="btn" @click="addArrowLine" title="箭头直线"><i class="iconfont icon-gl-arrowRd"></i></div><div class="btn" @click="addArrowSmooth" title="箭头曲线"><i class="iconfont icon-a-18"></i></div></div><div class="btn-group"><div class="btn" @click="changeMode('edit')" title="选择模式"><i class="iconfont icon-xuanze"></i></div><div class="btn" @click="changeMode('drag')" title="拖拽模式"><i class="iconfont icon-tuozhuai"></i></div></div><div class="btn-group"><div class="btn" @click="del" style="margin-top: 5px;" title="删除"><i class="el-icon-delete"></i></div><div class="btn" @click="save" title="保存"><i class="iconfont icon-baocun"></i></div></div><div class="btn-group"><el-input size="mini" v-model="workflowName" placeholder="请输入流图名称..."></el-input></div></div><!-- 右侧节点属性设置 --><div class="info"><div class="title"><span>{{infoTitle}}属性</span></div><div class="content"><el-checkbox v-if="isBlank === true" v-model="checked">网格对齐</el-checkbox><el-form v-else label-position="left" label-width="60px"><el-form-item v-if="isNode !== true" label="动作"><el-select v-model="action" size="mini" filterable placeholder="绑定动作" value=""><el-optionv-for="item in actionList":key="item.id":label="item.label":value="item.id"></el-option></el-select></el-form-item>   <!-- 线--><el-form-item v-if="isNode === true" label="名称"><el-input size="mini" v-model="name"></el-input></el-form-item><!-- <el-form-item v-if="isNode === true" label="类型"><el-select v-model="nodeType" size="mini" filterable placeholder="请选择类型" value=""><el-optionv-for="item in nodeTypeList":key="item.id":label="item.label":value="item.id"></el-option></el-select></el-form-item> --><el-form-item label="颜色"><el-color-picker v-model="color"></el-color-picker></el-form-item></el-form></div></div></div></template><script>import G6 from '@antv/g6';export default {mounted() {this.initG6();},props: {actionList: {type: Array, default: []},nodeTypeList: {type: Array, default: () => {return [{id: '001', label: '普通节点'},{id: '002', label: '开始节点'},]}}},data() {return {action: '',name: '',nodeType: 0,color: '',net: '',Util: '',workflowName: '',activation: '', //当前激活的节点isNode: false, //当前是节点isBlank: true,   //当前是空白区checked: true,  //网格对齐infoTitle: '画布',//属性标题oldColor: '',    //获取节点本身颜色type: '',        //有值为编辑状态}},methods: {//初始化initG6() {let self = this;self.Util = G6.Util;let grid;if (self.checked) {grid = {forceAlign: true, // 是否支持网格对齐cell: 25,         // 网格大小};} else {grid = null;}self.net = new G6.Net({id: 'flowChart',      // 容器IDmode: 'edit',grid: grid,/*width: 500,    // 画布宽*/height: 800    // 画布高});/***点击空白处*/self.net.on('click', (ev) => {if (!self.Util.isNull(ev.item)) {self.isBlank = false} else {self.isBlank = true;self.infoTitle = '画布'}});/***点击节点*/self.net.on('itemclick', function (ev) {self.isNode = self.Util.isNode(ev.item);   //是否为Nodeself.activation = ev.item;if (self.isNode) {/* 激活节点后节点名称input聚焦*/self.$nextTick(()=>{self.$refs.inputFocus.$el.querySelector('input').focus();});self.infoTitle = '节点';self.name = ev.item.get('model').label;self.nodeType = ev.item.get('model').nodeType;} else {self.infoTitle = '边';self.action = ev.item.get('model').action;}self.color = self.oldColor;});/*** 鼠标移入移出事件改变颜色*/self.net.on('itemmouseenter', ev => {const item = ev.item;self.oldColor = item.get('model').color;     //获取节点颜色self.net.update(item, {color: '#108EE9',});self.net.refresh();});self.net.on('itemmouseleave', ev => {const item = ev.item;self.net.update(item, {color: self.oldColor});self.net.refresh();});/*self.net.source(self.nodes, self.edges);*/  //加载资源数据self.net.render();},//添加起始节点addCircle() {this.net.beginAdd('node', {shape: 'circle',nodeType: 0})},//添加常规节点addRect() {this.net.beginAdd('node', {shape: 'rect',nodeType: 0})},//添加条件节点addRhombus() {this.net.beginAdd('node', {shape: 'rhombus',nodeType: 0})}, //添加直线addLine() {this.net.beginAdd('edge', {shape: 'line'});}, //添加曲线addSmooth() {this.net.beginAdd('edge', {shape: 'smooth'})}, //添加箭头曲线addArrowSmooth() {this.net.beginAdd('edge', {shape: 'smoothArrow'})}, //添加箭头直线addArrowLine() {this.net.beginAdd('edge', {shape: 'arrow'});}, //添加折线addPolyLine() {this.net.beginAdd('edge', {shape: 'polyLineFlow'});}, //拖拽与编辑模式的切换changeMode(mode) {this.net.changeMode(mode)}, //删除节点del() {this.net.del()},//保存流程图save() {/* 验证流图名称*/if (this.workflowName !== '') {let data = this.net.save();if (data.source.nodes.length === 0) {this.$message({type: 'error', message: '流图内容不能为空'});return false}/* 验证节点名称*/for (let item of data.source.nodes) {if (item.label === '' || item.label === null || item.label === undefined) {this.$message({type: 'error', message: '节点名称不能为空'});return false}}data.source['name'] = this.workflowName;/*let json = JSON.stringify(data, null, 2);*/this.$emit('saveData', data.source, this.type);} else {this.$message({type: 'error', message: '流图名称不能为空'})}/*console.log(saveData, json);*/},//更新节点update() {if (this.activation.get('type') === 'node') {this.net.update(this.activation, {label: this.name,nodeType: this.nodeType,color: this.color});} else {/* 根据ID取出label*/let label = this.actionList.map(item => {if (item.id === this.action) {return item.label}}).join('');this.net.update(this.activation, {label: label,color: this.color,action: this.action});}},//清空视图,重置画布clearView() {this.type = '';this.workflowName = '';this.net.changeData()},//渲染流程数据source(nodes, edges, name, type) {this.type = type;this.workflowName = name;this.net.changeData(nodes, edges)},  },watch: {/*** 监听输入框*/action: function () {this.update()},name: function () {this.update()},nodeType: function () {this.update()},color: function () {this.update()},/*** 网格切换*/checked: function () {let _saveData = this.net.save();this.net.destroy();  //销毁画布this.initG6();this.net.read(_saveData);this.net.render()}}}</script><style  lang="less" scoped>#flowChart {border: 1px solid #cdcdcd;border-radius: 5px;position: relative;overflow: hidden;width: 80%;box-sizing: border-box;height: 100%;}.operating {position: absolute;z-index: 99;background-color: #ffffff;padding: 20px 10px;box-shadow: 1px 1px 4px 0 #0a0a0a2e;}.info {position: absolute;height: 100%;right: 0;z-index: 99;box-shadow: 1px 1px 4px 0 #0a0a0a2e;.title {height: 40px;padding-left: 10px;border-top: 1px solid #DCE3E8;border-bottom: 1px solid #DCE3E8;border-left: 1px solid #DCE3E8;background: rgb(235, 238, 242);line-height: 40px;span {font-size: 14px;}}.content {background: rgba(247, 249, 251, 0.45);width: 220px;height: 800px;border-left: 1px solid #E6E9ED;padding: 10px;}}.btn-group {border-right: 1px solid #efefef;display: inline-block;padding-left: 10px;padding-right: 14px;&:last-of-type {border-right: 0;}.btn {display: inline-block;margin: 2px;width: 30px;height: 30px;line-height: 30px;text-align: center;cursor: pointer;border: 1px solid rgba(233, 233, 233, 0);i {font-size: 20px;}&:hover {border: 1px solid #E9E9E9;color: #767A85;border-radius: 2px;background: #FAFAFE;}}.el-form-item {margin-bottom: 0 !important;}}</style>

使用流程组件

<template><div class="flow_content"><div class="table_content"><el-button size="small" type="primary" style="margin: 10px 0;" @click="newAdd">新建流程</el-button>. <el-table:data="tableData"borderhighlight-current-row=truestyle="width: 100%"><el-table-columnprop="name"align="center"label="名称"></el-table-column><el-table-columnlabel="操作"align="center"width="100"><template slot-scope="scope"><el-button type="text" size="small"@click.native.prevent="viewFlow(scope.row)">查看</el-button><el-button type="text" size="small"@click.native.prevent="deleteRow(scope.$index, scope.row)">移除</el-button></template></el-table-column></el-table></div><flowChartref="flow":actionList="actionList"@saveData="saveData"></flowChart></div></template><script>import flowChart from './components/flow.vue'import { v4 as uuidv4 } from "uuid";export default {data(){return {actionList:[{id:'001',label:'拒绝'},{id:'002',label:'通过'},{id:'003',label:'下发'}],tableData:[],clickName:"",//当前点击渲染的流程图}},components:{flowChart},mounted(){//初始化获取列表数据,如果有数据,画布就展示第一个流程,如果没有数据就为空集合var tables = localStorage.getItem('flowTable')if(tables){this.tableData = JSON.parse(tables)const {nodes, edges, name, type} = this.tableData[0]this.$refs.flow.source(nodes, edges, name, type)}else{this.tableData = []}},methods:{saveData(source,type){var isHave = falsevar indexNum var filterTableData = this.tableData.filter( item => {return item.type !== type})filterTableData.forEach( (item,index) => {if(item.name == source.name){isHave = trueindexNum = index}})if(type){//type有值,编辑if(isHave){//编辑的名称已存在this.$message({message: '该名称已存在!',type: 'warning'});}else{var obj = sourceobj.type = typethis.tableData.splice(indexNum, 1,obj);this.$message({message: '保存成功!',type: 'success'});}}else{if(!isHave){//type无值,新建let uid = uuidv4()var obj = sourceobj.type = uidthis.tableData.push(source)this.$message({message: '保存成功!',type: 'success'});}else{this.$message({message: '该名称已存在!',type: 'warning'});}}var tables = JSON.stringify(this.tableData)localStorage.setItem('flowTable',tables)},//点击查看流程图viewFlow(row){this.clickName = row.namethis.$refs.flow.clearView()const {nodes, edges, name, type} = rowthis.$refs.flow.source(nodes, edges, name, type)},//新建流程图,清空画布newAdd(){this.$refs.flow.clearView()},//删除单个列表并清空当前删除的画布deleteRow(index, row) {var leng = this.tableData.lengthif(this.clickName == row.name || index == leng -1 || leng == 0){this.$refs.flow.clearView()}this.tableData.splice(index, 1);var tables = JSON.stringify(this.tableData)localStorage.setItem('flowTable',tables)}}}</script><style  lang="less" scoped>.flow_content{height: 100%;display: flex;justify-content: space-around;.table_content{width: 19%;box-sizing: border-box;border: 1px solid #cdcdcd;border-radius: 5px;padding: 0 10px;}}</style>

以上就是上面效果图实现的全部代码,没有什么技术含量,就是简单的记录下来,分享给有需要的人;


http://www.ppmy.cn/news/623828.html

相关文章

Centos 系统中使用 Firefix 播放视频 - VLC播放器的安装

问题&#xff1a; 出于刷视频的需要&#xff0c;需要使用虚拟机&#xff08;Centos7&#xff09;上的 Firefix 来播放视频&#xff0c;经确认安装 flash 的方式是不行的。事实上在 Firefix 播放视频仅需要安装 VLC 播放器就可以了&#xff0c;以下记录安装 VLC 视频播放器的过程…

《侠盗车手3》全攻略(完美版)

自由之城&#xff0c;这是一座喧闹的大都市&#xff0c;每当白昼过去黑夜降临&#xff0c;所有的东西都笼罩在模糊中&#xff0c;闪烁的灯光让每个人有了一种莫名的冲动。就在这种冲动的驱使下&#xff0c;我和女友露茜还有她哥哥一同光临了本城最大的银行&#xff0c;霰弹枪让…

《侠盗猎车手-罪恶都市》秘籍

在GTA-VC(侠盗猎车-罪恶都市)中&#xff0c;能够用秘籍调出来的汽车有很多&#xff0c;其中最不常用的大概就是TRASHMASTER(用秘籍RUBBISHCAR调出来的垃圾运输车)。 它又大&#xff0c;又笨&#xff0c;的确很“垃圾”。 摸索中发现改进方法&#xff0c;化腐朽为神奇&#xff0…

Grand Theft Auto V (侠盗列车手5)图形研究

原文地址&#xff1a;http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/ 原文的简介&#xff1a; GTA&#xff08;侠盗猎车&#xff09;系列自从1997年首部发售以来有了很大的进步&#xff0c;两年前&#xff0c;Rockstar发布的GTAV获得了成功&#xff0c…

侠盗飞车秘籍-侠盗秘籍-飞车4飞车5密籍

侠盗飞车秘籍 欢迎使用罪恶都市侠盗飞车秘籍,使用作弊码玩罪恶都市玩游戏不用攻略也能通关。 侠盗飞车秘籍大全 Post time: 2008年3月11日 侠盗飞车秘籍使用方法:在游戏中顺序输入以下英文即可生效。 评论:0 | 引用:0 | 浏览: | Tags: 秘籍 侠盗飞车 侠盗飞车密码攻略 Post …

游戏《侠盗飞车3:罪恶城市》功能码

标题: 游戏《侠盗飞车3&#xff1a;罪恶城市》功能码 正文: QUOTE: 这两天玩了几次 Vice City, 蛮好玩, 虽然我Hatesssssss 游戏, 这次例外. 顺便整理重译了一下 Vice City 的功能码. 近来熟悉一下 W3 的 Xssssssssssssssssssss 系列, 技术停呀停. W3 的 Xssssssssssss 比牛毛…

C. Robot Collisions(暑期集训)

原题链接 题意&#xff1a; 有n个机器人在OX轴上运动&#xff0c;运动范围为[0,m]。 第i个机器人开始位于xi的位置&#xff0c;然后以1单位距离每秒的速度向左或向右运动&#xff0c;当其运动到0点或m点时会调转方向。 如果任意时刻多于一个机器人在同一整数位置&#xff0c;…

vscode搭建汇编环境

汇编语言环境的配置 教程 视频教程 https://www.nasm.us/pub/nasm/releasebuilds/?CM;OD 下载zip压缩包&#xff0c;去目录去解压&#xff0c;然后把根目录配置到环境的变量 vscode搭建汇编环境 插件 assembly Hex editor 这个是用来显示.exe文件的十六字进制的显示 下载…