@zukhruf/diagram 0.3.32 → 0.3.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -52
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/compiler/diagram-compile.d.ts +3 -4
- package/dist/lib/compiler/diagram-compile.d.ts.map +1 -1
- package/dist/lib/compiler/diagram-compile.js +85 -370
- package/dist/lib/compiler/diagram-compile.js.map +1 -1
- package/dist/lib/layouts/graph/attach.d.ts +25 -0
- package/dist/lib/layouts/graph/attach.d.ts.map +1 -0
- package/dist/lib/layouts/graph/attach.js +272 -0
- package/dist/lib/layouts/graph/attach.js.map +1 -0
- package/dist/lib/layouts/graph/connections.d.ts +45 -0
- package/dist/lib/layouts/graph/connections.d.ts.map +1 -0
- package/dist/lib/layouts/graph/connections.js +138 -0
- package/dist/lib/layouts/graph/connections.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts +5 -3
- package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -1
- package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -1
- package/dist/lib/layouts/graph/gutters.js +41 -22
- package/dist/lib/layouts/graph/gutters.js.map +1 -1
- package/dist/lib/layouts/graph/labels.d.ts +23 -0
- package/dist/lib/layouts/graph/labels.d.ts.map +1 -0
- package/dist/lib/layouts/graph/labels.js +120 -0
- package/dist/lib/layouts/graph/labels.js.map +1 -0
- package/dist/lib/layouts/graph/layout.d.ts +1 -1
- package/dist/lib/layouts/graph/layout.d.ts.map +1 -1
- package/dist/lib/layouts/graph/layout.js +37 -12
- package/dist/lib/layouts/graph/layout.js.map +1 -1
- package/dist/lib/layouts/graph/measure.d.ts +15 -11
- package/dist/lib/layouts/graph/measure.d.ts.map +1 -1
- package/dist/lib/layouts/graph/measure.js +82 -38
- package/dist/lib/layouts/graph/measure.js.map +1 -1
- package/dist/lib/layouts/graph/min-heap.d.ts +8 -0
- package/dist/lib/layouts/graph/min-heap.d.ts.map +1 -0
- package/dist/lib/layouts/graph/min-heap.js +56 -0
- package/dist/lib/layouts/graph/min-heap.js.map +1 -0
- package/dist/lib/layouts/graph/node-content.d.ts +2 -3
- package/dist/lib/layouts/graph/node-content.d.ts.map +1 -1
- package/dist/lib/layouts/graph/node-content.js +67 -47
- package/dist/lib/layouts/graph/node-content.js.map +1 -1
- package/dist/lib/layouts/graph/path.d.ts +6 -0
- package/dist/lib/layouts/graph/path.d.ts.map +1 -0
- package/dist/lib/layouts/graph/path.js +53 -0
- package/dist/lib/layouts/graph/path.js.map +1 -0
- package/dist/lib/layouts/graph/round.d.ts +11 -0
- package/dist/lib/layouts/graph/round.d.ts.map +1 -0
- package/dist/lib/layouts/graph/round.js +181 -0
- package/dist/lib/layouts/graph/round.js.map +1 -0
- package/dist/lib/layouts/graph/route-search.d.ts +34 -0
- package/dist/lib/layouts/graph/route-search.d.ts.map +1 -0
- package/dist/lib/layouts/graph/route-search.js +208 -0
- package/dist/lib/layouts/graph/route-search.js.map +1 -0
- package/dist/lib/layouts/graph/route.d.ts +20 -0
- package/dist/lib/layouts/graph/route.d.ts.map +1 -0
- package/dist/lib/layouts/graph/route.js +276 -0
- package/dist/lib/layouts/graph/route.js.map +1 -0
- package/dist/lib/layouts/graph/sides.d.ts +28 -0
- package/dist/lib/layouts/graph/sides.d.ts.map +1 -0
- package/dist/lib/layouts/graph/sides.js +98 -0
- package/dist/lib/layouts/graph/sides.js.map +1 -0
- package/dist/lib/layouts/timeline/timeline-layout.d.ts +2 -1
- package/dist/lib/layouts/timeline/timeline-layout.d.ts.map +1 -1
- package/dist/lib/layouts/timeline/timeline-layout.js +9 -4
- package/dist/lib/layouts/timeline/timeline-layout.js.map +1 -1
- package/dist/lib/model/diagram-ir.d.ts +19 -156
- package/dist/lib/model/diagram-ir.d.ts.map +1 -1
- package/dist/lib/model/diagram-ir.js.map +1 -1
- package/dist/lib/model/validate-graph.d.ts +7 -0
- package/dist/lib/model/validate-graph.d.ts.map +1 -0
- package/dist/lib/model/validate-graph.js +54 -0
- package/dist/lib/model/validate-graph.js.map +1 -0
- package/dist/lib/react/Diagram.d.ts +3 -9
- package/dist/lib/react/Diagram.d.ts.map +1 -1
- package/dist/lib/react/Diagram.js +1 -13
- package/dist/lib/react/Diagram.js.map +1 -1
- package/dist/lib/react/diagram-types.d.ts +17 -46
- package/dist/lib/react/diagram-types.d.ts.map +1 -1
- package/dist/lib/react/diagram-types.js.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.d.ts +2 -5
- package/dist/lib/renderers/canvas/graph-canvas.d.ts.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.js +68 -43
- package/dist/lib/renderers/canvas/graph-canvas.js.map +1 -1
- package/dist/lib/renderers/html/graph-html.d.ts +2 -3
- package/dist/lib/renderers/html/graph-html.d.ts.map +1 -1
- package/dist/lib/renderers/html/graph-html.js +298 -289
- package/dist/lib/renderers/html/graph-html.js.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.d.ts +3 -1
- package/dist/lib/renderers/shared/graph-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.js +350 -418
- package/dist/lib/renderers/shared/graph-parts.js.map +1 -1
- package/dist/lib/renderers/shared/node-parts.d.ts +5 -6
- package/dist/lib/renderers/shared/node-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/node-parts.js +112 -190
- package/dist/lib/renderers/shared/node-parts.js.map +1 -1
- package/dist/lib/renderers/shared/run-spans.js +2 -2
- package/dist/lib/renderers/shared/run-spans.js.map +1 -1
- package/dist/lib/renderers/shared/text-runs.d.ts +0 -6
- package/dist/lib/renderers/shared/text-runs.d.ts.map +1 -1
- package/dist/lib/renderers/shared/text-runs.js +0 -12
- package/dist/lib/renderers/shared/text-runs.js.map +1 -1
- package/dist/lib/renderers/svg/graph-svg.d.ts +1 -3
- package/dist/lib/renderers/svg/graph-svg.d.ts.map +1 -1
- package/dist/lib/renderers/svg/graph-svg.js +66 -80
- package/dist/lib/renderers/svg/graph-svg.js.map +1 -1
- package/dist/lib/renderers/svg/timeline-svg.d.ts.map +1 -1
- package/dist/lib/renderers/svg/timeline-svg.js +7 -5
- package/dist/lib/renderers/svg/timeline-svg.js.map +1 -1
- package/package.json +1 -1
- package/dist/lib/layouts/graph/graph-layout.d.ts +0 -154
- package/dist/lib/layouts/graph/graph-layout.d.ts.map +0 -1
- package/dist/lib/layouts/graph/graph-layout.js +0 -2340
- package/dist/lib/layouts/graph/graph-layout.js.map +0 -1
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts +0 -6
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts.map +0 -1
- package/dist/lib/layouts/graph/legacy-graph-layout.js +0 -542
- package/dist/lib/layouts/graph/legacy-graph-layout.js.map +0 -1
- package/dist/lib/layouts/text-metrics.d.ts +0 -7
- package/dist/lib/layouts/text-metrics.d.ts.map +0 -1
- package/dist/lib/layouts/text-metrics.js +0 -40
- package/dist/lib/layouts/text-metrics.js.map +0 -1
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { validateGraph } from "../../model/validate-graph.js";
|
|
1
2
|
import { gridAreas } from "./areas.js";
|
|
2
3
|
import { gridGutters } from "./gutters.js";
|
|
3
|
-
import { measureGroupTitle, measureNode } from "./measure.js";
|
|
4
|
+
import { measureGroupTitle, measureNode, placeGroupPorts } from "./measure.js";
|
|
5
|
+
import { roundLayout } from "./round.js";
|
|
6
|
+
import { routeGraph } from "./route.js";
|
|
4
7
|
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
5
8
|
import { sizeTracks } from "./tracks.js";
|
|
6
9
|
|
|
@@ -8,11 +11,12 @@ import { sizeTracks } from "./tracks.js";
|
|
|
8
11
|
* Lays out a graph on a content-sized grid: it measures every node, sizes
|
|
9
12
|
* each row and column to the content in it, and reserves the chrome of the
|
|
10
13
|
* groups in the gutters between them. It throws when the grid cannot be
|
|
11
|
-
* drawn without overlap.
|
|
14
|
+
* drawn without overlap, or when an id or an edge end is wrong.
|
|
12
15
|
*/
|
|
13
16
|
export function layoutGraph(ir) {
|
|
14
|
-
|
|
15
|
-
const
|
|
17
|
+
validateGraph(ir);
|
|
18
|
+
const measured = new Map(ir.nodes.map(node => [node.id, measureNode(node)]));
|
|
19
|
+
const titles = new Map(ir.groups.map(group => [group.id, measureGroupTitle(group)]));
|
|
16
20
|
const areas = gridAreas(ir);
|
|
17
21
|
const gutters = gridGutters(areas, new Map([...titles].map(([id, title]) => [id, title.height])), ir.edges);
|
|
18
22
|
const items = axis => ir.nodes.map(node => {
|
|
@@ -45,13 +49,18 @@ export function layoutGraph(ir) {
|
|
|
45
49
|
};
|
|
46
50
|
});
|
|
47
51
|
const groups = areas.groups.map(groupArea => placeGroup(groupArea, titles.get(groupArea.group.id), lines, gutters));
|
|
48
|
-
|
|
52
|
+
const widestGutter = Math.max(...[...gutters.row, ...gutters.col].map(gutter => gutter.size));
|
|
53
|
+
const {
|
|
54
|
+
edges,
|
|
55
|
+
leaders
|
|
56
|
+
} = routeGraph(ir, nodes, groups, areas, 2 * widestGutter);
|
|
57
|
+
return roundLayout({
|
|
49
58
|
nodes,
|
|
50
59
|
groups,
|
|
51
|
-
edges
|
|
52
|
-
leaders
|
|
53
|
-
viewBox: viewBoxOf(nodes, groups)
|
|
54
|
-
};
|
|
60
|
+
edges,
|
|
61
|
+
leaders,
|
|
62
|
+
viewBox: viewBoxOf(nodes, groups, edges, leaders)
|
|
63
|
+
});
|
|
55
64
|
}
|
|
56
65
|
function areaBox(area, lines) {
|
|
57
66
|
const x = lines.col.trackStart(area.col);
|
|
@@ -108,7 +117,8 @@ function placeGroup({
|
|
|
108
117
|
depth,
|
|
109
118
|
rect,
|
|
110
119
|
...title.place(rect),
|
|
111
|
-
dividers: group.dividers ? dividers(rect, area, title, group.labelSide, lines, gutters) : []
|
|
120
|
+
dividers: group.dividers ? dividers(rect, area, title, group.labelSide, lines, gutters) : [],
|
|
121
|
+
ports: placeGroupPorts(group.ports ?? [], rect)
|
|
112
122
|
};
|
|
113
123
|
}
|
|
114
124
|
|
|
@@ -141,8 +151,23 @@ function dividers(rect, area, title, labelSide, lines, gutters) {
|
|
|
141
151
|
}];
|
|
142
152
|
})];
|
|
143
153
|
}
|
|
144
|
-
function viewBoxOf(nodes, groups) {
|
|
145
|
-
const
|
|
154
|
+
function viewBoxOf(nodes, groups, edges, leaders) {
|
|
155
|
+
const pointBox = ({
|
|
156
|
+
x,
|
|
157
|
+
y
|
|
158
|
+
}) => ({
|
|
159
|
+
x,
|
|
160
|
+
y,
|
|
161
|
+
w: 0,
|
|
162
|
+
h: 0
|
|
163
|
+
});
|
|
164
|
+
const boxes = [...nodes.map(nodeLayout => nodeLayout.visual), ...groups.map(groupLayout => groupLayout.rect), ...edges.flatMap(({
|
|
165
|
+
points,
|
|
166
|
+
label,
|
|
167
|
+
badge
|
|
168
|
+
}) => [...points.map(pointBox), ...(label ? [label.box] : []), ...(badge ? [badge.box] : [])]), ...leaders.flatMap(({
|
|
169
|
+
points
|
|
170
|
+
}) => points.map(pointBox))];
|
|
146
171
|
const pad = LAYOUT_TOKENS.CONTENT_PAD;
|
|
147
172
|
if (boxes.length === 0) return {
|
|
148
173
|
x: -pad,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","names":["gridAreas","gridGutters","measureGroupTitle","measureNode","LAYOUT_TOKENS","sizeTracks","layoutGraph","ir","measured","Map","nodes","map","node","id","titles","groups","group","areas","gutters","title","height","edges","items","axis","area","get","frame","overhang","start","row","span","rowSpan","size","h","top","bottom","col","colSpan","w","left","right","line","count","gutter","lines","rows","cols","measuredNode","areaBox","place","nodeFrame","groupArea","placeGroup","leaders","viewBox","viewBoxOf","x","trackStart","y","trackEnd","stretch","visualW","visualH","depth","border","boundary","side","gutterStart","rect","dividers","labelSide","centre","titleAtBottom","inner","Array","from","length","_","index","boxes","nodeLayout","visual","groupLayout","pad","CONTENT_PAD","Math","min","box","max"],"sources":["../../../../src/lib/layouts/graph/layout.ts"],"sourcesContent":["import type { Box, DiagramGraphIR, Point } from '../../model/diagram-ir.ts';\nimport { type CellArea, type GroupArea, gridAreas } from './areas.ts';\nimport type {\n GraphLayout,\n GroupLayout,\n NodeLayout,\n} from './graph-layout-result.ts';\nimport { type Axis, type GridGutters, gridGutters } from './gutters.ts';\nimport {\n type MeasuredGroupTitle,\n type MeasuredNode,\n measureGroupTitle,\n measureNode,\n} from './measure.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\nimport { type TrackLine, sizeTracks } from './tracks.ts';\n\n/**\n * Lays out a graph on a content-sized grid: it measures every node, sizes\n * each row and column to the content in it, and reserves the chrome of the\n * groups in the gutters between them. It throws when the grid cannot be\n * drawn without overlap.\n */\nexport function layoutGraph(ir: DiagramGraphIR): GraphLayout {\n const measured = new Map(\n ir.nodes.map(\n (node) => [node.id, measureNode(node, LAYOUT_TOKENS)] as const,\n ),\n );\n const titles = new Map(\n ir.groups.map(\n (group) => [group.id, measureGroupTitle(group, LAYOUT_TOKENS)] as const,\n ),\n );\n const areas = gridAreas(ir);\n const gutters = gridGutters(\n areas,\n new Map([...titles].map(([id, title]) => [id, title.height])),\n ir.edges,\n );\n\n const items = (axis: Axis) =>\n ir.nodes.map((node) => {\n const area = areas.nodes.get(node.id)!;\n const { frame, overhang } = measured.get(node.id)!;\n return axis === 'row'\n ? {\n start: area.row,\n span: area.rowSpan,\n size: frame.h + overhang.top + overhang.bottom,\n }\n : {\n start: area.col,\n span: area.colSpan,\n size: frame.w + overhang.left + overhang.right,\n };\n });\n const line = (axis: Axis, count: number) =>\n sizeTracks(\n count,\n items(axis),\n gutters[axis].map((gutter) => gutter.size),\n );\n const lines: Record<Axis, TrackLine> = {\n row: line('row', areas.rows),\n col: line('col', areas.cols),\n };\n\n const nodes: NodeLayout[] = ir.nodes.map((node) => {\n const measuredNode = measured.get(node.id)!;\n const area = areaBox(areas.nodes.get(node.id)!, lines);\n return { node, ...measuredNode.place(nodeFrame(measuredNode, area)) };\n });\n const groups = areas.groups.map((groupArea) =>\n placeGroup(groupArea, titles.get(groupArea.group.id)!, lines, gutters),\n );\n\n return {\n nodes,\n groups,\n edges: [],\n leaders: [],\n viewBox: viewBoxOf(nodes, groups),\n };\n}\n\nfunction areaBox(area: CellArea, lines: Record<Axis, TrackLine>): Box {\n const x = lines.col.trackStart(area.col);\n const y = lines.row.trackStart(area.row);\n return {\n x,\n y,\n w: lines.col.trackEnd(area.col + area.colSpan - 1) - x,\n h: lines.row.trackEnd(area.row + area.rowSpan - 1) - y,\n };\n}\n\n/** A stretching node fills its area; any other node keeps its measured frame, centred in the area. */\nfunction nodeFrame(measured: MeasuredNode, area: Box): Box {\n const { frame, overhang, stretch } = measured;\n if (stretch) {\n return {\n x: area.x + overhang.left,\n y: area.y + overhang.top,\n w: area.w - overhang.left - overhang.right,\n h: area.h - overhang.top - overhang.bottom,\n };\n }\n const visualW = frame.w + overhang.left + overhang.right;\n const visualH = frame.h + overhang.top + overhang.bottom;\n return {\n x: area.x + (area.w - visualW) / 2 + overhang.left,\n y: area.y + (area.h - visualH) / 2 + overhang.top,\n ...frame,\n };\n}\n\n/** Each side of a group lies on the outer edge of its chrome slot in the gutter where the group opens or closes. */\nfunction placeGroup(\n { group, depth, area }: GroupArea,\n title: MeasuredGroupTitle,\n lines: Record<Axis, TrackLine>,\n gutters: GridGutters,\n): GroupLayout {\n const border = (axis: Axis, boundary: number, side: 'opening' | 'closing') =>\n lines[axis].gutterStart(boundary) +\n gutters[axis][boundary]![side].get(depth)!;\n const x = border('col', area.col, 'opening');\n const y = border('row', area.row, 'opening');\n const rect = {\n x,\n y,\n w: border('col', area.col + area.colSpan, 'closing') - x,\n h: border('row', area.row + area.rowSpan, 'closing') - y,\n };\n return {\n group,\n depth,\n rect,\n ...title.place(rect),\n dividers: group.dividers\n ? dividers(rect, area, title, group.labelSide, lines, gutters)\n : [],\n };\n}\n\n/** A line through the middle of every gutter inside the group, clear of its title. */\nfunction dividers(\n rect: Box,\n area: CellArea,\n title: MeasuredGroupTitle,\n labelSide: 'top' | 'bottom' | undefined,\n lines: Record<Axis, TrackLine>,\n gutters: GridGutters,\n): [Point, Point][] {\n const centre = (axis: Axis, boundary: number) =>\n lines[axis].gutterStart(boundary) + gutters[axis][boundary]!.size / 2;\n const titleAtBottom = labelSide === 'bottom';\n const top = rect.y + (titleAtBottom ? 0 : title.height);\n const bottom = rect.y + rect.h - (titleAtBottom ? title.height : 0);\n const inner = (start: number, span: number) =>\n Array.from({ length: span - 1 }, (_, index) => start + index + 1);\n return [\n ...inner(area.col, area.colSpan).map((boundary): [Point, Point] => {\n const x = centre('col', boundary);\n return [\n { x, y: top },\n { x, y: bottom },\n ];\n }),\n ...inner(area.row, area.rowSpan).map((boundary): [Point, Point] => {\n const y = centre('row', boundary);\n return [\n { x: rect.x, y },\n { x: rect.x + rect.w, y },\n ];\n }),\n ];\n}\n\nfunction viewBoxOf(nodes: NodeLayout[], groups: GroupLayout[]): Box {\n const boxes = [\n ...nodes.map((nodeLayout) => nodeLayout.visual),\n ...groups.map((groupLayout) => groupLayout.rect),\n ];\n const pad = LAYOUT_TOKENS.CONTENT_PAD;\n if (boxes.length === 0) return { x: -pad, y: -pad, w: 2 * pad, h: 2 * pad };\n const left = Math.min(...boxes.map((box) => box.x));\n const top = Math.min(...boxes.map((box) => box.y));\n const right = Math.max(...boxes.map((box) => box.x + box.w));\n const bottom = Math.max(...boxes.map((box) => box.y + box.h));\n return {\n x: left - pad,\n y: top - pad,\n w: right - left + 2 * pad,\n h: bottom - top + 2 * pad,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"layout.js","names":["validateGraph","gridAreas","gridGutters","measureGroupTitle","measureNode","placeGroupPorts","roundLayout","routeGraph","LAYOUT_TOKENS","sizeTracks","layoutGraph","ir","measured","Map","nodes","map","node","id","titles","groups","group","areas","gutters","title","height","edges","items","axis","area","get","frame","overhang","start","row","span","rowSpan","size","h","top","bottom","col","colSpan","w","left","right","line","count","gutter","lines","rows","cols","measuredNode","areaBox","place","nodeFrame","groupArea","placeGroup","widestGutter","Math","max","leaders","viewBox","viewBoxOf","x","trackStart","y","trackEnd","stretch","visualW","visualH","depth","border","boundary","side","gutterStart","rect","dividers","labelSide","ports","centre","titleAtBottom","inner","Array","from","length","_","index","pointBox","boxes","nodeLayout","visual","groupLayout","flatMap","points","label","badge","box","pad","CONTENT_PAD","min"],"sources":["../../../../src/lib/layouts/graph/layout.ts"],"sourcesContent":["import type { Box, DiagramGraphIR, Point } from '../../model/diagram-ir.ts';\nimport { validateGraph } from '../../model/validate-graph.ts';\nimport { type CellArea, type GroupArea, gridAreas } from './areas.ts';\nimport type {\n GraphLayout,\n GroupLayout,\n NodeLayout,\n} from './graph-layout-result.ts';\nimport { type Axis, type GridGutters, gridGutters } from './gutters.ts';\nimport {\n type MeasuredGroupTitle,\n type MeasuredNode,\n measureGroupTitle,\n measureNode,\n placeGroupPorts,\n} from './measure.ts';\nimport { roundLayout } from './round.ts';\nimport { type RoutedGraph, routeGraph } from './route.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\nimport { type TrackLine, sizeTracks } from './tracks.ts';\n\n/**\n * Lays out a graph on a content-sized grid: it measures every node, sizes\n * each row and column to the content in it, and reserves the chrome of the\n * groups in the gutters between them. It throws when the grid cannot be\n * drawn without overlap, or when an id or an edge end is wrong.\n */\nexport function layoutGraph(ir: DiagramGraphIR): GraphLayout {\n validateGraph(ir);\n const measured = new Map(\n ir.nodes.map((node) => [node.id, measureNode(node)] as const),\n );\n const titles = new Map(\n ir.groups.map((group) => [group.id, measureGroupTitle(group)] as const),\n );\n const areas = gridAreas(ir);\n const gutters = gridGutters(\n areas,\n new Map([...titles].map(([id, title]) => [id, title.height])),\n ir.edges,\n );\n\n const items = (axis: Axis) =>\n ir.nodes.map((node) => {\n const area = areas.nodes.get(node.id)!;\n const { frame, overhang } = measured.get(node.id)!;\n return axis === 'row'\n ? {\n start: area.row,\n span: area.rowSpan,\n size: frame.h + overhang.top + overhang.bottom,\n }\n : {\n start: area.col,\n span: area.colSpan,\n size: frame.w + overhang.left + overhang.right,\n };\n });\n const line = (axis: Axis, count: number) =>\n sizeTracks(\n count,\n items(axis),\n gutters[axis].map((gutter) => gutter.size),\n );\n const lines: Record<Axis, TrackLine> = {\n row: line('row', areas.rows),\n col: line('col', areas.cols),\n };\n\n const nodes: NodeLayout[] = ir.nodes.map((node) => {\n const measuredNode = measured.get(node.id)!;\n const area = areaBox(areas.nodes.get(node.id)!, lines);\n return { node, ...measuredNode.place(nodeFrame(measuredNode, area)) };\n });\n const groups = areas.groups.map((groupArea) =>\n placeGroup(groupArea, titles.get(groupArea.group.id)!, lines, gutters),\n );\n\n const widestGutter = Math.max(\n ...[...gutters.row, ...gutters.col].map((gutter) => gutter.size),\n );\n const { edges, leaders } = routeGraph(\n ir,\n nodes,\n groups,\n areas,\n 2 * widestGutter,\n );\n\n return roundLayout({\n nodes,\n groups,\n edges,\n leaders,\n viewBox: viewBoxOf(nodes, groups, edges, leaders),\n });\n}\n\nfunction areaBox(area: CellArea, lines: Record<Axis, TrackLine>): Box {\n const x = lines.col.trackStart(area.col);\n const y = lines.row.trackStart(area.row);\n return {\n x,\n y,\n w: lines.col.trackEnd(area.col + area.colSpan - 1) - x,\n h: lines.row.trackEnd(area.row + area.rowSpan - 1) - y,\n };\n}\n\n/** A stretching node fills its area; any other node keeps its measured frame, centred in the area. */\nfunction nodeFrame(measured: MeasuredNode, area: Box): Box {\n const { frame, overhang, stretch } = measured;\n if (stretch) {\n return {\n x: area.x + overhang.left,\n y: area.y + overhang.top,\n w: area.w - overhang.left - overhang.right,\n h: area.h - overhang.top - overhang.bottom,\n };\n }\n const visualW = frame.w + overhang.left + overhang.right;\n const visualH = frame.h + overhang.top + overhang.bottom;\n return {\n x: area.x + (area.w - visualW) / 2 + overhang.left,\n y: area.y + (area.h - visualH) / 2 + overhang.top,\n ...frame,\n };\n}\n\n/** Each side of a group lies on the outer edge of its chrome slot in the gutter where the group opens or closes. */\nfunction placeGroup(\n { group, depth, area }: GroupArea,\n title: MeasuredGroupTitle,\n lines: Record<Axis, TrackLine>,\n gutters: GridGutters,\n): GroupLayout {\n const border = (axis: Axis, boundary: number, side: 'opening' | 'closing') =>\n lines[axis].gutterStart(boundary) +\n gutters[axis][boundary]![side].get(depth)!;\n const x = border('col', area.col, 'opening');\n const y = border('row', area.row, 'opening');\n const rect = {\n x,\n y,\n w: border('col', area.col + area.colSpan, 'closing') - x,\n h: border('row', area.row + area.rowSpan, 'closing') - y,\n };\n return {\n group,\n depth,\n rect,\n ...title.place(rect),\n dividers: group.dividers\n ? dividers(rect, area, title, group.labelSide, lines, gutters)\n : [],\n ports: placeGroupPorts(group.ports ?? [], rect),\n };\n}\n\n/** A line through the middle of every gutter inside the group, clear of its title. */\nfunction dividers(\n rect: Box,\n area: CellArea,\n title: MeasuredGroupTitle,\n labelSide: 'top' | 'bottom' | undefined,\n lines: Record<Axis, TrackLine>,\n gutters: GridGutters,\n): [Point, Point][] {\n const centre = (axis: Axis, boundary: number) =>\n lines[axis].gutterStart(boundary) + gutters[axis][boundary]!.size / 2;\n const titleAtBottom = labelSide === 'bottom';\n const top = rect.y + (titleAtBottom ? 0 : title.height);\n const bottom = rect.y + rect.h - (titleAtBottom ? title.height : 0);\n const inner = (start: number, span: number) =>\n Array.from({ length: span - 1 }, (_, index) => start + index + 1);\n return [\n ...inner(area.col, area.colSpan).map((boundary): [Point, Point] => {\n const x = centre('col', boundary);\n return [\n { x, y: top },\n { x, y: bottom },\n ];\n }),\n ...inner(area.row, area.rowSpan).map((boundary): [Point, Point] => {\n const y = centre('row', boundary);\n return [\n { x: rect.x, y },\n { x: rect.x + rect.w, y },\n ];\n }),\n ];\n}\n\nfunction viewBoxOf(\n nodes: NodeLayout[],\n groups: GroupLayout[],\n edges: RoutedGraph['edges'],\n leaders: RoutedGraph['leaders'],\n): Box {\n const pointBox = ({ x, y }: Point): Box => ({ x, y, w: 0, h: 0 });\n const boxes = [\n ...nodes.map((nodeLayout) => nodeLayout.visual),\n ...groups.map((groupLayout) => groupLayout.rect),\n ...edges.flatMap(({ points, label, badge }) => [\n ...points.map(pointBox),\n ...(label ? [label.box] : []),\n ...(badge ? [badge.box] : []),\n ]),\n ...leaders.flatMap(({ points }) => points.map(pointBox)),\n ];\n const pad = LAYOUT_TOKENS.CONTENT_PAD;\n if (boxes.length === 0) return { x: -pad, y: -pad, w: 2 * pad, h: 2 * pad };\n const left = Math.min(...boxes.map((box) => box.x));\n const top = Math.min(...boxes.map((box) => box.y));\n const right = Math.max(...boxes.map((box) => box.x + box.w));\n const bottom = Math.max(...boxes.map((box) => box.y + box.h));\n return {\n x: left - pad,\n y: top - pad,\n w: right - left + 2 * pad,\n h: bottom - top + 2 * pad,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Box, DiagramEdge, DiagramGroup, DiagramNode, DiagramSide } from '../../model/diagram-ir.ts';
|
|
2
|
-
import type { NodeLayout, TextRun } from './graph-layout-result.ts';
|
|
3
|
-
import type { LayoutTokens } from './tokens.ts';
|
|
1
|
+
import type { Box, DiagramEdge, DiagramGroup, DiagramNode, DiagramNodePort, DiagramSide } from '../../model/diagram-ir.ts';
|
|
2
|
+
import type { GroupLayout, NodeLayout, TextRun } from './graph-layout-result.ts';
|
|
4
3
|
type Sides = Record<DiagramSide, number>;
|
|
5
4
|
export type MeasuredNode = {
|
|
6
5
|
/** The smallest frame that holds the node's content. */
|
|
@@ -15,22 +14,21 @@ export type MeasuredNode = {
|
|
|
15
14
|
/** Positions everything the node draws, given its final frame (at least `frame`). */
|
|
16
15
|
place(box: Box): Omit<NodeLayout, 'node'>;
|
|
17
16
|
};
|
|
18
|
-
export declare function measureNode(node: DiagramNode
|
|
17
|
+
export declare function measureNode(node: DiagramNode): MeasuredNode;
|
|
18
|
+
/** A group's ports sit evenly along their side of its rect, like a node's ports along its frame. */
|
|
19
|
+
export declare function placeGroupPorts(ports: DiagramNodePort[], rect: Box): NodeLayout['ports'];
|
|
19
20
|
export type MeasuredGroupTitle = {
|
|
20
21
|
/** The height the title reserves on its side, BAND_PAD above and below included; 0 without a label. */
|
|
21
22
|
height: number;
|
|
22
|
-
place(rect: Box):
|
|
23
|
-
band?: Box;
|
|
24
|
-
label: TextRun[];
|
|
25
|
-
};
|
|
23
|
+
place(rect: Box): Pick<GroupLayout, 'band' | 'separator' | 'label'>;
|
|
26
24
|
};
|
|
27
|
-
export declare function measureGroupTitle(group: DiagramGroup
|
|
25
|
+
export declare function measureGroupTitle(group: DiagramGroup): MeasuredGroupTitle;
|
|
28
26
|
export type MeasuredEdgeLabel = {
|
|
29
27
|
w: number;
|
|
30
28
|
h: number;
|
|
31
29
|
place(box: Box): TextRun[];
|
|
32
30
|
};
|
|
33
|
-
export declare function measureEdgeLabel(edge: DiagramEdge
|
|
31
|
+
export declare function measureEdgeLabel(edge: DiagramEdge): MeasuredEdgeLabel;
|
|
34
32
|
export type MeasuredEdgeBadge = {
|
|
35
33
|
w: number;
|
|
36
34
|
h: number;
|
|
@@ -39,6 +37,12 @@ export type MeasuredEdgeBadge = {
|
|
|
39
37
|
text: TextRun[];
|
|
40
38
|
};
|
|
41
39
|
};
|
|
42
|
-
export declare function measureEdgeBadge(edge: DiagramEdge
|
|
40
|
+
export declare function measureEdgeBadge(edge: DiagramEdge): MeasuredEdgeBadge;
|
|
41
|
+
export type MeasuredEdgeTags = {
|
|
42
|
+
label?: MeasuredEdgeLabel;
|
|
43
|
+
badge?: MeasuredEdgeBadge;
|
|
44
|
+
};
|
|
45
|
+
/** What an edge carries along its route: a label beside it and a badge on it, each only when the edge has one. */
|
|
46
|
+
export declare function measureEdgeTags(edge: DiagramEdge): MeasuredEdgeTags;
|
|
43
47
|
export {};
|
|
44
48
|
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,GAAG,EACH,WAAW,EACX,YAAY,EACZ,WAAW,
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,GAAG,EACH,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,OAAO,EACR,MAAM,0BAA0B,CAAC;AAKlC,KAAK,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB,wDAAwD;IACxD,KAAK,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,0EAA0E;IAC1E,QAAQ,EAAE,KAAK,CAAC;IAChB,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;CAC3C,CAAC;AAWF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,CA8D3D;AAsGD,oGAAoG;AACpG,wBAAgB,eAAe,CAC7B,KAAK,EAAE,eAAe,EAAE,EACxB,IAAI,EAAE,GAAG,GACR,UAAU,CAAC,OAAO,CAAC,CAErB;AAsGD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,uGAAuG;IACvG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,CAAC;CACrE,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,kBAAkB,CAkCzE;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,EAAE,CAAC;CAC5B,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAWrE;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;CAClD,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAoBrE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,kHAAkH;AAClH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,gBAAgB,CAOnE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { nodeContent } from "./node-content.js";
|
|
2
2
|
import { labelLines, textBlock } from "./text-block.js";
|
|
3
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
3
4
|
/** The distance from a port's point to its label: the port marker's radius plus a gap. */
|
|
4
5
|
const PORT_LABEL_OFFSET = 8;
|
|
5
6
|
const EDGE_LABEL_FRAME_PAD = 4;
|
|
@@ -10,11 +11,11 @@ const BADGE_PAD = {
|
|
|
10
11
|
};
|
|
11
12
|
const BADGE_MIN_CONTENT = 24;
|
|
12
13
|
const SIDES = ['top', 'right', 'bottom', 'left'];
|
|
13
|
-
export function measureNode(node
|
|
14
|
+
export function measureNode(node) {
|
|
14
15
|
const kind = node.kind ?? 'node';
|
|
15
16
|
if (node.hidden && kind === 'node') return hiddenNode();
|
|
16
|
-
const content = nodeContent(node
|
|
17
|
-
const ports = portGeometry(node.ports ?? []
|
|
17
|
+
const content = nodeContent(node);
|
|
18
|
+
const ports = portGeometry(node.ports ?? []);
|
|
18
19
|
const w = Math.max(content.w + 2 * content.pad.x + ports.inset.left + ports.inset.right, ports.minLength.top, ports.minLength.bottom);
|
|
19
20
|
const h = Math.max(content.h + 2 * content.pad.y + ports.inset.top + ports.inset.bottom, ports.minLength.left, ports.minLength.right);
|
|
20
21
|
const place = box => {
|
|
@@ -24,13 +25,13 @@ export function measureNode(node, tokens) {
|
|
|
24
25
|
left: content.pad.x,
|
|
25
26
|
right: content.pad.x
|
|
26
27
|
});
|
|
27
|
-
const frames = stackFrames(node, box
|
|
28
|
-
const caption = placeCaption(node, union([box, ...frames])
|
|
28
|
+
const frames = stackFrames(node, box);
|
|
29
|
+
const caption = placeCaption(node, union([box, ...frames]));
|
|
29
30
|
return {
|
|
30
31
|
box,
|
|
31
32
|
visual: union([box, ...frames, ...(caption ? [caption.box] : [])]),
|
|
32
33
|
frames,
|
|
33
|
-
radius: frameRadius(node, box
|
|
34
|
+
radius: frameRadius(node, box),
|
|
34
35
|
...content.place(inner),
|
|
35
36
|
...(caption ? {
|
|
36
37
|
caption
|
|
@@ -39,25 +40,43 @@ export function measureNode(node, tokens) {
|
|
|
39
40
|
};
|
|
40
41
|
};
|
|
41
42
|
const {
|
|
42
|
-
visual
|
|
43
|
+
visual,
|
|
44
|
+
frames
|
|
43
45
|
} = place({
|
|
44
46
|
x: 0,
|
|
45
47
|
y: 0,
|
|
46
48
|
w,
|
|
47
49
|
h
|
|
48
50
|
});
|
|
51
|
+
const outside = outer => ({
|
|
52
|
+
top: 0 - outer.y,
|
|
53
|
+
left: 0 - outer.x,
|
|
54
|
+
bottom: outer.y + outer.h - h,
|
|
55
|
+
right: outer.x + outer.w - w
|
|
56
|
+
});
|
|
57
|
+
const stack = outside(union([{
|
|
58
|
+
x: 0,
|
|
59
|
+
y: 0,
|
|
60
|
+
w,
|
|
61
|
+
h
|
|
62
|
+
}, ...frames]));
|
|
63
|
+
const all = outside(visual);
|
|
64
|
+
// A caption reserves its room on both sides of the frame, so the frames of a row (or column) stay on one centre line whichever side their captions hang.
|
|
65
|
+
const caption = (a, b) => Math.max(all[a] - stack[a], all[b] - stack[b]);
|
|
66
|
+
const vertical = caption('top', 'bottom');
|
|
67
|
+
const horizontal = caption('left', 'right');
|
|
49
68
|
return {
|
|
50
69
|
frame: {
|
|
51
70
|
w,
|
|
52
71
|
h
|
|
53
72
|
},
|
|
54
73
|
overhang: {
|
|
55
|
-
top:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
right:
|
|
74
|
+
top: stack.top + vertical,
|
|
75
|
+
bottom: stack.bottom + vertical,
|
|
76
|
+
left: stack.left + horizontal,
|
|
77
|
+
right: stack.right + horizontal
|
|
59
78
|
},
|
|
60
|
-
stretch: kind === 'node'
|
|
79
|
+
stretch: kind === 'node',
|
|
61
80
|
place
|
|
62
81
|
};
|
|
63
82
|
}
|
|
@@ -85,7 +104,7 @@ function hiddenNode() {
|
|
|
85
104
|
})
|
|
86
105
|
};
|
|
87
106
|
}
|
|
88
|
-
function frameRadius(node, box
|
|
107
|
+
function frameRadius(node, box) {
|
|
89
108
|
switch (node.kind) {
|
|
90
109
|
case 'connector':
|
|
91
110
|
return box.h / 2;
|
|
@@ -97,7 +116,7 @@ function frameRadius(node, box, tokens) {
|
|
|
97
116
|
return 0;
|
|
98
117
|
default:
|
|
99
118
|
if (node.frame === 'none') return 0;
|
|
100
|
-
return node.frame === 'flat' ?
|
|
119
|
+
return node.frame === 'flat' ? LAYOUT_TOKENS.FLAT_RADIUS : LAYOUT_TOKENS.RADIUS;
|
|
101
120
|
}
|
|
102
121
|
}
|
|
103
122
|
|
|
@@ -106,8 +125,8 @@ function frameRadius(node, box, tokens) {
|
|
|
106
125
|
* side's labels push the content inward, and a side with k ports is long
|
|
107
126
|
* enough for k + 1 port spacings.
|
|
108
127
|
*/
|
|
109
|
-
function portGeometry(ports
|
|
110
|
-
const font =
|
|
128
|
+
function portGeometry(ports) {
|
|
129
|
+
const font = LAYOUT_TOKENS.fonts.portLabel;
|
|
111
130
|
const bySide = new Map(SIDES.map(side => [side, ports.filter(port => port.side === side).map(port => ({
|
|
112
131
|
port,
|
|
113
132
|
label: port.label ? textBlock(labelLines(port.label, port.accent ? 'accent' : undefined), font) : undefined
|
|
@@ -126,7 +145,7 @@ function portGeometry(ports, tokens) {
|
|
|
126
145
|
const count = bySide.get(side).length;
|
|
127
146
|
if (count === 0) return 0;
|
|
128
147
|
const labelLength = side === 'top' || side === 'bottom' ? widest(side) : tallest(side);
|
|
129
|
-
const pitch = Math.max(
|
|
148
|
+
const pitch = Math.max(LAYOUT_TOKENS.PORT_SPACING, labelLength + LAYOUT_TOKENS.LABEL_GAP);
|
|
130
149
|
return (count + 1) * pitch;
|
|
131
150
|
};
|
|
132
151
|
return {
|
|
@@ -154,6 +173,11 @@ function portGeometry(ports, tokens) {
|
|
|
154
173
|
};
|
|
155
174
|
}
|
|
156
175
|
|
|
176
|
+
/** A group's ports sit evenly along their side of its rect, like a node's ports along its frame. */
|
|
177
|
+
export function placeGroupPorts(ports, rect) {
|
|
178
|
+
return portGeometry(ports).place(rect);
|
|
179
|
+
}
|
|
180
|
+
|
|
157
181
|
/** The point `fraction` of the way along `side` of `box`. */
|
|
158
182
|
function portPoint(box, side, fraction) {
|
|
159
183
|
switch (side) {
|
|
@@ -193,13 +217,13 @@ function placePortLabel(label, point, side) {
|
|
|
193
217
|
}
|
|
194
218
|
|
|
195
219
|
/** The back frames of a stack, farthest first, each one STACK_STEP further in the stack direction. */
|
|
196
|
-
function stackFrames(node, box
|
|
220
|
+
function stackFrames(node, box) {
|
|
197
221
|
const count = Math.max(1, Math.floor(node.stack ?? 1));
|
|
198
222
|
const kind = node.kind ?? 'node';
|
|
199
223
|
if (count === 1 || kind !== 'node' || node.frame === 'none') return [];
|
|
200
224
|
const direction = node.stackDirection ?? 'up-left';
|
|
201
|
-
const dx = (direction.endsWith('left') ? -1 : 1) *
|
|
202
|
-
const dy = (direction.startsWith('up') ? -1 : 1) *
|
|
225
|
+
const dx = (direction.endsWith('left') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.x;
|
|
226
|
+
const dy = (direction.startsWith('up') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.y;
|
|
203
227
|
return Array.from({
|
|
204
228
|
length: count - 1
|
|
205
229
|
}, (_, index) => {
|
|
@@ -213,8 +237,8 @@ function stackFrames(node, box, tokens) {
|
|
|
213
237
|
}
|
|
214
238
|
|
|
215
239
|
/** The caption sits beside `box`, the frame together with its stacked back frames. */
|
|
216
|
-
function placeCaption(node, box
|
|
217
|
-
const font =
|
|
240
|
+
function placeCaption(node, box) {
|
|
241
|
+
const font = LAYOUT_TOKENS.fonts.caption;
|
|
218
242
|
const lines = textBlock(labelLines([node.caption ?? []].flat().map(line => line.trim()), node.captionColor), font);
|
|
219
243
|
if (lines.h === 0) return undefined;
|
|
220
244
|
const framed = node.captionFrame ?? false;
|
|
@@ -227,7 +251,7 @@ function placeCaption(node, box, tokens) {
|
|
|
227
251
|
};
|
|
228
252
|
const w = lines.w + 2 * pad.x;
|
|
229
253
|
const h = lines.h + 2 * pad.y;
|
|
230
|
-
const gap =
|
|
254
|
+
const gap = LAYOUT_TOKENS.CAPTION_GAP;
|
|
231
255
|
const side = node.captionSide ?? 'bottom';
|
|
232
256
|
const centreX = box.x + (box.w - w) / 2;
|
|
233
257
|
const centreY = box.y + (box.h - h) / 2;
|
|
@@ -272,9 +296,9 @@ function placeCaption(node, box, tokens) {
|
|
|
272
296
|
text
|
|
273
297
|
};
|
|
274
298
|
}
|
|
275
|
-
export function measureGroupTitle(group
|
|
276
|
-
const lines = textBlock(labelLines(group.label),
|
|
277
|
-
const height = lines.h > 0 ? lines.h + 2 *
|
|
299
|
+
export function measureGroupTitle(group) {
|
|
300
|
+
const lines = textBlock(labelLines(group.label), LAYOUT_TOKENS.fonts.groupLabel);
|
|
301
|
+
const height = lines.h > 0 ? lines.h + 2 * LAYOUT_TOKENS.BAND_PAD : 0;
|
|
278
302
|
return {
|
|
279
303
|
height,
|
|
280
304
|
place(rect) {
|
|
@@ -282,32 +306,41 @@ export function measureGroupTitle(group, tokens) {
|
|
|
282
306
|
label: []
|
|
283
307
|
};
|
|
284
308
|
const y = group.labelSide === 'bottom' ? rect.y + rect.h - height : rect.y;
|
|
285
|
-
const top = y +
|
|
309
|
+
const top = y + LAYOUT_TOKENS.BAND_PAD;
|
|
286
310
|
const align = group.labelAlign ?? 'center';
|
|
287
311
|
let label;
|
|
288
312
|
if (align === 'start') {
|
|
289
|
-
label = lines.place(rect.x +
|
|
313
|
+
label = lines.place(rect.x + LAYOUT_TOKENS.PAD_X, top, 'start');
|
|
290
314
|
} else if (align === 'end') {
|
|
291
|
-
label = lines.place(rect.x + rect.w -
|
|
315
|
+
label = lines.place(rect.x + rect.w - LAYOUT_TOKENS.PAD_X, top, 'end');
|
|
292
316
|
} else {
|
|
293
317
|
label = lines.place(rect.x + rect.w / 2, top, 'middle');
|
|
294
318
|
}
|
|
295
|
-
|
|
319
|
+
if (!group.titleBand) return {
|
|
320
|
+
label
|
|
321
|
+
};
|
|
322
|
+
const edge = group.labelSide === 'bottom' ? y : y + height;
|
|
323
|
+
return {
|
|
296
324
|
band: {
|
|
297
325
|
x: rect.x,
|
|
298
326
|
y,
|
|
299
327
|
w: rect.w,
|
|
300
328
|
h: height
|
|
301
329
|
},
|
|
302
|
-
|
|
303
|
-
|
|
330
|
+
separator: [{
|
|
331
|
+
x: rect.x,
|
|
332
|
+
y: edge
|
|
333
|
+
}, {
|
|
334
|
+
x: rect.x + rect.w,
|
|
335
|
+
y: edge
|
|
336
|
+
}],
|
|
304
337
|
label
|
|
305
338
|
};
|
|
306
339
|
}
|
|
307
340
|
};
|
|
308
341
|
}
|
|
309
|
-
export function measureEdgeLabel(edge
|
|
310
|
-
const lines = textBlock(labelLines(edge.label),
|
|
342
|
+
export function measureEdgeLabel(edge) {
|
|
343
|
+
const lines = textBlock(labelLines(edge.label), LAYOUT_TOKENS.fonts.edgeLabel);
|
|
311
344
|
const pad = edge.labelFrame ? EDGE_LABEL_FRAME_PAD : 0;
|
|
312
345
|
return {
|
|
313
346
|
w: lines.w + 2 * pad,
|
|
@@ -315,10 +348,10 @@ export function measureEdgeLabel(edge, tokens) {
|
|
|
315
348
|
place: box => lines.place(box.x + box.w / 2, box.y + pad, 'middle')
|
|
316
349
|
};
|
|
317
350
|
}
|
|
318
|
-
export function measureEdgeBadge(edge
|
|
319
|
-
const lines = textBlock(labelLines(edge.badgeLabel),
|
|
320
|
-
const icon = edge.badgeIcon ?
|
|
321
|
-
const gap = icon > 0 && lines.w > 0 ?
|
|
351
|
+
export function measureEdgeBadge(edge) {
|
|
352
|
+
const lines = textBlock(labelLines(edge.badgeLabel), LAYOUT_TOKENS.fonts.badge);
|
|
353
|
+
const icon = edge.badgeIcon ? LAYOUT_TOKENS.BADGE_ICON : 0;
|
|
354
|
+
const gap = icon > 0 && lines.w > 0 ? LAYOUT_TOKENS.BLOCK_GAP : 0;
|
|
322
355
|
const rowW = icon + gap + lines.w;
|
|
323
356
|
return {
|
|
324
357
|
w: Math.max(BADGE_MIN_CONTENT, rowW) + 2 * BADGE_PAD.x,
|
|
@@ -341,6 +374,17 @@ export function measureEdgeBadge(edge, tokens) {
|
|
|
341
374
|
}
|
|
342
375
|
};
|
|
343
376
|
}
|
|
377
|
+
/** What an edge carries along its route: a label beside it and a badge on it, each only when the edge has one. */
|
|
378
|
+
export function measureEdgeTags(edge) {
|
|
379
|
+
return {
|
|
380
|
+
...(edge.label?.length ? {
|
|
381
|
+
label: measureEdgeLabel(edge)
|
|
382
|
+
} : {}),
|
|
383
|
+
...(edge.badgeIcon || edge.badgeLabel?.length ? {
|
|
384
|
+
badge: measureEdgeBadge(edge)
|
|
385
|
+
} : {})
|
|
386
|
+
};
|
|
387
|
+
}
|
|
344
388
|
function sidesOf(value) {
|
|
345
389
|
return {
|
|
346
390
|
top: value('top'),
|