Files
auto-solution/modeler/src/views/decision/builder/graph.ts

178 lines
4.6 KiB
TypeScript
Raw Normal View History

2026-02-08 15:38:50 +08:00
/*
* This file is part of the kernelstudio package.
*
* (c) 2014-2025 zlin <admin@kernelstudio.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
2026-02-08 15:59:14 +08:00
import { Clipboard, Edge, Graph, History, Keyboard, Path, Selection, Snapline, Transform } from '@antv/x6';
import type { BaseElement } from '../types';
2026-02-08 15:38:50 +08:00
import type { Connecting } from '@antv/x6/lib/graph/options';
Graph.registerConnector(
'sequenceFlowConnector',
(s, e) => {
const offset = 4;
const deltaY = Math.abs(e.y - s.y);
const control = Math.floor((deltaY / 3) * 2);
const v1 = { x: s.x, y: s.y + offset + control };
const v2 = { x: e.x, y: e.y - offset - control };
return Path.parse(
`
M ${s.x} ${s.y}
L ${s.x} ${s.y + offset}
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
L ${e.x} ${e.y}
`,
).serialize();
},
true,
);
2026-02-08 15:59:14 +08:00
2026-02-08 15:38:50 +08:00
export const createGraphConnectingAttributes = (): Partial<Connecting> => {
return {
snap: true, // 当 snap 设置为 true 时连线的过程中距离节点或者连接桩 50px 时会触发自动吸附
allowBlank: false, // 是否允许连接到画布空白位置的点,默认为 true
allowLoop: false, // 是否允许创建循环连线,即边的起始节点和终止节点为同一节点,默认为 true
highlight: true, // 当连接到节点时,通过 sourceAnchor 来指定源节点的锚点。
2026-02-08 15:59:14 +08:00
connector: 'sequenceFlowConnector',
connectionPoint: 'boundary', // 指定连接点,默认值为 boundary。
2026-02-08 15:38:50 +08:00
anchor: 'center',
2026-02-08 15:59:14 +08:00
router: 'manhattan',
// connector: {
// name: 'rounded',
// args: {
// radius: 8,
// },
// },
// connectionPoint: 'anchor',
2026-02-08 15:38:50 +08:00
// validateMagnet({ magnet }) {
// return magnet.getAttribute('port-group') !== 'top'
// },
// 验证连接
validateConnection(this: Graph, { sourceCell, targetCell }) {
console.error('validateConnection');
if (!sourceCell || !targetCell) return false;
// 核心逻辑:禁止节点连接自己(自环)
if (sourceCell === targetCell) {
return false;
}
// const sourceData = sourceCell.getData() as GraphElement;
2026-02-08 15:59:14 +08:00
const targetData = targetCell.getData() as BaseElement;
2026-02-08 15:38:50 +08:00
// 根节点不能作为子节点
2026-02-08 15:59:14 +08:00
if (targetData.type === 'root') {
2026-02-08 15:38:50 +08:00
return false;
}
2026-02-08 15:59:14 +08:00
// 检查是否已存在相同连接(保留原有逻辑)
const edges: Edge[] = this.getEdges();
const existingConnection = edges.find(edge =>
edge.getSourceCell() === sourceCell &&
edge.getTargetCell() === targetCell,
);
return !existingConnection;
2026-02-08 15:38:50 +08:00
},
};
};
export const createGraphCanvas = (container: HTMLDivElement, readonly: boolean = false): Graph => {
const graph = new Graph({
container: container,
grid: {
size: 20,
visible: true,
type: 'dot',
// color: '#e5e7eb'
},
// 确保启用了异步渲染
async: true,
panning: {
enabled: true,
eventTypes: ['leftMouseDown', 'mouseWheel'],
},
mousewheel: {
enabled: true,
2026-02-08 15:59:14 +08:00
zoomAtMousePosition: true,
2026-02-08 15:38:50 +08:00
modifiers: 'ctrl',
minScale: 0.5,
2026-02-08 15:59:14 +08:00
maxScale: 3,
2026-02-08 15:38:50 +08:00
},
highlighting: {
magnetAdsorbed: {
name: 'stroke',
args: {
attrs: {
fill: '#fff',
stroke: '#31d0c6',
strokeWidth: 4,
},
},
},
},
connecting: createGraphConnectingAttributes(),
scaling: {
min: 0.5,
max: 2,
},
// 背景配置
background: {},
// 交互配置
interacting: (cellView) => {
if (readonly) {
return false; // 只读模式下禁用所有交互
}
// 确保边edge的顶点交互权限开启
if (cellView.cell.isEdge()) {
return {
vertexAddable: true, // 允许添加顶点
vertexMovable: true, // 允许移动顶点
vertexDeletable: true, // 允许删除顶点
edgeMovable: true, // 允许整体拖动连线
arrowheadMovable: true, // 允许拖动箭头调整端点
};
}
// 节点的交互配置(保持不变)
return {
nodeMovable: true,
};
},
});
graph.use(
new Selection({
multiple: true,
rubberEdge: true,
rubberNode: true,
modifiers: 'shift',
rubberband: true,
}),
2026-02-08 15:59:14 +08:00
).use(
new Transform({
resizing: false,
rotating: false,
}),
)
.use(new Snapline())
.use(new Keyboard())
.use(new Clipboard())
.use(new History());
2026-02-08 15:38:50 +08:00
return graph;
};