代码迁移出去。
This commit is contained in:
parent
a45d25634f
commit
0ec831fc36
7
frontend/package-lock.json
generated
7
frontend/package-lock.json
generated
@ -232,7 +232,6 @@
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-clipboard/-/x6-plugin-clipboard-2.1.6.tgz",
|
||||
"integrity": "sha512-roZPLnZx6PK8MBvee0QMo90fz/TXeF0WNe4EGin2NBq5M1I5XTWrYvA6N2XVIiWAAI67gjQeEE8TpkL7f8QdqA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
@ -250,7 +249,6 @@
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-history/-/x6-plugin-history-2.2.4.tgz",
|
||||
"integrity": "sha512-9gHHvEW4Fla+1hxUV49zNgJyIMoV9CjVM52MrFgAJcvyRn1Kvxz4MfxiKlG+DEZUs+/zvfjl9pS6gJOd8laRkg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
@ -259,7 +257,6 @@
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-keyboard/-/x6-plugin-keyboard-2.2.3.tgz",
|
||||
"integrity": "sha512-pnCIC+mDyKKfkcDyLePfGxKVIqXBcldTgannITkHC1kc0IafRS1GMvzpvuDGrM5haRYd6Nwz8kjkJyHkJE4GPA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mousetrap": "^1.6.5"
|
||||
},
|
||||
@ -271,7 +268,6 @@
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-minimap/-/x6-plugin-minimap-2.0.7.tgz",
|
||||
"integrity": "sha512-8zzESCx0jguFPCOKCA0gPFb6JmRgq81CXXtgJYe34XhySdZ6PB23I5Po062lNsEuTjTjnzli4lju8vvU+jzlGw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
@ -280,7 +276,6 @@
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-selection/-/x6-plugin-selection-2.2.2.tgz",
|
||||
"integrity": "sha512-s2gtR9Onlhr7HOHqyqg0d+4sG76JCcQEbvrZZ64XmSChlvieIPlC3YtH4dg1KMNhYIuBmBmpSum6S0eVTEiPQw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
@ -289,7 +284,6 @@
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-snapline/-/x6-plugin-snapline-2.1.7.tgz",
|
||||
"integrity": "sha512-AsysoCb9vES0U2USNhEpYuO/W8I0aYfkhlbee5Kt4NYiMfQfZKQyqW/YjDVaS2pm38C1NKu1LdPVk/BBr4CasA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
@ -298,7 +292,6 @@
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-transform/-/x6-plugin-transform-2.1.8.tgz",
|
||||
"integrity": "sha512-GvJuiJ4BKp0H7+qx3R1I+Vzbw5gXp9+oByXo/WyVxE3urOC7LC5sqnaDfIjyYMN6ROLPYPZraLSeSyYBgMgcDw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@antv/x6": "^2.x"
|
||||
}
|
||||
|
||||
@ -6,13 +6,6 @@ import {getDefinition, updateDefinition} from '../../service';
|
||||
import {WorkflowDefinition, WorkflowStatus} from '../../../Workflow/types';
|
||||
import {Graph, Node, Cell, Edge, Shape} from '@antv/x6';
|
||||
import '@antv/x6-react-shape';
|
||||
import {Selection} from '@antv/x6-plugin-selection';
|
||||
import {History} from '@antv/x6-plugin-history';
|
||||
import {Clipboard} from '@antv/x6-plugin-clipboard';
|
||||
import {Transform} from '@antv/x6-plugin-transform';
|
||||
import {Keyboard} from '@antv/x6-plugin-keyboard';
|
||||
import {Snapline} from '@antv/x6-plugin-snapline';
|
||||
import {MiniMap} from '@antv/x6-plugin-minimap';
|
||||
import './index.module.less';
|
||||
import NodePanel from './components/NodePanel';
|
||||
import NodeConfig from './components/NodeConfig';
|
||||
@ -22,9 +15,9 @@ import {DeleteOutlined, CopyOutlined, SettingOutlined, ClearOutlined, Fullscreen
|
||||
import EdgeConfig from './components/EdgeConfig';
|
||||
import { validateFlow, hasCycle } from './validate';
|
||||
import { generateNodeStyle, generatePorts, calculateNodePosition, calculateCanvasPosition } from './utils/nodeUtils';
|
||||
import { Position } from './types';
|
||||
import { NODE_CONFIG } from './configs/nodeConfig';
|
||||
import { isWorkflowError } from './utils/errors';
|
||||
import { initGraph } from './utils/graphUtils';
|
||||
|
||||
const {Sider, Content} = Layout;
|
||||
|
||||
@ -194,264 +187,38 @@ const FlowDesigner: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
// 初始化图形
|
||||
const initGraph = () => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const graph = new Graph({
|
||||
useEffect(() => {
|
||||
if (detail && containerRef.current) {
|
||||
const graph = initGraph({
|
||||
container: containerRef.current,
|
||||
grid: {
|
||||
visible: true,
|
||||
type: 'mesh',
|
||||
size: 10,
|
||||
args: {
|
||||
color: '#e5e5e5',
|
||||
thickness: 1,
|
||||
},
|
||||
},
|
||||
mousewheel: {
|
||||
enabled: true,
|
||||
modifiers: ['ctrl', 'meta'],
|
||||
minScale: 0.5,
|
||||
maxScale: 2,
|
||||
},
|
||||
connecting: {
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
allowNode: false,
|
||||
allowEdge: false,
|
||||
connector: {
|
||||
name: 'rounded',
|
||||
args: {
|
||||
radius: 8,
|
||||
},
|
||||
},
|
||||
router: {
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
padding: 1,
|
||||
},
|
||||
},
|
||||
validateConnection({sourceCell, targetCell, sourceMagnet, targetMagnet}) {
|
||||
if (sourceCell === targetCell) {
|
||||
return false;
|
||||
miniMapContainer: document.getElementById('workflow-minimap')!,
|
||||
onContextMenu: (params) => setContextMenu(params),
|
||||
onNodeClick: (node) => {
|
||||
setCurrentNode(node);
|
||||
const data = node.getData() as NodeData;
|
||||
console.log('Node clicked, data:', data);
|
||||
|
||||
if (data) {
|
||||
const nodeType = nodeTypes.find(type => type.code === data.type);
|
||||
if (nodeType) {
|
||||
setCurrentNodeType(nodeType);
|
||||
const formValues = {
|
||||
name: data.name || nodeType.name,
|
||||
description: data.description,
|
||||
...data.config
|
||||
};
|
||||
console.log('Setting form values:', formValues);
|
||||
form.setFieldsValue(formValues);
|
||||
setConfigVisible(true);
|
||||
} else {
|
||||
message.error('未找到对应的节点类型');
|
||||
}
|
||||
if (!sourceMagnet || !targetMagnet) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
router: {
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
padding: 1,
|
||||
},
|
||||
},
|
||||
connector: {
|
||||
name: 'rounded',
|
||||
args: {
|
||||
radius: 8,
|
||||
},
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
attrs: {
|
||||
label: {
|
||||
text: '',
|
||||
fill: '#333',
|
||||
fontSize: 12,
|
||||
},
|
||||
rect: {
|
||||
fill: '#fff',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
rx: 3,
|
||||
ry: 3,
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
},
|
||||
},
|
||||
position: {
|
||||
distance: 0.5,
|
||||
offset: {
|
||||
x: 0,
|
||||
y: -10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
highlighting: {
|
||||
magnetAvailable: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 4,
|
||||
attrs: {
|
||||
strokeWidth: 4,
|
||||
stroke: '#52c41a',
|
||||
},
|
||||
},
|
||||
},
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 4,
|
||||
attrs: {
|
||||
strokeWidth: 4,
|
||||
stroke: '#1890ff',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
keyboard: {
|
||||
enabled: true,
|
||||
},
|
||||
clipboard: {
|
||||
enabled: true,
|
||||
},
|
||||
history: {
|
||||
enabled: true,
|
||||
},
|
||||
snapline: {
|
||||
enabled: true,
|
||||
},
|
||||
translating: {
|
||||
restrict: true,
|
||||
},
|
||||
background: {
|
||||
color: '#ffffff', // 画布背景色
|
||||
},
|
||||
});
|
||||
|
||||
// 启用必要的功能
|
||||
graph.use(
|
||||
new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberband: true,
|
||||
rubberEdge: true,
|
||||
movable: true,
|
||||
showNodeSelectionBox: true,
|
||||
showEdgeSelectionBox: true,
|
||||
selectCellOnMoved: false,
|
||||
selectEdgeOnMoved: false,
|
||||
selectNodeOnMoved: false,
|
||||
className: 'node-selected',
|
||||
strict: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new History({
|
||||
enabled: true,
|
||||
beforeAddCommand: (event: string, args: any) => {
|
||||
if (event === 'cell:change:*') {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Clipboard({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Transform({
|
||||
resizing: {
|
||||
enabled: true,
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
orthogonal: true,
|
||||
restricted: true,
|
||||
},
|
||||
rotating: {
|
||||
enabled: true,
|
||||
grid: 15,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Keyboard({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Snapline({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
// 启用小地图
|
||||
graph.use(
|
||||
new MiniMap({
|
||||
container: document.getElementById('workflow-minimap'),
|
||||
width: 200,
|
||||
height: 150,
|
||||
padding: 10,
|
||||
scalable: false,
|
||||
minScale: 0.5,
|
||||
maxScale: 2,
|
||||
graphOptions: {
|
||||
async: true,
|
||||
// 简化节点渲染
|
||||
grid: false,
|
||||
background: {
|
||||
color: '#f5f5f5',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// 绑定右键菜单事件
|
||||
graph.on('cell:contextmenu', ({ cell, e }) => {
|
||||
e.preventDefault();
|
||||
setContextMenu({
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
visible: true,
|
||||
type: cell.isNode() ? 'node' : 'edge',
|
||||
cell,
|
||||
});
|
||||
});
|
||||
|
||||
graph.on('blank:contextmenu', ({ e }) => {
|
||||
e.preventDefault();
|
||||
setContextMenu({
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
visible: true,
|
||||
type: 'canvas',
|
||||
});
|
||||
});
|
||||
|
||||
// 点击画布时隐藏右键菜单
|
||||
graph.on('blank:click', () => {
|
||||
setContextMenu(prev => ({ ...prev, visible: false }));
|
||||
});
|
||||
|
||||
// 点击节点时隐藏右键菜单
|
||||
graph.on('cell:click', () => {
|
||||
setContextMenu(prev => ({ ...prev, visible: false }));
|
||||
onGraphChange: (g) => setGraph(g),
|
||||
onDragOver: handleDragOver,
|
||||
onDrop: handleDrop,
|
||||
flowDetail: detail
|
||||
});
|
||||
|
||||
graphRef.current = graph;
|
||||
@ -461,45 +228,14 @@ const FlowDesigner: React.FC = () => {
|
||||
if (detail) {
|
||||
loadGraphData(graph, detail);
|
||||
}
|
||||
|
||||
// 监听画布拖拽事件
|
||||
containerRef.current.addEventListener('dragover', handleDragOver);
|
||||
containerRef.current.addEventListener('drop', handleDrop);
|
||||
|
||||
// 监听节点点击事件
|
||||
graph.on('node:click', ({node}: { node: Node }) => {
|
||||
setCurrentNode(node);
|
||||
const data = node.getData() as NodeData;
|
||||
console.log('Node clicked, data:', data);
|
||||
|
||||
if (data) {
|
||||
// 获取节点类型
|
||||
const nodeType = nodeTypes.find(type => type.code === data.type);
|
||||
if (nodeType) {
|
||||
setCurrentNodeType(nodeType);
|
||||
|
||||
// 合并节点基本配置和执器配置
|
||||
const formValues = {
|
||||
name: data.name || nodeType.name,
|
||||
description: data.description,
|
||||
...data.config // 直接展开所有配置
|
||||
};
|
||||
|
||||
console.log('Setting form values:', formValues);
|
||||
form.setFieldsValue(formValues);
|
||||
setConfigVisible(true);
|
||||
} else {
|
||||
message.error('未找到对应的节点类型');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 监听选择状态变化
|
||||
graph.on('selection:changed', () => {
|
||||
// 强制更新工具栏状态
|
||||
setGraph(graph);
|
||||
});
|
||||
return () => {
|
||||
if (graphRef.current) {
|
||||
graphRef.current.dispose();
|
||||
}
|
||||
};
|
||||
}, [detail]);
|
||||
|
||||
// 处理拖拽移动
|
||||
const handleDragOver = (e: DragEvent) => {
|
||||
@ -714,43 +450,6 @@ const FlowDesigner: React.FC = () => {
|
||||
fetchDetail();
|
||||
}, [id]);
|
||||
|
||||
// 初始化图形
|
||||
useEffect(() => {
|
||||
if (detail && containerRef.current) {
|
||||
initGraph();
|
||||
}
|
||||
// 清理事件监听
|
||||
return () => {
|
||||
if (containerRef.current) {
|
||||
containerRef.current.removeEventListener('dragover', handleDragOver);
|
||||
containerRef.current.removeEventListener('drop', handleDrop);
|
||||
}
|
||||
if (graphRef.current) {
|
||||
graphRef.current.dispose();
|
||||
}
|
||||
};
|
||||
}, [detail, containerRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
if (graphRef.current) {
|
||||
const container = containerRef.current;
|
||||
if (container) {
|
||||
const { width, height } = container.getBoundingClientRect();
|
||||
graphRef.current.resize(width, height);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resizeObserver.observe(containerRef.current);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 处理节点拖拽开始
|
||||
const handleNodeDragStart = (nodeType: NodeType) => {
|
||||
draggedNodeRef.current = nodeType;
|
||||
|
||||
@ -0,0 +1,302 @@
|
||||
import { Graph } from '@antv/x6';
|
||||
import { Selection } from '@antv/x6-plugin-selection';
|
||||
import { Keyboard } from '@antv/x6-plugin-keyboard';
|
||||
import { Clipboard } from '@antv/x6-plugin-clipboard';
|
||||
import { History } from '@antv/x6-plugin-history';
|
||||
import { Transform } from '@antv/x6-plugin-transform';
|
||||
import { Snapline } from '@antv/x6-plugin-snapline';
|
||||
import { MiniMap } from '@antv/x6-plugin-minimap';
|
||||
import { NodeData, NodeType, WorkflowDefinition } from '../types';
|
||||
import { Node } from '@antv/x6';
|
||||
|
||||
export const initGraph = ({
|
||||
container,
|
||||
miniMapContainer,
|
||||
onContextMenu,
|
||||
onNodeClick,
|
||||
onGraphChange,
|
||||
onDragOver,
|
||||
onDrop,
|
||||
flowDetail
|
||||
}: {
|
||||
container: HTMLDivElement;
|
||||
miniMapContainer: HTMLElement;
|
||||
onContextMenu: (params: any) => void;
|
||||
onNodeClick: (node: Node) => void;
|
||||
onGraphChange: (graph: Graph) => void;
|
||||
onDragOver: (e: DragEvent) => void;
|
||||
onDrop: (e: DragEvent) => void;
|
||||
flowDetail?: WorkflowDefinition;
|
||||
}) => {
|
||||
const graph = new Graph({
|
||||
container,
|
||||
grid: {
|
||||
visible: true,
|
||||
type: 'mesh',
|
||||
size: 10,
|
||||
args: {
|
||||
color: '#e5e5e5',
|
||||
thickness: 1,
|
||||
},
|
||||
},
|
||||
mousewheel: {
|
||||
enabled: true,
|
||||
modifiers: ['ctrl', 'meta'],
|
||||
minScale: 0.5,
|
||||
maxScale: 2,
|
||||
},
|
||||
connecting: {
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
allowNode: false,
|
||||
allowEdge: false,
|
||||
connector: {
|
||||
name: 'rounded',
|
||||
args: {
|
||||
radius: 8,
|
||||
},
|
||||
},
|
||||
router: {
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
padding: 1,
|
||||
},
|
||||
},
|
||||
validateConnection({sourceCell, targetCell, sourceMagnet, targetMagnet}) {
|
||||
if (sourceCell === targetCell) {
|
||||
return false;
|
||||
}
|
||||
if (!sourceMagnet || !targetMagnet) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
router: {
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
padding: 1,
|
||||
},
|
||||
},
|
||||
connector: {
|
||||
name: 'rounded',
|
||||
args: {
|
||||
radius: 8,
|
||||
},
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
attrs: {
|
||||
label: {
|
||||
text: '',
|
||||
fill: '#333',
|
||||
fontSize: 12,
|
||||
},
|
||||
rect: {
|
||||
fill: '#fff',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
rx: 3,
|
||||
ry: 3,
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
},
|
||||
},
|
||||
position: {
|
||||
distance: 0.5,
|
||||
offset: {
|
||||
x: 0,
|
||||
y: -10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
highlighting: {
|
||||
magnetAvailable: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 4,
|
||||
attrs: {
|
||||
strokeWidth: 4,
|
||||
stroke: '#52c41a',
|
||||
},
|
||||
},
|
||||
},
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 4,
|
||||
attrs: {
|
||||
strokeWidth: 4,
|
||||
stroke: '#1890ff',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
keyboard: {
|
||||
enabled: true,
|
||||
},
|
||||
clipboard: {
|
||||
enabled: true,
|
||||
},
|
||||
history: {
|
||||
enabled: true,
|
||||
},
|
||||
snapline: {
|
||||
enabled: true,
|
||||
},
|
||||
translating: {
|
||||
restrict: true,
|
||||
},
|
||||
background: {
|
||||
color: '#ffffff', // 画布背景色
|
||||
},
|
||||
});
|
||||
|
||||
// 启用必要的功能
|
||||
graph.use(
|
||||
new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberband: true,
|
||||
rubberEdge: true,
|
||||
movable: true,
|
||||
showNodeSelectionBox: true,
|
||||
showEdgeSelectionBox: true,
|
||||
selectCellOnMoved: false,
|
||||
selectEdgeOnMoved: false,
|
||||
selectNodeOnMoved: false,
|
||||
className: 'node-selected',
|
||||
strict: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new History({
|
||||
enabled: true,
|
||||
beforeAddCommand: (event: string, args: any) => {
|
||||
if (event === 'cell:change:*') {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Clipboard({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Transform({
|
||||
resizing: {
|
||||
enabled: true,
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
orthogonal: true,
|
||||
restricted: true,
|
||||
},
|
||||
rotating: {
|
||||
enabled: true,
|
||||
grid: 15,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Keyboard({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
graph.use(
|
||||
new Snapline({
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
// 启用小地图
|
||||
graph.use(
|
||||
new MiniMap({
|
||||
container: miniMapContainer,
|
||||
width: 200,
|
||||
height: 150,
|
||||
padding: 10,
|
||||
scalable: false,
|
||||
minScale: 0.5,
|
||||
maxScale: 2,
|
||||
graphOptions: {
|
||||
async: true,
|
||||
grid: false,
|
||||
background: {
|
||||
color: '#f5f5f5',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// 绑定事件
|
||||
graph.on('cell:contextmenu', ({ cell, e }) => {
|
||||
e.preventDefault();
|
||||
onContextMenu({
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
visible: true,
|
||||
type: cell.isNode() ? 'node' : 'edge',
|
||||
cell,
|
||||
});
|
||||
});
|
||||
|
||||
graph.on('blank:contextmenu', ({ e }) => {
|
||||
e.preventDefault();
|
||||
onContextMenu({
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
visible: true,
|
||||
type: 'canvas',
|
||||
});
|
||||
});
|
||||
|
||||
// 点击画布时隐藏右键菜单
|
||||
graph.on('blank:click', () => {
|
||||
onContextMenu({ visible: false, x: 0, y: 0, type: 'canvas' });
|
||||
});
|
||||
|
||||
// 点击节点时隐藏右键菜单
|
||||
graph.on('cell:click', () => {
|
||||
onContextMenu({ visible: false, x: 0, y: 0, type: 'canvas' });
|
||||
});
|
||||
|
||||
// 监听节点点击事件
|
||||
graph.on('node:click', ({ node }) => {
|
||||
onNodeClick(node);
|
||||
});
|
||||
|
||||
// 监听选择状态变化
|
||||
graph.on('selection:changed', () => {
|
||||
onGraphChange(graph);
|
||||
});
|
||||
|
||||
// 监听画布拖拽事件
|
||||
container.addEventListener('dragover', onDragOver);
|
||||
container.addEventListener('drop', onDrop);
|
||||
|
||||
return graph;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user