diff --git a/apps/web/src/shared/gov/flow/flow-layout.ts b/apps/web/src/shared/gov/flow/flow-layout.ts index f37aa47..9dda365 100644 --- a/apps/web/src/shared/gov/flow/flow-layout.ts +++ b/apps/web/src/shared/gov/flow/flow-layout.ts @@ -428,11 +428,33 @@ function layoutManualFlow(graph: FlowGraph): FlowLayoutResult { maxY = Math.max(maxY, caption.y + 4); } + /* + * 水平居中:画幅有 1000 的下限,内容却总从左缘 PAD 起 —— 画得比 1000 窄时 + * 余白全堆在右边,图看着左贴(保存后经归一化尤其明显)。 + * 定完画幅宽度后把内容平移到正中,两侧余白对称;纵向保持收顶,不居中。 + */ + let cMinX = Infinity; + for (const shape of shapes) cMinX = Math.min(cMinX, shape.x); + for (const connection of connections) for (const p of connection.waypoints) cMinX = Math.min(cMinX, p.x); + for (const caption of captions) cMinX = Math.min(cMinX, caption.x - estTextWidth(caption.text, 10) / 2); + if (!Number.isFinite(cMinX)) cMinX = 0; + const contentW = maxX - cMinX; + const width = Math.max(1000, contentW + 40); + const dxCenter = (width - contentW) / 2 - cMinX; + if (dxCenter !== 0) { + for (const shape of shapes) shape.x += dxCenter; + for (const caption of captions) caption.x += dxCenter; + for (const connection of connections) { + connection.waypoints = connection.waypoints.map((p) => ({ x: p.x + dxCenter, y: p.y })); + if (connection.label) connection.label = { ...connection.label, x: connection.label.x + dxCenter }; + } + } + return { shapes, captions, connections, - width: Math.max(1000, maxX + 40), + width, height: maxY + 44, ghost: false, };