文章目录
- 1. 源码及其效果图
- 1.1 下载所需npm包
- 2.1 效果图
- 1.3 完整代码
- 1.3.1 x6Config.js
- 1.3.2 x6.vue
1. 源码及其效果图
1.1 下载所需npm包
npm install @antv/x6
2.1 效果图

1.3 完整代码
1.3.1 x6Config.js
import { Graph } from "@antv/x6";const groupMock = {groups: {top: {position: "top",attrs: {circle: {magnet: true,stroke: "#8f8f8f",r: 1,style: {visibility: "hidden",},},},},left: {position: "left",attrs: {circle: {magnet: true,stroke: "#8f8f8f",r: 1,style: {visibility: "hidden",},},},},right: {position: "right",attrs: {circle: {magnet: true,stroke: "#8f8f8f",r: 1,style: {visibility: "hidden",},},},},bottom: {position: "bottom",attrs: {circle: {magnet: true,stroke: "#8f8f8f",r: 1,style: {visibility: "hidden",},},},},bottomR: {position: {name: "absolute",args: { x: 70, y: 50 },},attrs: {circle: {magnet: true,stroke: "#8f8f8f",r: 1,style: {visibility: "hidden",},},},},},
};export const antvX6TypeConfig = (width, headerWidth) => {Graph.registerNode("lane-contanier",{inherit: "rect",markup: [{tagName: "rect",selector: "body",},{tagName: "rect",selector: "name-rect",},{tagName: "text",selector: "name-text",},],attrs: {body: {fill: "#FFF",stroke: "#5F95FF",strokeWidth: 1,},"name-rect": {width: headerWidth,height: 40,fill: "#5F95FF",stroke: "#fff",strokeWidth: 1,x: -1,},"name-text": {ref: "name-rect",refY: 0.5,refX: 0.5,textAnchor: "middle",fontWeight: "bold",fill: "#fff",fontSize: 18,},},},true);Graph.registerNode("lane",{inherit: "rect",markup: [{tagName: "rect",selector: "body",},{tagName: "rect",selector: "name-rect",},{tagName: "text",selector: "name-text",},],attrs: {body: {fill: "#FFF",stroke: "#5F95FF",strokeWidth: 1,},"name-rect": {width: width,height: 40,fill: "#5F95FF",stroke: "#fff",strokeWidth: 1,x: -1,},"name-text": {ref: "name-rect",refY: 0.5,refX: 0.5,textAnchor: "middle",fontWeight: "bold",fill: "#fff",fontSize: 18,},},},true);Graph.registerNode("lane-rect",{inherit: "rect",width: 100,height: 60,attrs: {body: {strokeWidth: 1,stroke: "#5F95FF",fill: "#EFF4FF",},text: {fontSize: 18,fill: "#262626",},},ports: {...groupMock,items: [{ id: "top-1", group: "top" },{ id: "left-1", group: "left" },{ id: "right-1", group: "right" },{ id: "bottom-1", group: "bottom" },{ id: "bottom-1R", group: "bottomR" },],},},true);Graph.registerNode("lane-polygon",{inherit: "polygon",width: 80,height: 80,attrs: {body: {strokeWidth: 1,stroke: "#5F95FF",fill: "#EFF4FF",refPoints: "0,10 10,0 20,10 10,20",},text: {fontSize: 18,fill: "#262626",},},ports: {...groupMock,items: [{ id: "top-2", group: "top" },{ id: "left-2", group: "left" },{ id: "right-2", group: "right" },{ id: "bottom-2", group: "bottom" },],},},true);Graph.registerEdge("lane-edge",{inherit: "edge",attrs: {line: {stroke: "#8A9EB8",strokeWidth: 2,},},label: {attrs: {label: {fill: "#8A9EB8",fontSize: 18,},},},},true);Graph.registerEdge("lane-edge-revoke",{inherit: "edge",attrs: {line: {stroke: "#E96F0C",strokeWidth: 2,},},label: {attrs: {label: {fill: "#E96F0C",fontSize: 18,},},},},true);
}
const success_box = {attrs: {body: {fill: "#5cbf77",stroke: "#5cbf77",strokeWidth: 1},text: {fill: "#262626",lineHeight: 24,fontSize: 18,}}
}
const never_passed_box = {attrs: {body: {fill: "#f56c6c",stroke: "#f56c6c",strokeWidth: 1},text: {fill: "#262626",lineHeight: 24,fontSize: 18,}}
}
const success_box_active = {attrs: {body: {fill: "#ffc000",stroke: "#ffc000",strokeWidth: 1},text: {fill: "#262626",lineHeight: 24,fontSize: 18,}}
}
const success_box_skip = {attrs: {body: {fill: "#bfbfbf",stroke: "#bfbfbf",strokeWidth: 1},text: {fill: "#262626",lineHeight: 24,fontSize: 18,}}
}
const success_line = {labels: [{position: 0.5, attrs: {text: {text: "是",fill: "#5cbf77",stroke: "#5cbf77",fontSize: 18,}}}],attrs: {line: {stroke: "#5cbf77",strokeWidth: 2}},label: {attrs: {label: {text: "是",fill: "#5cbf77",fontSize: 18,},},},
}
const never_passed_line = {labels: [{position: 0.5, attrs: {text: {text: "是",fill: "#f56c6c",stroke: "#f56c6c",fontSize: 18,}}}],attrs: {line: {stroke: "#f56c6c",strokeWidth: 2}},label: {attrs: {label: {text: "是",fill: "#f56c6c",fontSize: 18,},},},
}
const success_line_skip = {labels: [{position: 0.5, attrs: {text: {text: "是",fill: "#bfbfbf",stroke: "#bfbfbf",fontSize: 18,}}}],attrs: {line: {stroke: "#bfbfbf",strokeWidth: 2}},label: {attrs: {label: {text: "是",fill: "#bfbfbf",fontSize: 18,},},},
}
const success_line_skip_no = {labels: [{position: 0.5, attrs: {text: {text: "否",fill: "#bfbfbf",stroke: "#bfbfbf",fontSize: 18,}}}],attrs: {line: {stroke: "#bfbfbf",strokeWidth: 2}},label: {attrs: {label: {text: "否",fill: "#bfbfbf",fontSize: 18,},},},
}
const success_line_no = {labels: [{position: 0.5, attrs: {text: {text: "否",fill: "#5cbf77",stroke: "#5cbf77",fontSize: 18,}}}],attrs: {line: {stroke: "#5cbf77",strokeWidth: 2}},label: {attrs: {label: {text: "否",fill: "#5cbf77",fontSize: 18,},},},
}
const never_passed_line_no = {labels: [{position: 0.5, attrs: {text: {text: "否",fill: "#f56c6c",stroke: "#f56c6c",fontSize: 18,}}}],attrs: {line: {stroke: "#f56c6c",strokeWidth: 2}},label: {attrs: {label: {text: "否",fill: "#f56c6c",fontSize: 18,},},},
}
const success_line_no_text = {attrs: {line: {stroke: "#5cbf77",strokeWidth: 2}},
}
const never_passed_line_no_text = {attrs: {line: {stroke: "#f56c6c",strokeWidth: 2}},
}
const success_line_skip_no_text = {labels: [{position: 0.5, attrs: {text: {text: "",fill: "#bfbfbf",stroke: "#bfbfbf",fontSize: 18,}}}],attrs: {line: {stroke: "#bfbfbf",strokeWidth: 2}},label: {attrs: {label: {text: "",fill: "#bfbfbf",fontSize: 18,},},},
}export const dataMock = (node, flowLogRepVOS, width = 300, height = 800) => {return [{id: "1",shape: "lane",width: width,height: height,position: {x: 60,y: 40,},label: "节点1",}, {id: "2",shape: "lane",width: width,height: height,position: {x: 60 + width,y: 40,},label: "节点2",}, {id: "3",shape: "lane",width: width,height: height,position: {x: 60 + width * 2,y: 40,},label: "节点3",}, {id: "4",shape: "lane",width: width,height: height,position: {x: 60 + width * 3,y: 40,},label: "节点4",}, {id: "5",shape: "lane",width: width,height: height,position: {x: 60 + width * 4,y: 40,},label: "节点5",}, {id: "6",shape: "lane",width: width,height: height,position: {x: 60 + width * 5,y: 40,},label: "节点6",}, {id: "7",shape: "lane",width: width,height: height,position: {x: 60 + width * 6,y: 40,},label: "节点7\n(审批)",}, {id: "8",shape: "lane",width: width,height: height,position: {x: 60 + width * 7,y: 40,},label: "节点8",}, {id: "9",shape: "lane-rect",width: 100,height: 50,position: {x: 190,y: 120,},label: "开始",attrs: {body: {rx: 30,ry: 20,fill: "#5cbf77",},},parent: "1",}, {id: "10", shape: "lane-rect",width: 310,height: 120,position: {x: 85,y: 260},label: "提交",...(node >= 10 && node < 20 ? success_box_active : node >= 20 ? success_box : never_passed_box),}, {id: "11", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width,y: 260},label: "审批",...(node >= 20 && node < 30 ? success_box_active : node >= 30 ? success_box : never_passed_box),}, {id: "12", shape: "lane-polygon",width: 240,height: 80,position: {x: 125 + width,y: 480},label: '审批是否通过',...(node >= 30 ? success_box : never_passed_box),}, {id: "13", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 2,y: 260},label: "审批",...(node >= 30 && node < 40 ? success_box_active : node >= 40 ? success_box : never_passed_box),}, {id: "14", shape: "lane-polygon",width: 240,height: 80,position: {x: 125 + width * 2,y: 480},label: '审批是否通过',...(node >= 40 ? success_box : never_passed_box),}, {id: "15", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 3,y: 260},label: "审批",...(node >= 40 && node < 50 ? success_box_active : node >= 50 ? success_box : never_passed_box),}, {id: "16", shape: "lane-polygon",width: 240,height: 80,position: {x: 125 + width * 3,y: 480},label: '审批是否通过',...(node >= 50 ? success_box : never_passed_box),}, {id: "17", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 4,y: 260},label: "审批",...(node >= 50 && node < 60 ? success_box_active : node >= 60 ? success_box : never_passed_box),}, {id: "18", shape: "lane-polygon",width: 240,height: 80,position: {x: 125 + width * 4,y: 480},label: '审批是否通过',...(node >= 60 ? success_box : never_passed_box),}, {id: "20", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 5,y: 260},label: "审批",...(node >= 60 && node < 70 ? success_box_active : node >= 70 && flowLogRepVOS.some(x => x.node > 59 && x.node < 70) ? success_box : node >= 70 && !flowLogRepVOS.some(x => x.node > 59 && x.node < 70) ? success_box_skip : never_passed_box),}, {id: "21", shape: "lane-polygon",width: 240,height: 80,position: {x: 125 + width * 5,y: 480},label: '审批是否通过',...(node >= 70 && flowLogRepVOS.some(x => x.node > 59 && x.node < 70) ? success_box : node >= 70 && !flowLogRepVOS.some(x => x.node > 59 && x.node < 70) ? success_box_skip : never_passed_box),}, {id: "22", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 6,y: 760},label: "抄送",...(node >= 70 && node < 80 ? success_box_active : node >= 80 ? success_box : never_passed_box),}, {id: "23", shape: "lane-rect",width: 240,height: 120,position: {x: 125 + width * 7,y: 760},label: "抄送",...(node >= 80 && node < 90 ? success_box_active : node >= 90 ? success_box : never_passed_box),}, {id: "24",shape: "lane-rect",width: 100,height: 50,position: {x: 195 + width * 7,y: 960},label: "结束",attrs: {body: {rx: 30,ry: 20,},},attrs: {body: {rx: 30,ry: 20,fill: node > 100 ? "#5cbf77" : '#f56c6c',}},}, {id: "25",shape: "lane-edge",source: { cell: "9", port: "bottom-2" },target: { cell: "10", port: "top-1" },...success_line_no_text,}, {id: "26",shape: "lane-edge",source: { cell: "10", port: "right-2" },target: { cell: "11", port: "left-1" },...(node >= 20 ? success_line_no_text : never_passed_line_no_text),}, {id: "27",shape: "lane-edge",source: { cell: "11", port: "bottom-2" },target: { cell: "12", port: "top-1" },...(node >= 30 ? success_line_no_text : never_passed_line_no_text),}, {id: "28",shape: "lane-edge",source: { cell: "12", port: "right-2" },target: { cell: "13", port: "left-1" },...(node >= 30 ? success_line : never_passed_line),vertices: [{ x: 180 + width * 1.6, y: 500 }],}, {id: "29",shape: "lane-edge",source: { cell: "12", port: "bottom-2" },target: { cell: "10", port: "bottom-1" },label: "否",vertices: [{ x: 200 + width * 1.1, y: 620 }],}, {id: "30",shape: "lane-edge",source: { cell: "13", port: "bottom-2" },target: { cell: "14", port: "top-1" },...(node >= 40 ? success_line_no_text : never_passed_line_no_text),}, {id: "31",shape: "lane-edge",source: { cell: "14", port: "right-2" },target: { cell: "15", port: "left-1" },...(node >= 40 ? success_line : never_passed_line),vertices: [{ x: 180 + width * 2.6, y: 500 }],}, {id: "32",shape: "lane-edge",source: { cell: "14", port: "bottom-2" },target: { cell: "10", port: "bottom-1" },label: "否",vertices: [{ x: 200 + width * 2.1, y: 620 }],}, {id: "33",shape: "lane-edge",source: { cell: "15", port: "bottom-2" },target: { cell: "16", port: "top-1" },...(node >= 50 ? success_line_no_text : never_passed_line_no_text),}, {id: "34",shape: "lane-edge",source: { cell: "16", port: "right-2" },target: { cell: "17", port: "left-1" },...(node >= 50 ? success_line : never_passed_line),vertices: [{ x: 180 + width * 3.6, y: 500 }],}, {id: "35",shape: "lane-edge",source: { cell: "16", port: "bottom-2" },target: { cell: "10", port: "bottom-1" },label: "否",vertices: [{ x: 200 + width * 2.1, y: 620 }],}, {id: "36",shape: "lane-edge",source: { cell: "17", port: "bottom-2" },target: { cell: "18", port: "top-1" },...(node >= 60 ? success_line_no_text : never_passed_line_no_text),}, {id: "37",shape: "lane-edge",source: { cell: "18", port: "bottom-2" },target: { cell: "10", port: "bottom-1" },label: "否",vertices: [{ x: 200 + width * 4.1, y: 620 }],}, {id: "38",shape: "lane-edge",source: { cell: "18", port: "right-2" },target: { cell: "20", port: "top-2" },...(node >= 60 ? success_line : never_passed_line),vertices: [{ x: 200 + width * 4.55, y: 500 }],}, {id: "40",shape: "lane-edge",source: { cell: "20", port: "bottom-2" },target: { cell: "21", port: "top-1" },...(node >= 70 ? success_line_no_text : never_passed_line_no_text),}, {id: "41",shape: "lane-edge",source: { cell: "21", port: "bottom-2" },target: { cell: "10", port: "bottom-1" },label: "否",vertices: [{ x: 200 + width * 5.1, y: 620 }],}, {id: "43",shape: "lane-edge",source: { cell: "21", port: "right-2" },target: { cell: "22", port: "left-1" },...(node >= 70 ? success_line : never_passed_line),vertices: [{ x: 200 + width * 5.5, y: 820 }],}, {id: "44",shape: "lane-edge",source: { cell: "22", port: "right-2" },target: { cell: "23", port: "left-1" },...(node >= 80 ? success_line_no_text : never_passed_line_no_text),}, {id: "45",shape: "lane-edge",source: { cell: "23", port: "bottom-2" },target: { cell: "24", port: "top-1" },...(node >= 100 ? success_line_no_text : never_passed_line_no_text),},]
}
1.3.2 x6.vue
<template><div id="flowContainer"></div>
</template><script setup name="setup">
import { onMounted, ref, nextTick } from 'vue'
import { Graph } from "@antv/x6";
import { antvX6TypeConfig, dataMock } from "./x6Config.js";const initGraph = (node,flowLogRepVOS
) => {antvX6TypeConfig(366, 2700)const graph = new Graph({container: document.getElementById("flowContainer"),height: 950,connecting: {router: "orth",},interacting: { nodeMovable: false, edgeMovable: false },translating: {restrict (cellView) {const cell = cellView.cell;const parentId = cell.prop("parent");if (parentId) {const parentNode = graph.getCellById(parentId);if (parentNode) {return parentNode.getBBox().moveAndExpand({x: 0,y: 30,width: 0,height: -30,});}}return cell.getBBox();},},});graph.on('node:click', ({ node }) => {console.log('节点被点击:', node.id);});graph.on('node:dblclick', ({ node }) => {console.log('节点被双击:', node.id);});graph.on('node:mouseenter', ({ node }) => {node.attr('body/stroke', '#ff0000'); });graph.on('node:mouseleave', ({ node }) => {node.attr('body/stroke', '#5F95FF'); });graph.on('node:contextmenu', ({ e, node }) => {e.preventDefault(); console.log('节点右键点击:', node.id);});graph.on('node:selected', ({ node }) => {console.log('节点被选中:', node.id);});graph.on('node:unselected', ({ node }) => {console.log('节点取消选中:', node.id);});Promise.resolve(dataMock(node, flowLogRepVOS, 366, 1000)).then((data) => {const cells = [];data.forEach((item) => {if (item.shape.includes("lane-edge")) {cells.push(graph.createEdge(item));} else {cells.push(graph.createNode(item));}});graph.resetCells(cells);graph.zoomToFit({ padding: 10, maxScale: 1 });nextTick(() => {let designWidth = 1920 - document.body.offsetWidth < 10 && document.body.offsetWidth < 1920 ? document.body.offsetWidth : 1920; let dom = document.querySelector("#flowContainer");if (dom) {graph.translate(-28 * (dom.clientWidth / designWidth), 0);}})});
};onMounted(() => {initGraph(40, [{ node: 10 }])
})</script><style scoped lang="less"></style>