Tighten architecture nodes by label length

This commit is contained in:
tianma-if committed 2026-10-05 00:20:01 +08:00
1 parent f8233d9f20
commit ab23e48f4f
4 files changed
+47 -5

No files matched your search

@@ -174,6 +174,7 @@ import { api } from "@/lib/api";
import { EDITOR_LOCAL_SAVE_DELAY_MS, formatShortcutBinding, getNotebookMoveOptions, type ShortcutSettings } from "@/lib/app-helpers";
import { copyTextToClipboard } from "@/lib/clipboard";
import {
architectureNodeHeight,
compactArchitectureNodeSize,
compactFlowchartNodeSize,
flowchartNodePresentation,
@@ -1114,7 +1115,14 @@ const diagramNodePresentation = (
fontSize, 'font-size': fontSize, 'font-weight': kind === "architecture" ? ARCHITECTURE_NODE_FONT_WEIGHT : !node.parentId ? 650 : 500,
lineHeight,
});
return { ...size, height: Math.max(size.height, text.split("\n").length * lineHeight + 16), text };
const lineCount = text.split("\n").length;
return {
...size,
height: kind === "architecture"
? architectureNodeHeight(node.shape, lineCount)
: Math.max(size.height, lineCount * lineHeight + 16),
text,
};
};
const diagramNodeSize = (node: DiagramDocument["nodes"][number], kind: DiagramDocument["kind"], structure?: DiagramStructure) => {
+16
View File
@@ -180,6 +180,22 @@ describe("diagram auto layout", () => {
expect(compactArchitectureNodeSize("boundary", { width: 640, height: 360 })).toEqual({ width: 640, height: 360 });
});
test("reserves height for wrapped architecture labels while shortening compact nodes", () => {
const document = compileDiagramIr({
kind: "architecture",
nodes: [
{ id: "short", type: "service", label: "API" },
{ id: "medium", type: "service", label: "商品与库存查询服务" },
{ id: "long", type: "service", label: "商品与库存查询服务及活动规则配置中心" },
],
edges: [],
});
const heights = Object.fromEntries(document.nodes.map((node) => [node.id, node.height]));
expect(heights.short).toBe(56);
expect(heights.medium).toBe(60);
expect(heights.long).toBeGreaterThan(heights.medium);
});
test("turns a long ungrouped architecture pipeline downward on creation and auto layout", () => {
const nodes = Array.from({ length: 17 }, (_, index) => ({
id: `service-${index}`,
+1
View File
@@ -1,5 +1,6 @@
export {
compileDiagramIr,
architectureNodeHeight,
compactArchitectureNodeSize,
compactFlowchartNodeSize,
flowchartNodePresentation,
+21 -4
View File
@@ -1,4 +1,4 @@
import { compactFlowchartNodeSize, flowchartNodePresentation } from "./diagram-node-presentation";
import { compactFlowchartNodeSize, flowchartNodePresentation, visualTextUnits } from "./diagram-node-presentation";
export { compactFlowchartNodeSize, flowchartNodePresentation } from "./diagram-node-presentation";
import { DIAGRAM_READABLE_MIN_SCALE, FLOWCHART_LAYOUT_SPACING } from "./diagram-flowchart-style";
export {
@@ -131,8 +131,25 @@ export const compactArchitectureNodeSize = (
if (shape === "boundary") return authored ?? { width: 560, height: 320 };
if (shape === "database") return { width: 150, height: 72 };
if (shape === "queue") return { width: 156, height: 60 };
if (shape === "security") return { width: 148, height: 68 };
return { width: 156, height: 64 };
if (shape === "security") return { width: 148, height: 60 };
return { width: 156, height: 56 };
};
export const architectureNodeHeight = (shape: DiagramNodeShape, lineCount: number) => {
const baseHeight = compactArchitectureNodeSize(shape).height;
return Math.max(baseHeight, lineCount <= 1 ? 56 : lineCount === 2 ? 60 : lineCount * 17 + 20);
};
const architectureNodeSizeForLabel = (shape: DiagramNodeShape, label: string) => {
const { width } = compactArchitectureNodeSize(shape);
if (shape === "boundary") return compactArchitectureNodeSize(shape);
// Reserve space during semantic layout before the browser measures the final wrapping.
const capacity = (width - 66) / 12;
const lineCount = label.split("\n").reduce(
(count, paragraph) => count + Math.max(1, Math.ceil(visualTextUnits(paragraph) / capacity)),
0,
);
return { width, height: architectureNodeHeight(shape, lineCount) };
};
const computeMindMapLayout = (
@@ -1115,7 +1132,7 @@ export const compileDiagramIr = (ir: DiagramIr): DiagramDocument => {
const size = ir.kind === "mind-map"
? mindMapNodePresentation(node.label, mindMapNodeRole(ir.nodes, node.id), ir.structure)
: ir.kind === "architecture"
? compactArchitectureNodeSize(shape)
? architectureNodeSizeForLabel(shape, node.label)
: flowchartNodePresentation(shape, node.label);
return {
id: node.id,