From 4889312eb360c78c6a0f80a0ab83c92664e5adc5 Mon Sep 17 00:00:00 2001 From: asp_ly Date: Fri, 13 Dec 2024 20:59:39 +0800 Subject: [PATCH] 1 --- .../Definition/Design/utils/layoutUtils.ts | 127 ++++++++++++++---- 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/frontend/src/pages/Workflow/Definition/Design/utils/layoutUtils.ts b/frontend/src/pages/Workflow/Definition/Design/utils/layoutUtils.ts index f222d3fa..85b8fd7a 100644 --- a/frontend/src/pages/Workflow/Definition/Design/utils/layoutUtils.ts +++ b/frontend/src/pages/Workflow/Definition/Design/utils/layoutUtils.ts @@ -2,6 +2,7 @@ import { Graph } from '@antv/x6'; import dagre from 'dagre'; interface NodeData { + id: string; graph: { position?: { x: number; @@ -10,17 +11,24 @@ interface NodeData { }; } +interface RelativePosition { + id: string; + position: { + x: number; + y: number; + }; +} + /** * 检查是否所有节点都有位置信息 * @param nodes 节点列表 * @returns 是否所有节点都有位置信息 */ -const hasAllNodesPosition = (nodes: NodeData[]) => { +const hasAllNodesPosition = (nodes: NodeData[]): boolean => { return nodes.every(node => { const graphData = node.graph; - return graphData && graphData.position && - typeof graphData.position.x === 'number' && - typeof graphData.position.y === 'number'; + return graphData?.position?.x != null && + graphData?.position?.y != null; }); }; @@ -28,29 +36,83 @@ const hasAllNodesPosition = (nodes: NodeData[]) => { * 居中显示并适应画布大小 * @param graph 图形实例 */ -const centerAndFit = (graph: Graph) => { +const centerAndFit = (graph: Graph): void => { + const nodes = graph.getNodes(); + if (nodes.length === 0) return; + + // 计算所有节点的边界 + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + + nodes.forEach(node => { + const position = node.getPosition(); + const size = node.getSize(); + minX = Math.min(minX, position.x); + minY = Math.min(minY, position.y); + maxX = Math.max(maxX, position.x + size.width); + maxY = Math.max(maxY, position.y + size.height); + }); + // 获取画布大小 const container = graph.container; if (!container) return; const containerBBox = container.getBoundingClientRect(); - const padding = 40; // 设置更大的内边距 + const padding = 40; - // 居中并缩放 - graph.centerContent(); - graph.zoomToFit({ - padding, - maxScale: 1, // 限制最大缩放比例 - minScale: 0.5, // 限制最小缩放比例 + // 计算图形的宽度和高度 + const graphWidth = maxX - minX; + const graphHeight = maxY - minY; + + // 计算缩放比例 + const scaleX = (containerBBox.width - padding * 2) / graphWidth; + const scaleY = (containerBBox.height - padding * 2) / graphHeight; + const scale = Math.min(Math.min(scaleX, scaleY), 1); + + // 计算居中位置 + const tx = (containerBBox.width - graphWidth * scale) / 2 - minX * scale; + const ty = (containerBBox.height - graphHeight * scale) / 2 - minY * scale; + + // 应用变换 + graph.scale(scale); + graph.translate(tx, ty); +}; + +/** + * 计算节点的相对位置 + * @param nodes 节点列表 + * @returns 节点的相对位置数组 + */ +const calculateRelativePositions = (nodes: NodeData[]): RelativePosition[] | null => { + if (nodes.length === 0) return null; + + // 计算所有节点的最小坐标 + let minX = Infinity; + let minY = Infinity; + nodes.forEach(node => { + if (node.graph?.position) { + minX = Math.min(minX, node.graph.position.x); + minY = Math.min(minY, node.graph.position.y); + } }); - // 确保在视口中心 - const graphBBox = graph.getBBox(); - if (graphBBox) { - const tx = (containerBBox.width - graphBBox.width) / 2; - const ty = (containerBBox.height - graphBBox.height) / 2; - graph.translate(tx, ty); - } + // 计算相对位置 + const positions = nodes.map(node => { + if (node.graph?.position) { + return { + id: node.id, + position: { + x: node.graph.position.x - minX, + y: node.graph.position.y - minY + } + }; + } + return null; + }).filter((pos): pos is RelativePosition => pos !== null); + + return positions.length > 0 ? positions : null; }; /** @@ -58,23 +120,32 @@ const centerAndFit = (graph: Graph) => { * @param graph 图形实例 * @param nodes 节点数据列表 */ -export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []) => { - // 如果所有节点都有位置信息,只进行居中显示 +export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []): void => { + // 如果所有节点都有位置信息,计算并应用相对位置 if (nodes.length > 0 && hasAllNodesPosition(nodes)) { - // 等待所有节点渲染完成后再居中 - setTimeout(() => { + const relativePositions = calculateRelativePositions(nodes); + if (relativePositions) { + // 应用相对位置 + graph.getNodes().forEach(node => { + const nodePosition = relativePositions.find(pos => pos.id === node.id); + if (nodePosition) { + node.position(nodePosition.position.x, nodePosition.position.y); + } + }); + // 立即居中显示 centerAndFit(graph); - }, 100); + } return; } + // 创建布局图 const g = new dagre.graphlib.Graph(); g.setGraph({ rankdir: 'LR', align: 'UL', - ranksep: 100, // 增加节点间距 - nodesep: 60, // 增加节点间距 - marginx: 40, // 增加边距 + ranksep: 100, + nodesep: 60, + marginx: 40, marginy: 40, }); g.setDefaultEdgeLabel(() => ({})); @@ -108,6 +179,6 @@ export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []) => { } }); - // 居中显示并适应画布 + // 立即居中显示 centerAndFit(graph); }; \ No newline at end of file