VUE+antv/x6实现拖拽自定义流程图
最近公司需要做一个流程图, 看了看antv/X6感觉挺合适,就研究了半个月。 网上也没什么资料,又怕自己忘,就自己记录一下用到得一些事件方法,方便以后再用到可以查阅。一:实现流程图最重要得就是画布了,官网上都有文档可以轻松实现画布。下面放一下我用VUE写得画布代码。首先最重要得就是下载依赖了, x6在vue中下载得话需要下载两个依赖;npm install @antv/x6 --savenpm i
最近公司需要做一个流程图, 看了看antv/X6感觉挺合适,就研究了半个月。 网上也没什么资料,又怕自己忘,就自己记录一下用到得一些事件方法,方便以后再用到可以查阅。
一:实现流程图最重要得就是画布了,官网上都有文档可以轻松实现画布。下面放一下我用VUE写得画布代码。
首先最重要得就是下载依赖了, x6在vue中下载得话需要下载两个依赖;
npm install @antv/x6 --save
npm install @antv/x6-vue-shape
把这两个依赖下载好就可以在vue中使用X6了
首先在页面引入依赖
import "@antv/x6-vue-shape";
import { Graph } from '@antv/x6';
下面开始写代码
在methods里定义一个initX6方法, 然后拿到mounted里调用
initX6() {
this.graph = new Graph({
container: document.getElementById("containerChart"), //这是画布需要挂载得ID名字
width:1000, //画布宽度
height: 500, //画布高度
grid: this.grid, //画布样式, 在modou层自己定义用this调用
autoResize: true, //跟随窗口自动变化大小
});
},
需要定义画布背景网格得话可以自己定义, 下面是我自己定义得一个背景网格,直接在grid后面使用this.名字调用就可以。
data(){
return{
grid: {
// 网格设置
size: 20, // 网格大小 10px
visible: true, // 渲染网格背景
type: "mesh",
args: {
color: "#D0D0D0",
thickness: 1, // 网格线宽度/网格点大小
factor: 10,
},
},
}
}
这个时候在css里给你的挂载容器定义一个宽高你就可以在页面上看到一个画布了。 给他调整一个位置就开始写节点吧。
新建一个JS文件, 用来定义节点和写拖拽代码。
import '@antv/x6-vue-shape';
import { Addon} from '@antv/x6';
// 拖拽生成四边形
export const startDragToGraph = (graph,type,e) =>{
const node =
graph.createNode({
width: 100, //节点的宽度
height: 60, //节点的高度
attrs: {
label: {
text: type,
fill: '#000000',
fontSize: 14,
textWrap: {
width: -10 ,
height: -10,
ellipsis: true,
},
},
body: {
stroke: '#000000',
strokeWidth: 1,
fill: '#ffffff',
}
},
ports: ports
})
const dnd = new Addon.Dnd({target:graph})
dnd.start(node,e)
}
//下面是锚点的代码。 知道就行了 我就不一一写了。
const ports = {
groups: {
// 输入链接桩群组定义
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#2D8CF0',
strokeWidth: 2,
fill: '#fff',
},
},
},
// 输出链接桩群组定义
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#2D8CF0',
strokeWidth: 2,
fill: '#fff',
},
},
},
left: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#2D8CF0',
strokeWidth: 2,
fill: '#fff',
},
},
},
right: {
position: 'right',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#2D8CF0',
strokeWidth: 2,
fill: '#fff',
},
},
},
},
items: [
{
id: 'port1',
group: 'top',
},
{
id: 'port2',
group: 'bottom',
},
{
id: 'port3',
group: 'left',
},
{
id: 'port4',
group: 'right',
}
],
}
定义完节点和锚点以后回到vue页面引入JS文件
import { startDragToGraph } from "../methods.js"; //引入定义好的JS文件
去HTML层加入手动拖拽的节点内容。
<template>
<div class="warp">
<div id="containerchart"></div>
<div
v-for="(item, index) in List"
:key="index"
class="btn"
:title="item"
@mousedown="startDrag(item, $event)"
>
<span>
{{ item }}
</span>
</div>
</div>
</template>
//循环的list是自己写的
data() {
return {
List: ["内置节点"],
grid: {
// 网格设置
size: 20, // 网格大小 10px
visible: true, // 渲染网格背景
type: "mesh",
args: {
color: "#D0D0D0",
thickness: 1, // 网格线宽度/网格点大小
factor: 10,
},
},
};
},
然后在methods里定义方法,把type传到js文件里。
startDrag(type, e) {
startDragToGraph(this.graph, type, e);
},
完成以上你就可以得到如下效果,从右侧拖拽节点到画布上就可以展示了。
只不过现在拖拽和线条还是有问题的。 接下来解决一下连线的问题。
data() {
return {
List: ["内置节点"],
grid: {
// 网格设置
size: 20, // 网格大小 10px
visible: true, // 渲染网格背景
type: "mesh",
args: {
color: "#D0D0D0",
thickness: 1, // 网格线宽度/网格点大小
factor: 10,
},
},
connectEdgeType: {
//连线方式
connector: "normal",
router: {
name: "",
},
},
//首先在data里定义下面三个内容,下面需要用到
graph: "",
type: "grid",
selectCell: "",
};
},
//然后在methods里的initX6方法里加上下面的方法
connecting: {
// 节点连接
anchor: "center",
connectionPoint: "anchor",
allowBlank: false,
snap: true,
},
createEdge() {
return new Shape.Edge({
attrs: {
line: {
stroke: "#1890ff",
strokeWidth: 1,
targetMarker: {
name: "classic",
size: 8,
},
strokeDasharray: 0, //虚线
style: {
animation: "ant-line 30s infinite linear",
},
},
},
label: {
text: "",
},
connector: _that.connectEdgeType.connector,
router: {
name: _that.connectEdgeType.router.name || "",
},
zIndex: 0,
});
},
//注意 这两个方法写到new的Graph实例里面。
//然后给节点写上拖拽事件,这个方法写到initX6方法里,new的Graph实例外。
this.graph.on("selection:changed", (args) => {
args.added.forEach((cell) => {
this.selectCell = cell;
if (cell.isEdge()) {
cell.isEdge() && cell.attr("line/strokeDasharray", 5); //虚线蚂蚁线
cell.addTools([
{
name: "vertices",
args: {
padding: 4,
attrs: {
strokeWidth: 0.1,
stroke: "#2d8cf0",
fill: "#ffffff",
},
},
},
]);
}
});
args.removed.forEach((cell) => {
cell.isEdge() && cell.attr("line/strokeDasharray", 0); //正常线
cell.removeTools();
});
});
现在就看到画布上面的内置节点上面的锚点是处于一直显示的状态。 下面给他处理一下。
//需要先在引入的X6方法里添加一个方法
import { Graph,FunctionExt } from "@antv/x6";
在methods里定义一个遍历方法在鼠标移入移出里调用。。
showPorts(ports, show) {
for (let i = 0, len = ports.length; i < len; i = i + 1) {
ports[i].style.visibility = show ? "visible" : "hidden";
}
},
然后在方法里给this.garph.on()添加两个鼠标移入移出事件。 移入让锚点显示,移出让锚点隐藏。 这样就可以让画布的节点好看一点了。
//鼠标移入
this.graph.on(
"node:mouseenter",
FunctionExt.debounce(() => {
const container = document.getElementById("containerchart");
const ports = container.querySelectorAll(".x6-port-body");
this.showPorts(ports, true);
}),
500
);
//鼠标移出
this.graph.on("node:mouseleave", () => {
const container = document.getElementById("containerchart");
const ports = container.querySelectorAll(".x6-port-body");
this.showPorts(ports, false);
});
下面是全部的代码
<template>
<div class="container_warp">
<div id="containerChart"></div>
<div
v-for="(item, index) in List"
:key="index"
class="btn"
:title="item"
@mousedown="startDrag(item, $event)"
>
<span>
{{ item }}
</span>
</div>
</div>
</template>
<script>
import "@antv/x6-vue-shape";
import { Graph, Shape, FunctionExt } from "@antv/x6";
import { startDragToGraph } from "../methods.js";
export default {
data() {
return {
List: [
"目录监听",
"数据组织",
"影像发布",
"目标检测",
"变化检测",
"地物分类",
"专家候审",
"样本入库",
"影像入库",
"目标入库",
"图幅整饰",
"打包下载",
],
graph: "",
type: "grid",
selectCell: "",
connectEdgeType: {
//连线方式
connector: "normal",
router: {
name: "",
},
},
grid: {
// 网格设置
size: 20, // 网格大小 10px
visible: true, // 渲染网格背景
type: "mesh",
args: {
color: "#D0D0D0",
thickness: 1, // 网格线宽度/网格点大小
factor: 10,
},
},
};
},
methods: {
initX6() {
this.graph = new Graph({
container: document.getElementById("containerChart"),
width: 1000,
height: 500,
grid: this.grid,
connecting: {
// 节点连接
anchor: "center",
connectionPoint: "anchor",
allowBlank: false,
snap: true,
},
createEdge() {
return new Shape.Edge({
attrs: {
line: {
stroke: "#1890ff",
strokeWidth: 1,
targetMarker: {
name: "classic",
size: 8,
},
strokeDasharray: 0, //虚线
style: {
animation: "ant-line 30s infinite linear",
},
},
},
label: {
text: "",
},
connector: _that.connectEdgeType.connector,
router: {
name: _that.connectEdgeType.router.name || "",
},
zIndex: 0,
});
},
});
// 鼠标移入移出节点
this.graph.on(
"node:mouseenter",
FunctionExt.debounce(() => {
const container = document.getElementById("containerChart");
const ports = container.querySelectorAll(".x6-port-body");
this.showPorts(ports, true);
}),
500
);
this.graph.on("node:mouseleave", () => {
const container = document.getElementById("containerChart");
const ports = container.querySelectorAll(".x6-port-body");
this.showPorts(ports, false);
});
this.graph.on("selection:changed", (args) => {
args.added.forEach((cell) => {
this.selectCell = cell;
if (cell.isEdge()) {
cell.isEdge() && cell.attr("line/strokeDasharray", 5); //虚线蚂蚁线
cell.addTools([
{
name: "vertices",
args: {
padding: 4,
attrs: {
strokeWidth: 0.1,
stroke: "#2d8cf0",
fill: "#ffffff",
},
},
},
]);
}
});
args.removed.forEach((cell) => {
cell.isEdge() && cell.attr("line/strokeDasharray", 0); //正常线
cell.removeTools();
});
});
},
showPorts(ports, show) {
for (let i = 0, len = ports.length; i < len; i = i + 1) {
ports[i].style.visibility = show ? "visible" : "hidden";
}
},
// 拖拽生成正方形或者圆形
startDrag(type, e) {
console.log(type, e);
console.log(this.graph);
startDragToGraph(this.graph, type, e);
},
},
mounted() {
this.initX6();
},
};
</script>
<style lang="less">
#containerChart {
width: 1000px;
height: 500px;
border: 1px solid red;
float: left;
}
.btn {
width: 400px;
float: right;
margin-right: 500px;
}
</style>
这样就完成了一个手动生成节点到画布的X6了 剩下的就是一些CSS的问题了。 下面写几个X6的事件。方便以后用到或者查阅
this.garph.on('node:click',()=>{
//这是点击节点事件
})
this.graph.on("blank:click", () => {
//这是点击画布背景事件
});
this.graph.on("cell:click", () => {
//这是点击连接线事件
});
// 删除节点
deleteNode() {
const cell = this.graph.getSelectedCells();
this.graph.removeCells(cell);
this.type = "grid";
},
//清空画布
deleteAll() {
this.graph.clearCells();
},
//销毁画布
GraphDelete() {
this.graph.dispose();
},
// 保存png
saveToPNG() {
//下面保存图片
this.$nextTick(() => {
this.graph.toPNG(
(dataUri) => {
console.log(dataUri);
// 下载
DataUri.downloadDataUri(dataUri, "资产拓扑图.png");
},
{
backgroundColor: "white",
padding: {
top: 50,
right: 50,
bottom: 50,
left: 50,
},
quality: 1,
copyStyles: false,
}
);
});
},
this.graph.toJSON()获取当前画布里的节点所有内容
JSON.stringify(this.graph.toJSON())可以把当前画布的所有节点内容转成JSON串存到本地或者后台
JSON.parse(json); 把json数据整形成数据格式 然后通过fromJSON方法再渲染到画布上。
this.graph.fromJSON(json); 可以把从后台或者本地获取到的json数据整形后渲染到画布上。
下面是个人写的一些经验, 由于网上资料有限,记录一下供以后方便查阅, 写的不好各位大神别喷。 有什么问题的也可以留言私信我。
更多推荐
所有评论(0)