vue +antvX6 根据节点与线,动态设置节点坐标生成流程图

时间:2024-04-30 07:29:17
<script> import API from '../api' // 接口 import { Graph } from '@antv/x6' // 引入antvX6 import { Snapline } from '@antv/x6-plugin-snapline' // 引入对齐线 Graph.registerNode( // 设置节点基础样式 'custom-rect', { inherit: 'rect', width: 200, height: 40, attrs: { body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' }, text: { fontSize: 12, fill: '#262626' } }, text: { fontSize: 12, fill: '#262626' } }, true ) export default { data() { return { loading: false, graph: null, // 画布实例对象 data: { nodes: [], edges: [] } } }, mounted() { // 先初始化画布 this.initGraph() }, beforeDestroy() { // 画布的销毁以及回收 this.graph.dispose() this.graph = null }, methods: { // 初始化流程图画布 initGraph() { const container = document.getElementById('container') this.graph = new Graph({ container: container, // 画布容器 width: container.offsetWidth, // 画布宽 height: container.offsetHeight, // 画布高 autoResize: true, background: { // 背景 color: '#F2F7FA' }, panning: { enabled: true // 支持滚动放大缩小 }, mousewheel: { enabled: true, modifiers: 'Ctrl', // 按住ctrl按键滚动鼠标滚轮缩放 factor: 1.1, maxScale: 10, // 最大放大 minScale: 0.05 // 最小缩小 }, grid: { visible: true, // 渲染网格背景 type: 'doubleMesh', args: [ { color: '#eee', // 主网格线颜色 thickness: 1 // 主网格线宽度 }, { color: '#ddd', // 次网格线颜色 thickness: 1, // 次网格线宽度 factor: 4 // 主次网格线间隔 } ] } }) this.graph.use( // 启用对齐线 new Snapline({ enabled: true }) ) // 鼠标移入线 this.graph.on('edge:mouseenter', ({ e, edge, view }) => { edge.attr({ line: { stroke: 'red', strokeWidth: 3 } }) }) // 鼠标移出线 this.graph.on('edge:mouseleave', ({ edge }) => { edge.attr({ line: { stroke: '#8f8f8f', strokeWidth: 1 } }) }) }, // 获取数据 init() { this.loading = true API.getData().then(res => { if (res.code === 200) { this.setGraphData(res) } else { this.$message.error(res.msg) } }).finally(() => { this.loading = false }) }, // 设置画布数据 setGraphData(data) { // const X = document.getElementById('top-width').offsetWidth / 2 - 100 // 居中 const X = 200 this.data = { nodes: [], edges: [] } const obj = {} // 转为对象数组 节点有可能顺序相同,顺序相同的配列在同一行 data.node_data.map(item => { if (obj[item.order_id]) { obj[item.order_id].push(item) } else { obj[item.order_id] = [] obj[item.order_id].push(item) } }) // 遍历对象数组 通过遍历数组,将节点数据转为流程图中需要的数据类型 Object.keys(obj).forEach((key, objIndex) => { obj[key].map((item, index) => { const node = { id: item.id, // 节点id shape: 'custom-rect', // 这是上边定义的节点类型 label: item.name, // 节点名称 x: X + 300 * index, // 节点x轴坐标 因为存在顺序相同的节点,需要排在同一行,但是y不一样 y: 40 + 100 * objIndex, // 节点y轴坐标 顺序不同的节点,y轴坐标不同 attrs: { body: { // 这里是区分普通节点与开始结束节点的, 具体看效果图 rx: item.type_id === 0 ? 4 : 10, ry: item.type_id === 0 ? 4 : 10 } } } this.data.nodes.push(node) }) }) // 遍历线的数据 通过遍历数组,将线数据转为流程图中需要的数据类型 data.line_data.map((item, index) => { const obj = { id: item.id, // 线id shape: 'edge', // 类型为线 source: item.destination_state_id, // 源节点 target: item.source_state_id, // 目标节点 labels: [ // 线名称样式 { attrs: { label: { text: item.name // 线名称 } }, position: 0.4 // 名称在线的相对位置(0-1)一般为0.5 } ], router: { // 线的路由 name: 'manhattan', // 智能路由 移动节点时,线自动避免与节点接触 args: { // 这里根据线的状态来判断线是从源节点的哪里开始,到目标节点的哪里结束 // 值为1 线从源节点下方开始,到目标节点上方结束 // 值为2 线从源节点左方开始,到目标节点左方结束 // 值其他 线从源节点右方开始,到目标节点右方结束 startDirections: item.attribute_type_id === 1 ? ['bottom'] : item.attribute_type_id === 2 ? ['left'] : ['right'], endDirections: item.attribute_type_id === 1 ? ['top'] : item.attribute_type_id === 2 ? ['left'] : ['right'] } }, tools: [{ name: 'segments', args: { snapRadius: 20, attrs: { fill: '#444' } } }], attrs: { // 线样式 line: { stroke: '#8f8f8f', strokeWidth: 1 } } } this.data.edges.push(obj) }) this.graph.fromJSON(this.data) // 渲染数据 将添加的节点与线画出来 }, zoomToFit() { this.graph.zoomToFit({ padding: 20, preserveAspectRatio: true, maxScale: 1 }) } } } </script>