@zukhruf/diagram 0.3.30 → 0.3.32
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/dist/lib/layouts/graph/areas.d.ts +27 -0
- package/dist/lib/layouts/graph/areas.d.ts.map +1 -0
- package/dist/lib/layouts/graph/areas.js +196 -0
- package/dist/lib/layouts/graph/areas.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts +95 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.js +2 -0
- package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout.d.ts +2 -1
- package/dist/lib/layouts/graph/graph-layout.d.ts.map +1 -1
- package/dist/lib/layouts/graph/graph-layout.js +5 -3
- package/dist/lib/layouts/graph/graph-layout.js.map +1 -1
- package/dist/lib/layouts/graph/gutters.d.ts +25 -0
- package/dist/lib/layouts/graph/gutters.d.ts.map +1 -0
- package/dist/lib/layouts/graph/gutters.js +124 -0
- package/dist/lib/layouts/graph/gutters.js.map +1 -0
- package/dist/lib/layouts/graph/layout.d.ts +10 -0
- package/dist/lib/layouts/graph/layout.d.ts.map +1 -0
- package/dist/lib/layouts/graph/layout.js +164 -0
- package/dist/lib/layouts/graph/layout.js.map +1 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts +6 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts.map +1 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.js +542 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.js.map +1 -0
- package/dist/lib/layouts/graph/measure.d.ts +44 -0
- package/dist/lib/layouts/graph/measure.d.ts.map +1 -0
- package/dist/lib/layouts/graph/measure.js +372 -0
- package/dist/lib/layouts/graph/measure.js.map +1 -0
- package/dist/lib/layouts/graph/node-content.d.ts +16 -0
- package/dist/lib/layouts/graph/node-content.d.ts.map +1 -0
- package/dist/lib/layouts/graph/node-content.js +323 -0
- package/dist/lib/layouts/graph/node-content.js.map +1 -0
- package/dist/lib/layouts/graph/text-block.d.ts +19 -0
- package/dist/lib/layouts/graph/text-block.d.ts.map +1 -0
- package/dist/lib/layouts/graph/text-block.js +86 -0
- package/dist/lib/layouts/graph/text-block.js.map +1 -0
- package/dist/lib/layouts/graph/tokens.d.ts +53 -0
- package/dist/lib/layouts/graph/tokens.d.ts.map +1 -0
- package/dist/lib/layouts/graph/tokens.js +95 -0
- package/dist/lib/layouts/graph/tokens.js.map +1 -0
- package/dist/lib/layouts/graph/tracks.d.ts +20 -0
- package/dist/lib/layouts/graph/tracks.d.ts.map +1 -0
- package/dist/lib/layouts/graph/tracks.js +47 -0
- package/dist/lib/layouts/graph/tracks.js.map +1 -0
- package/dist/lib/layouts/text/font-metrics.generated.d.ts +18 -0
- package/dist/lib/layouts/text/font-metrics.generated.d.ts.map +1 -0
- package/dist/lib/layouts/text/font-metrics.generated.js +1043 -0
- package/dist/lib/layouts/text/font-metrics.generated.js.map +1 -0
- package/dist/lib/layouts/text/font.d.ts +14 -0
- package/dist/lib/layouts/text/font.d.ts.map +1 -0
- package/dist/lib/layouts/text/font.js +11 -0
- package/dist/lib/layouts/text/font.js.map +1 -0
- package/dist/lib/layouts/text/measure-text.d.ts +13 -0
- package/dist/lib/layouts/text/measure-text.d.ts.map +1 -0
- package/dist/lib/layouts/text/measure-text.js +67 -0
- package/dist/lib/layouts/text/measure-text.js.map +1 -0
- package/dist/lib/model/diagram-ir.d.ts +11 -1
- package/dist/lib/model/diagram-ir.d.ts.map +1 -1
- package/dist/lib/model/diagram-ir.js.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.d.ts.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.js +148 -138
- package/dist/lib/renderers/canvas/graph-canvas.js.map +1 -1
- package/dist/lib/renderers/html/graph-html.d.ts.map +1 -1
- package/dist/lib/renderers/html/graph-html.js +462 -511
- package/dist/lib/renderers/html/graph-html.js.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.d.ts +15 -13
- package/dist/lib/renderers/shared/graph-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.js +649 -644
- package/dist/lib/renderers/shared/graph-parts.js.map +1 -1
- package/dist/lib/renderers/shared/node-parts.d.ts +20 -19
- package/dist/lib/renderers/shared/node-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/node-parts.js +678 -811
- package/dist/lib/renderers/shared/node-parts.js.map +1 -1
- package/dist/lib/renderers/shared/run-spans.d.ts +8 -0
- package/dist/lib/renderers/shared/run-spans.d.ts.map +1 -0
- package/dist/lib/renderers/shared/run-spans.js +18 -0
- package/dist/lib/renderers/shared/run-spans.js.map +1 -0
- package/dist/lib/renderers/shared/text-runs.d.ts +21 -0
- package/dist/lib/renderers/shared/text-runs.d.ts.map +1 -0
- package/dist/lib/renderers/shared/text-runs.js +44 -0
- package/dist/lib/renderers/shared/text-runs.js.map +1 -0
- package/dist/lib/renderers/svg/graph-svg.d.ts.map +1 -1
- package/dist/lib/renderers/svg/graph-svg.js +304 -465
- 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 +10 -5
- package/dist/lib/renderers/svg/timeline-svg.js.map +1 -1
- package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts +2 -2
- package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts.map +1 -1
- package/dist/lib/renderers/webgpu/graph-flow-effects.js.map +1 -1
- package/package.json +3 -1
- package/styles.css +8 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DiagramEdge } from '../../model/diagram-ir.ts';
|
|
2
|
+
import type { GridAreas } from './areas.ts';
|
|
3
|
+
export type Axis = 'row' | 'col';
|
|
4
|
+
/**
|
|
5
|
+
* The space at one track boundary. Boundary b lies before track b, so
|
|
6
|
+
* boundaries 0 and N are the outer edges of the grid.
|
|
7
|
+
*/
|
|
8
|
+
export type Gutter = {
|
|
9
|
+
size: number;
|
|
10
|
+
/** For each depth, how far from the gutter's start the border of a group closing here lies. */
|
|
11
|
+
closing: Map<number, number>;
|
|
12
|
+
/** For each depth, how far from the gutter's start the border of a group opening here lies. */
|
|
13
|
+
opening: Map<number, number>;
|
|
14
|
+
};
|
|
15
|
+
export type GridGutters = Record<Axis, Gutter[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Sizes every gutter before the tracks, because no gutter depends on a
|
|
18
|
+
* track's size. A gutter holds, in order: the chrome of the groups closing
|
|
19
|
+
* there (deepest first, next to the track before), a middle gap, and the
|
|
20
|
+
* chrome of the groups opening there (deepest last, next to the track after).
|
|
21
|
+
* Each depth's slot is as wide as its widest group anywhere along the
|
|
22
|
+
* boundary, so every group border stays a straight line.
|
|
23
|
+
*/
|
|
24
|
+
export declare function gridGutters(areas: GridAreas, titleHeights: Map<string, number>, edges: DiagramEdge[]): GridGutters;
|
|
25
|
+
//# sourceMappingURL=gutters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gutters.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/gutters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AAItD,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;AAEjC;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,+FAA+F;IAC/F,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAajD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,EAChB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,KAAK,EAAE,WAAW,EAAE,GACnB,WAAW,CAqBb"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { parseEndpointRef } from "../../model/endpoint-ref.js";
|
|
2
|
+
import { measureEdgeLabel } from "./measure.js";
|
|
3
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The space at one track boundary. Boundary b lies before track b, so
|
|
7
|
+
* boundaries 0 and N are the outer edges of the grid.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** The border stroke a group draws, which its chrome must hold. */
|
|
11
|
+
const STROKE = 1;
|
|
12
|
+
/**
|
|
13
|
+
* Sizes every gutter before the tracks, because no gutter depends on a
|
|
14
|
+
* track's size. A gutter holds, in order: the chrome of the groups closing
|
|
15
|
+
* there (deepest first, next to the track before), a middle gap, and the
|
|
16
|
+
* chrome of the groups opening there (deepest last, next to the track after).
|
|
17
|
+
* Each depth's slot is as wide as its widest group anywhere along the
|
|
18
|
+
* boundary, so every group border stays a straight line.
|
|
19
|
+
*/
|
|
20
|
+
export function gridGutters(areas, titleHeights, edges) {
|
|
21
|
+
const minimums = labelMinimums(edges, areas.nodes);
|
|
22
|
+
const chrome = LAYOUT_TOKENS.GROUP_PAD + STROKE;
|
|
23
|
+
const spans = axis => areas.groups.map(({
|
|
24
|
+
group,
|
|
25
|
+
depth,
|
|
26
|
+
area
|
|
27
|
+
}) => {
|
|
28
|
+
const [start, span] = axis === 'row' ? [area.row, area.rowSpan] : [area.col, area.colSpan];
|
|
29
|
+
const title = axis === 'row' ? titleHeights.get(group.id) : 0;
|
|
30
|
+
const titleAtEnd = group.labelSide === 'bottom';
|
|
31
|
+
return {
|
|
32
|
+
depth,
|
|
33
|
+
start,
|
|
34
|
+
end: start + span,
|
|
35
|
+
openingChrome: chrome + (titleAtEnd ? 0 : title),
|
|
36
|
+
closingChrome: chrome + (titleAtEnd ? title : 0)
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
row: axisGutters(areas.rows, spans('row'), minimums.row),
|
|
41
|
+
col: axisGutters(areas.cols, spans('col'), minimums.col)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function axisGutters(count, spans, minimums) {
|
|
45
|
+
return Array.from({
|
|
46
|
+
length: count + 1
|
|
47
|
+
}, (_, boundary) => {
|
|
48
|
+
const closing = slotWidths(spans.filter(span => span.end === boundary), span => span.closingChrome);
|
|
49
|
+
const opening = slotWidths(spans.filter(span => span.start === boundary), span => span.openingChrome);
|
|
50
|
+
const slots = [...closing.values(), ...opening.values()].reduce((total, width) => total + width, 0);
|
|
51
|
+
const outer = boundary === 0 || boundary === count;
|
|
52
|
+
const middle = Math.max(outer ? 0 : LAYOUT_TOKENS.GAP, (minimums.get(boundary) ?? 0) - slots);
|
|
53
|
+
const closingEdges = new Map();
|
|
54
|
+
let offset = 0;
|
|
55
|
+
for (const [depth, width] of [...closing].sort(([a], [b]) => b - a)) {
|
|
56
|
+
offset += width;
|
|
57
|
+
closingEdges.set(depth, offset);
|
|
58
|
+
}
|
|
59
|
+
offset += middle;
|
|
60
|
+
const openingEdges = new Map();
|
|
61
|
+
for (const [depth, width] of [...opening].sort(([a], [b]) => a - b)) {
|
|
62
|
+
openingEdges.set(depth, offset);
|
|
63
|
+
offset += width;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
size: offset,
|
|
67
|
+
closing: closingEdges,
|
|
68
|
+
opening: openingEdges
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The width of each depth's slot: its widest chrome plus a channel for edges. */
|
|
74
|
+
function slotWidths(spans, chromeOf) {
|
|
75
|
+
const widths = new Map();
|
|
76
|
+
for (const span of spans) {
|
|
77
|
+
const width = chromeOf(span) + LAYOUT_TOKENS.CHANNEL;
|
|
78
|
+
widths.set(span.depth, Math.max(widths.get(span.depth) ?? 0, width));
|
|
79
|
+
}
|
|
80
|
+
return widths;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A labelled edge between two neighbouring cells has only the gutter between
|
|
85
|
+
* them for its label, so that gutter must hold the label and a stub on each
|
|
86
|
+
* side of it.
|
|
87
|
+
*/
|
|
88
|
+
function labelMinimums(edges, nodes) {
|
|
89
|
+
const minimums = {
|
|
90
|
+
row: new Map(),
|
|
91
|
+
col: new Map()
|
|
92
|
+
};
|
|
93
|
+
const raise = (axis, boundary, need) => minimums[axis].set(boundary, Math.max(minimums[axis].get(boundary) ?? 0, need));
|
|
94
|
+
for (const edge of edges) {
|
|
95
|
+
if (!edge.label?.length) continue;
|
|
96
|
+
const from = nodes.get(parseEndpointRef(edge.from).nodeId);
|
|
97
|
+
const to = nodes.get(parseEndpointRef(edge.to).nodeId);
|
|
98
|
+
if (!from || !to) continue;
|
|
99
|
+
const label = measureEdgeLabel(edge, LAYOUT_TOKENS);
|
|
100
|
+
const side = sideBySide(from, to);
|
|
101
|
+
if (side) raise('col', side, label.w + 2 * LAYOUT_TOKENS.STUB);
|
|
102
|
+
const stacked = sideBySide(transpose(from), transpose(to));
|
|
103
|
+
if (stacked) raise('row', stacked, label.h + 2 * LAYOUT_TOKENS.STUB);
|
|
104
|
+
}
|
|
105
|
+
return minimums;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** The column boundary between two areas that share rows and touch across it. */
|
|
109
|
+
function sideBySide(a, b) {
|
|
110
|
+
const shareRows = Math.max(a.row, b.row) < Math.min(a.row + a.rowSpan, b.row + b.rowSpan);
|
|
111
|
+
if (!shareRows) return undefined;
|
|
112
|
+
if (a.col + a.colSpan === b.col) return b.col;
|
|
113
|
+
if (b.col + b.colSpan === a.col) return a.col;
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
function transpose(area) {
|
|
117
|
+
return {
|
|
118
|
+
row: area.col,
|
|
119
|
+
col: area.row,
|
|
120
|
+
rowSpan: area.colSpan,
|
|
121
|
+
colSpan: area.rowSpan
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=gutters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gutters.js","names":["parseEndpointRef","measureEdgeLabel","LAYOUT_TOKENS","STROKE","gridGutters","areas","titleHeights","edges","minimums","labelMinimums","nodes","chrome","GROUP_PAD","spans","axis","groups","map","group","depth","area","start","span","row","rowSpan","col","colSpan","title","get","id","titleAtEnd","labelSide","end","openingChrome","closingChrome","axisGutters","rows","cols","count","Array","from","length","_","boundary","closing","slotWidths","filter","opening","slots","values","reduce","total","width","outer","middle","Math","max","GAP","closingEdges","Map","offset","sort","a","b","set","openingEdges","size","chromeOf","widths","CHANNEL","raise","need","edge","label","nodeId","to","side","sideBySide","w","STUB","stacked","transpose","h","shareRows","min","undefined"],"sources":["../../../../src/lib/layouts/graph/gutters.ts"],"sourcesContent":["import type { DiagramEdge } from '../../model/diagram-ir.ts';\nimport { parseEndpointRef } from '../../model/endpoint-ref.ts';\nimport type { CellArea, GridAreas } from './areas.ts';\nimport { measureEdgeLabel } from './measure.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\n\nexport type Axis = 'row' | 'col';\n\n/**\n * The space at one track boundary. Boundary b lies before track b, so\n * boundaries 0 and N are the outer edges of the grid.\n */\nexport type Gutter = {\n size: number;\n /** For each depth, how far from the gutter's start the border of a group closing here lies. */\n closing: Map<number, number>;\n /** For each depth, how far from the gutter's start the border of a group opening here lies. */\n opening: Map<number, number>;\n};\n\nexport type GridGutters = Record<Axis, Gutter[]>;\n\n/** The border stroke a group draws, which its chrome must hold. */\nconst STROKE = 1;\n\ntype GroupSpan = {\n depth: number;\n start: number;\n end: number;\n openingChrome: number;\n closingChrome: number;\n};\n\n/**\n * Sizes every gutter before the tracks, because no gutter depends on a\n * track's size. A gutter holds, in order: the chrome of the groups closing\n * there (deepest first, next to the track before), a middle gap, and the\n * chrome of the groups opening there (deepest last, next to the track after).\n * Each depth's slot is as wide as its widest group anywhere along the\n * boundary, so every group border stays a straight line.\n */\nexport function gridGutters(\n areas: GridAreas,\n titleHeights: Map<string, number>,\n edges: DiagramEdge[],\n): GridGutters {\n const minimums = labelMinimums(edges, areas.nodes);\n const chrome = LAYOUT_TOKENS.GROUP_PAD + STROKE;\n const spans = (axis: Axis): GroupSpan[] =>\n areas.groups.map(({ group, depth, area }) => {\n const [start, span] =\n axis === 'row' ? [area.row, area.rowSpan] : [area.col, area.colSpan];\n const title = axis === 'row' ? titleHeights.get(group.id)! : 0;\n const titleAtEnd = group.labelSide === 'bottom';\n return {\n depth,\n start,\n end: start + span,\n openingChrome: chrome + (titleAtEnd ? 0 : title),\n closingChrome: chrome + (titleAtEnd ? title : 0),\n };\n });\n return {\n row: axisGutters(areas.rows, spans('row'), minimums.row),\n col: axisGutters(areas.cols, spans('col'), minimums.col),\n };\n}\n\nfunction axisGutters(\n count: number,\n spans: GroupSpan[],\n minimums: Map<number, number>,\n): Gutter[] {\n return Array.from({ length: count + 1 }, (_, boundary) => {\n const closing = slotWidths(\n spans.filter((span) => span.end === boundary),\n (span) => span.closingChrome,\n );\n const opening = slotWidths(\n spans.filter((span) => span.start === boundary),\n (span) => span.openingChrome,\n );\n const slots = [...closing.values(), ...opening.values()].reduce(\n (total, width) => total + width,\n 0,\n );\n const outer = boundary === 0 || boundary === count;\n const middle = Math.max(\n outer ? 0 : LAYOUT_TOKENS.GAP,\n (minimums.get(boundary) ?? 0) - slots,\n );\n\n const closingEdges = new Map<number, number>();\n let offset = 0;\n for (const [depth, width] of [...closing].sort(([a], [b]) => b - a)) {\n offset += width;\n closingEdges.set(depth, offset);\n }\n offset += middle;\n const openingEdges = new Map<number, number>();\n for (const [depth, width] of [...opening].sort(([a], [b]) => a - b)) {\n openingEdges.set(depth, offset);\n offset += width;\n }\n return { size: offset, closing: closingEdges, opening: openingEdges };\n });\n}\n\n/** The width of each depth's slot: its widest chrome plus a channel for edges. */\nfunction slotWidths(\n spans: GroupSpan[],\n chromeOf: (span: GroupSpan) => number,\n): Map<number, number> {\n const widths = new Map<number, number>();\n for (const span of spans) {\n const width = chromeOf(span) + LAYOUT_TOKENS.CHANNEL;\n widths.set(span.depth, Math.max(widths.get(span.depth) ?? 0, width));\n }\n return widths;\n}\n\n/**\n * A labelled edge between two neighbouring cells has only the gutter between\n * them for its label, so that gutter must hold the label and a stub on each\n * side of it.\n */\nfunction labelMinimums(\n edges: DiagramEdge[],\n nodes: Map<string, CellArea>,\n): Record<Axis, Map<number, number>> {\n const minimums: Record<Axis, Map<number, number>> = {\n row: new Map(),\n col: new Map(),\n };\n const raise = (axis: Axis, boundary: number, need: number) =>\n minimums[axis].set(\n boundary,\n Math.max(minimums[axis].get(boundary) ?? 0, need),\n );\n for (const edge of edges) {\n if (!edge.label?.length) continue;\n const from = nodes.get(parseEndpointRef(edge.from).nodeId);\n const to = nodes.get(parseEndpointRef(edge.to).nodeId);\n if (!from || !to) continue;\n const label = measureEdgeLabel(edge, LAYOUT_TOKENS);\n const side = sideBySide(from, to);\n if (side) raise('col', side, label.w + 2 * LAYOUT_TOKENS.STUB);\n const stacked = sideBySide(transpose(from), transpose(to));\n if (stacked) raise('row', stacked, label.h + 2 * LAYOUT_TOKENS.STUB);\n }\n return minimums;\n}\n\n/** The column boundary between two areas that share rows and touch across it. */\nfunction sideBySide(a: CellArea, b: CellArea): number | undefined {\n const shareRows =\n Math.max(a.row, b.row) < Math.min(a.row + a.rowSpan, b.row + b.rowSpan);\n if (!shareRows) return undefined;\n if (a.col + a.colSpan === b.col) return b.col;\n if (b.col + b.colSpan === a.col) return a.col;\n return undefined;\n}\n\nfunction transpose(area: CellArea): CellArea {\n return {\n row: area.col,\n col: area.row,\n rowSpan: area.colSpan,\n colSpan: area.rowSpan,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DiagramGraphIR } from '../../model/diagram-ir.ts';
|
|
2
|
+
import type { GraphLayout } from './graph-layout-result.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Lays out a graph on a content-sized grid: it measures every node, sizes
|
|
5
|
+
* each row and column to the content in it, and reserves the chrome of the
|
|
6
|
+
* groups in the gutters between them. It throws when the grid cannot be
|
|
7
|
+
* drawn without overlap.
|
|
8
|
+
*/
|
|
9
|
+
export declare function layoutGraph(ir: DiagramGraphIR): GraphLayout;
|
|
10
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,cAAc,EAAS,MAAM,2BAA2B,CAAC;AAE5E,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,0BAA0B,CAAC;AAWlC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,GAAG,WAAW,CA6D3D"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { gridAreas } from "./areas.js";
|
|
2
|
+
import { gridGutters } from "./gutters.js";
|
|
3
|
+
import { measureGroupTitle, measureNode } from "./measure.js";
|
|
4
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
5
|
+
import { sizeTracks } from "./tracks.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Lays out a graph on a content-sized grid: it measures every node, sizes
|
|
9
|
+
* each row and column to the content in it, and reserves the chrome of the
|
|
10
|
+
* groups in the gutters between them. It throws when the grid cannot be
|
|
11
|
+
* drawn without overlap.
|
|
12
|
+
*/
|
|
13
|
+
export function layoutGraph(ir) {
|
|
14
|
+
const measured = new Map(ir.nodes.map(node => [node.id, measureNode(node, LAYOUT_TOKENS)]));
|
|
15
|
+
const titles = new Map(ir.groups.map(group => [group.id, measureGroupTitle(group, LAYOUT_TOKENS)]));
|
|
16
|
+
const areas = gridAreas(ir);
|
|
17
|
+
const gutters = gridGutters(areas, new Map([...titles].map(([id, title]) => [id, title.height])), ir.edges);
|
|
18
|
+
const items = axis => ir.nodes.map(node => {
|
|
19
|
+
const area = areas.nodes.get(node.id);
|
|
20
|
+
const {
|
|
21
|
+
frame,
|
|
22
|
+
overhang
|
|
23
|
+
} = measured.get(node.id);
|
|
24
|
+
return axis === 'row' ? {
|
|
25
|
+
start: area.row,
|
|
26
|
+
span: area.rowSpan,
|
|
27
|
+
size: frame.h + overhang.top + overhang.bottom
|
|
28
|
+
} : {
|
|
29
|
+
start: area.col,
|
|
30
|
+
span: area.colSpan,
|
|
31
|
+
size: frame.w + overhang.left + overhang.right
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
const line = (axis, count) => sizeTracks(count, items(axis), gutters[axis].map(gutter => gutter.size));
|
|
35
|
+
const lines = {
|
|
36
|
+
row: line('row', areas.rows),
|
|
37
|
+
col: line('col', areas.cols)
|
|
38
|
+
};
|
|
39
|
+
const nodes = ir.nodes.map(node => {
|
|
40
|
+
const measuredNode = measured.get(node.id);
|
|
41
|
+
const area = areaBox(areas.nodes.get(node.id), lines);
|
|
42
|
+
return {
|
|
43
|
+
node,
|
|
44
|
+
...measuredNode.place(nodeFrame(measuredNode, area))
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
const groups = areas.groups.map(groupArea => placeGroup(groupArea, titles.get(groupArea.group.id), lines, gutters));
|
|
48
|
+
return {
|
|
49
|
+
nodes,
|
|
50
|
+
groups,
|
|
51
|
+
edges: [],
|
|
52
|
+
leaders: [],
|
|
53
|
+
viewBox: viewBoxOf(nodes, groups)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function areaBox(area, lines) {
|
|
57
|
+
const x = lines.col.trackStart(area.col);
|
|
58
|
+
const y = lines.row.trackStart(area.row);
|
|
59
|
+
return {
|
|
60
|
+
x,
|
|
61
|
+
y,
|
|
62
|
+
w: lines.col.trackEnd(area.col + area.colSpan - 1) - x,
|
|
63
|
+
h: lines.row.trackEnd(area.row + area.rowSpan - 1) - y
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** A stretching node fills its area; any other node keeps its measured frame, centred in the area. */
|
|
68
|
+
function nodeFrame(measured, area) {
|
|
69
|
+
const {
|
|
70
|
+
frame,
|
|
71
|
+
overhang,
|
|
72
|
+
stretch
|
|
73
|
+
} = measured;
|
|
74
|
+
if (stretch) {
|
|
75
|
+
return {
|
|
76
|
+
x: area.x + overhang.left,
|
|
77
|
+
y: area.y + overhang.top,
|
|
78
|
+
w: area.w - overhang.left - overhang.right,
|
|
79
|
+
h: area.h - overhang.top - overhang.bottom
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const visualW = frame.w + overhang.left + overhang.right;
|
|
83
|
+
const visualH = frame.h + overhang.top + overhang.bottom;
|
|
84
|
+
return {
|
|
85
|
+
x: area.x + (area.w - visualW) / 2 + overhang.left,
|
|
86
|
+
y: area.y + (area.h - visualH) / 2 + overhang.top,
|
|
87
|
+
...frame
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Each side of a group lies on the outer edge of its chrome slot in the gutter where the group opens or closes. */
|
|
92
|
+
function placeGroup({
|
|
93
|
+
group,
|
|
94
|
+
depth,
|
|
95
|
+
area
|
|
96
|
+
}, title, lines, gutters) {
|
|
97
|
+
const border = (axis, boundary, side) => lines[axis].gutterStart(boundary) + gutters[axis][boundary][side].get(depth);
|
|
98
|
+
const x = border('col', area.col, 'opening');
|
|
99
|
+
const y = border('row', area.row, 'opening');
|
|
100
|
+
const rect = {
|
|
101
|
+
x,
|
|
102
|
+
y,
|
|
103
|
+
w: border('col', area.col + area.colSpan, 'closing') - x,
|
|
104
|
+
h: border('row', area.row + area.rowSpan, 'closing') - y
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
group,
|
|
108
|
+
depth,
|
|
109
|
+
rect,
|
|
110
|
+
...title.place(rect),
|
|
111
|
+
dividers: group.dividers ? dividers(rect, area, title, group.labelSide, lines, gutters) : []
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** A line through the middle of every gutter inside the group, clear of its title. */
|
|
116
|
+
function dividers(rect, area, title, labelSide, lines, gutters) {
|
|
117
|
+
const centre = (axis, boundary) => lines[axis].gutterStart(boundary) + gutters[axis][boundary].size / 2;
|
|
118
|
+
const titleAtBottom = labelSide === 'bottom';
|
|
119
|
+
const top = rect.y + (titleAtBottom ? 0 : title.height);
|
|
120
|
+
const bottom = rect.y + rect.h - (titleAtBottom ? title.height : 0);
|
|
121
|
+
const inner = (start, span) => Array.from({
|
|
122
|
+
length: span - 1
|
|
123
|
+
}, (_, index) => start + index + 1);
|
|
124
|
+
return [...inner(area.col, area.colSpan).map(boundary => {
|
|
125
|
+
const x = centre('col', boundary);
|
|
126
|
+
return [{
|
|
127
|
+
x,
|
|
128
|
+
y: top
|
|
129
|
+
}, {
|
|
130
|
+
x,
|
|
131
|
+
y: bottom
|
|
132
|
+
}];
|
|
133
|
+
}), ...inner(area.row, area.rowSpan).map(boundary => {
|
|
134
|
+
const y = centre('row', boundary);
|
|
135
|
+
return [{
|
|
136
|
+
x: rect.x,
|
|
137
|
+
y
|
|
138
|
+
}, {
|
|
139
|
+
x: rect.x + rect.w,
|
|
140
|
+
y
|
|
141
|
+
}];
|
|
142
|
+
})];
|
|
143
|
+
}
|
|
144
|
+
function viewBoxOf(nodes, groups) {
|
|
145
|
+
const boxes = [...nodes.map(nodeLayout => nodeLayout.visual), ...groups.map(groupLayout => groupLayout.rect)];
|
|
146
|
+
const pad = LAYOUT_TOKENS.CONTENT_PAD;
|
|
147
|
+
if (boxes.length === 0) return {
|
|
148
|
+
x: -pad,
|
|
149
|
+
y: -pad,
|
|
150
|
+
w: 2 * pad,
|
|
151
|
+
h: 2 * pad
|
|
152
|
+
};
|
|
153
|
+
const left = Math.min(...boxes.map(box => box.x));
|
|
154
|
+
const top = Math.min(...boxes.map(box => box.y));
|
|
155
|
+
const right = Math.max(...boxes.map(box => box.x + box.w));
|
|
156
|
+
const bottom = Math.max(...boxes.map(box => box.y + box.h));
|
|
157
|
+
return {
|
|
158
|
+
x: left - pad,
|
|
159
|
+
y: top - pad,
|
|
160
|
+
w: right - left + 2 * pad,
|
|
161
|
+
h: bottom - top + 2 * pad
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +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":[]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DiagramGraphIR } from '../../model/diagram-ir.ts';
|
|
2
|
+
import type { GraphLayout } from './graph-layout-result.ts';
|
|
3
|
+
/** The prefix of the id of the note node that stands for a free annotation. */
|
|
4
|
+
export declare const ANNOTATION_NOTE_PREFIX = "annotation:";
|
|
5
|
+
export declare function legacyGraphLayout(ir: DiagramGraphIR): GraphLayout;
|
|
6
|
+
//# sourceMappingURL=legacy-graph-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-graph-layout.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/legacy-graph-layout.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,cAAc,EAOf,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAEV,WAAW,EAOZ,MAAM,0BAA0B,CAAC;AA+BlC,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,WAAW,CAiBjE"}
|