@zukhruf/diagram 0.3.31 → 0.3.33
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.js +17 -8
- package/dist/lib/layouts/graph/areas.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 +216 -0
- package/dist/lib/layouts/graph/attach.js.map +1 -0
- package/dist/lib/layouts/graph/connections.d.ts +38 -0
- package/dist/lib/layouts/graph/connections.d.ts.map +1 -0
- package/dist/lib/layouts/graph/connections.js +112 -0
- package/dist/lib/layouts/graph/connections.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts +1 -1
- 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.d.ts +1 -2
- package/dist/lib/layouts/graph/gutters.d.ts.map +1 -1
- package/dist/lib/layouts/graph/gutters.js +20 -19
- package/dist/lib/layouts/graph/gutters.js.map +1 -1
- package/dist/lib/layouts/graph/labels.d.ts +16 -0
- package/dist/lib/layouts/graph/labels.d.ts.map +1 -0
- package/dist/lib/layouts/graph/labels.js +76 -0
- package/dist/lib/layouts/graph/labels.js.map +1 -0
- package/dist/lib/layouts/graph/layout.d.ts.map +1 -1
- package/dist/lib/layouts/graph/layout.js +34 -13
- package/dist/lib/layouts/graph/layout.js.map +1 -1
- package/dist/lib/layouts/graph/measure.d.ts +7 -6
- package/dist/lib/layouts/graph/measure.d.ts.map +1 -1
- package/dist/lib/layouts/graph/measure.js +35 -29
- package/dist/lib/layouts/graph/measure.js.map +1 -1
- package/dist/lib/layouts/graph/min-heap.d.ts +12 -0
- package/dist/lib/layouts/graph/min-heap.d.ts.map +1 -0
- package/dist/lib/layouts/graph/min-heap.js +60 -0
- package/dist/lib/layouts/graph/min-heap.js.map +1 -0
- package/dist/lib/layouts/graph/node-content.d.ts +1 -2
- package/dist/lib/layouts/graph/node-content.d.ts.map +1 -1
- package/dist/lib/layouts/graph/node-content.js +43 -42
- package/dist/lib/layouts/graph/node-content.js.map +1 -1
- package/dist/lib/layouts/graph/path.d.ts +14 -0
- package/dist/lib/layouts/graph/path.d.ts.map +1 -0
- package/dist/lib/layouts/graph/path.js +55 -0
- package/dist/lib/layouts/graph/path.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 +16 -0
- package/dist/lib/layouts/graph/route.d.ts.map +1 -0
- package/dist/lib/layouts/graph/route.js +241 -0
- package/dist/lib/layouts/graph/route.js.map +1 -0
- package/dist/lib/layouts/graph/sides.d.ts +23 -0
- package/dist/lib/layouts/graph/sides.d.ts.map +1 -0
- package/dist/lib/layouts/graph/sides.js +91 -0
- package/dist/lib/layouts/graph/sides.js.map +1 -0
- package/dist/lib/layouts/graph/tokens.d.ts +2 -7
- package/dist/lib/layouts/graph/tokens.d.ts.map +1 -1
- package/dist/lib/layouts/graph/tokens.js +91 -104
- package/dist/lib/layouts/graph/tokens.js.map +1 -1
- package/dist/lib/model/diagram-ir.d.ts +0 -3
- package/dist/lib/model/diagram-ir.d.ts.map +1 -1
- package/dist/lib/model/diagram-ir.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-layout-result.js","names":[],"sources":["../../../../src/lib/layouts/graph/graph-layout-result.ts"],"sourcesContent":["import type {\n Box,\n DiagramEdge,\n DiagramGroup,\n DiagramNode,\n DiagramSide,\n DiagramTextColor,\n Point,\n} from '../../model/diagram-ir.ts';\nimport type { Font } from '../text/font.ts';\n\nexport type TextAnchor = 'start' | 'middle' | 'end';\n\nexport type TextRun = {\n text: string;\n x: number;\n /** The baseline. */\n y: number;\n anchor: TextAnchor;\n font: Font;\n color?: DiagramTextColor;\n /** The ink box the engine measured. */\n bounds: Box;\n};\n\nexport type PortLayout = {\n id: string;\n side: DiagramSide;\n point: Point;\n label?: TextRun;\n};\n\nexport type NodeLayout = {\n node: DiagramNode;\n /** The frame. */\n box: Box;\n /** The frame, the stacked back frames and the caption together. */\n visual: Box;\n /** The stacked back frames. */\n frames: Box[];\n radius: number;\n icon?: { x: number; y: number; size: number };\n text: TextRun[];\n bullets: Point[];\n caption?: { box: Box; framed: boolean; text: TextRun[] };\n ports: PortLayout[];\n appliance?: {\n body: Point[];\n /** The line under the front edge of the body. */\n face: [Point, Point];\n antenna: [Point, Point][];\n jacks: Box[];\n };\n};\n\nexport type GroupLayout = {\n group: DiagramGroup;\n depth: number;\n rect: Box;\n /** The title band, inside `rect`. */\n band?: Box;\n label: TextRun[];\n dividers: [Point, Point][];\n ports
|
|
1
|
+
{"version":3,"file":"graph-layout-result.js","names":[],"sources":["../../../../src/lib/layouts/graph/graph-layout-result.ts"],"sourcesContent":["import type {\n Box,\n DiagramEdge,\n DiagramGroup,\n DiagramNode,\n DiagramSide,\n DiagramTextColor,\n Point,\n} from '../../model/diagram-ir.ts';\nimport type { Font } from '../text/font.ts';\n\nexport type TextAnchor = 'start' | 'middle' | 'end';\n\nexport type TextRun = {\n text: string;\n x: number;\n /** The baseline. */\n y: number;\n anchor: TextAnchor;\n font: Font;\n color?: DiagramTextColor;\n /** The ink box the engine measured. */\n bounds: Box;\n};\n\nexport type PortLayout = {\n id: string;\n side: DiagramSide;\n point: Point;\n label?: TextRun;\n};\n\nexport type NodeLayout = {\n node: DiagramNode;\n /** The frame. */\n box: Box;\n /** The frame, the stacked back frames and the caption together. */\n visual: Box;\n /** The stacked back frames. */\n frames: Box[];\n radius: number;\n icon?: { x: number; y: number; size: number };\n text: TextRun[];\n bullets: Point[];\n caption?: { box: Box; framed: boolean; text: TextRun[] };\n ports: PortLayout[];\n appliance?: {\n body: Point[];\n /** The line under the front edge of the body. */\n face: [Point, Point];\n antenna: [Point, Point][];\n jacks: Box[];\n };\n};\n\nexport type GroupLayout = {\n group: DiagramGroup;\n depth: number;\n rect: Box;\n /** The title band, inside `rect`. */\n band?: Box;\n label: TextRun[];\n dividers: [Point, Point][];\n ports: PortLayout[];\n};\n\nexport type EdgeLabelLayout = {\n box: Box;\n text: TextRun[];\n /** The index of the route segment that the label sits beside. */\n segment?: number;\n};\n\nexport type EdgeLayout = {\n edge: DiagramEdge;\n exitSide: DiagramSide;\n entrySide: DiagramSide;\n points: Point[];\n d: string;\n label?: EdgeLabelLayout;\n badge?: { box: Box; icon?: Box; text: TextRun[] };\n};\n\nexport type LeaderLayout = {\n /** The id of the note node. */\n note: string;\n /** The id of the node or group that the note explains. */\n target: string;\n points: Point[];\n d: string;\n};\n\nexport type GraphLayout = {\n nodes: NodeLayout[];\n groups: GroupLayout[];\n edges: EdgeLayout[];\n leaders: LeaderLayout[];\n viewBox: Box;\n};\n"],"mappings":"","ignoreList":[]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { DiagramEdge } from '../../model/diagram-ir.ts';
|
|
2
2
|
import type { GridAreas } from './areas.ts';
|
|
3
|
-
import type { LayoutTokens } from './tokens.ts';
|
|
4
3
|
export type Axis = 'row' | 'col';
|
|
5
4
|
/**
|
|
6
5
|
* The space at one track boundary. Boundary b lies before track b, so
|
|
@@ -22,5 +21,5 @@ export type GridGutters = Record<Axis, Gutter[]>;
|
|
|
22
21
|
* Each depth's slot is as wide as its widest group anywhere along the
|
|
23
22
|
* boundary, so every group border stays a straight line.
|
|
24
23
|
*/
|
|
25
|
-
export declare function gridGutters(areas: GridAreas, titleHeights: Map<string, number>, edges: DiagramEdge[]
|
|
24
|
+
export declare function gridGutters(areas: GridAreas, titleHeights: Map<string, number>, edges: DiagramEdge[]): GridGutters;
|
|
26
25
|
//# sourceMappingURL=gutters.d.ts.map
|
|
@@ -1 +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;
|
|
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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseEndpointRef } from "../../model/endpoint-ref.js";
|
|
2
2
|
import { measureEdgeLabel } from "./measure.js";
|
|
3
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The space at one track boundary. Boundary b lies before track b, so
|
|
@@ -16,16 +17,16 @@ const STROKE = 1;
|
|
|
16
17
|
* Each depth's slot is as wide as its widest group anywhere along the
|
|
17
18
|
* boundary, so every group border stays a straight line.
|
|
18
19
|
*/
|
|
19
|
-
export function gridGutters(areas, titleHeights, edges
|
|
20
|
-
const minimums = labelMinimums(edges, areas.nodes
|
|
21
|
-
const chrome =
|
|
20
|
+
export function gridGutters(areas, titleHeights, edges) {
|
|
21
|
+
const minimums = labelMinimums(edges, areas.nodes);
|
|
22
|
+
const chrome = LAYOUT_TOKENS.GROUP_PAD + STROKE;
|
|
22
23
|
const spans = axis => areas.groups.map(({
|
|
23
24
|
group,
|
|
24
25
|
depth,
|
|
25
26
|
area
|
|
26
27
|
}) => {
|
|
27
28
|
const [start, span] = axis === 'row' ? [area.row, area.rowSpan] : [area.col, area.colSpan];
|
|
28
|
-
const title = axis === 'row' ? titleHeights.get(group.id)
|
|
29
|
+
const title = axis === 'row' ? titleHeights.get(group.id) : 0;
|
|
29
30
|
const titleAtEnd = group.labelSide === 'bottom';
|
|
30
31
|
return {
|
|
31
32
|
depth,
|
|
@@ -36,19 +37,18 @@ export function gridGutters(areas, titleHeights, edges, tokens) {
|
|
|
36
37
|
};
|
|
37
38
|
});
|
|
38
39
|
return {
|
|
39
|
-
row: axisGutters(areas.rows, spans('row'), minimums.row
|
|
40
|
-
col: axisGutters(areas.cols, spans('col'), minimums.col
|
|
40
|
+
row: axisGutters(areas.rows, spans('row'), minimums.row),
|
|
41
|
+
col: axisGutters(areas.cols, spans('col'), minimums.col)
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
|
-
function axisGutters(count, spans, minimums
|
|
44
|
+
function axisGutters(count, spans, minimums) {
|
|
44
45
|
return Array.from({
|
|
45
46
|
length: count + 1
|
|
46
47
|
}, (_, boundary) => {
|
|
47
|
-
const closing = slotWidths(spans.filter(span => span.end === boundary), span => span.closingChrome
|
|
48
|
-
const opening = slotWidths(spans.filter(span => span.start === boundary), span => span.openingChrome
|
|
49
|
-
const slots = [...closing.values(), ...opening.values()].reduce((total, width) => total + width, 0);
|
|
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
50
|
const outer = boundary === 0 || boundary === count;
|
|
51
|
-
const middle = Math.max(outer ? 0 :
|
|
51
|
+
const middle = Math.max(outer ? 0 : LAYOUT_TOKENS.GAP, minimums.get(boundary) ?? 0);
|
|
52
52
|
const closingEdges = new Map();
|
|
53
53
|
let offset = 0;
|
|
54
54
|
for (const [depth, width] of [...closing].sort(([a], [b]) => b - a)) {
|
|
@@ -70,10 +70,10 @@ function axisGutters(count, spans, minimums, tokens) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/** The width of each depth's slot: its widest chrome plus a channel for edges. */
|
|
73
|
-
function slotWidths(spans, chromeOf
|
|
73
|
+
function slotWidths(spans, chromeOf) {
|
|
74
74
|
const widths = new Map();
|
|
75
75
|
for (const span of spans) {
|
|
76
|
-
const width = chromeOf(span) +
|
|
76
|
+
const width = chromeOf(span) + LAYOUT_TOKENS.CHANNEL;
|
|
77
77
|
widths.set(span.depth, Math.max(widths.get(span.depth) ?? 0, width));
|
|
78
78
|
}
|
|
79
79
|
return widths;
|
|
@@ -81,10 +81,11 @@ function slotWidths(spans, chromeOf, tokens) {
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* A labelled edge between two neighbouring cells has only the gutter between
|
|
84
|
-
* them for its label
|
|
85
|
-
*
|
|
84
|
+
* them for its label. The label must not straddle the border of a group that
|
|
85
|
+
* opens or closes there, so the middle of that gutter, outside all their
|
|
86
|
+
* chrome, must hold the label and a stub on each side of it.
|
|
86
87
|
*/
|
|
87
|
-
function labelMinimums(edges, nodes
|
|
88
|
+
function labelMinimums(edges, nodes) {
|
|
88
89
|
const minimums = {
|
|
89
90
|
row: new Map(),
|
|
90
91
|
col: new Map()
|
|
@@ -95,11 +96,11 @@ function labelMinimums(edges, nodes, tokens) {
|
|
|
95
96
|
const from = nodes.get(parseEndpointRef(edge.from).nodeId);
|
|
96
97
|
const to = nodes.get(parseEndpointRef(edge.to).nodeId);
|
|
97
98
|
if (!from || !to) continue;
|
|
98
|
-
const label = measureEdgeLabel(edge
|
|
99
|
+
const label = measureEdgeLabel(edge);
|
|
99
100
|
const side = sideBySide(from, to);
|
|
100
|
-
if (side) raise('col', side, label.w + 2 *
|
|
101
|
+
if (side) raise('col', side, label.w + 2 * LAYOUT_TOKENS.STUB);
|
|
101
102
|
const stacked = sideBySide(transpose(from), transpose(to));
|
|
102
|
-
if (stacked) raise('row', stacked, label.h + 2 *
|
|
103
|
+
if (stacked) raise('row', stacked, label.h + 2 * LAYOUT_TOKENS.STUB);
|
|
103
104
|
}
|
|
104
105
|
return minimums;
|
|
105
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gutters.js","names":["parseEndpointRef","measureEdgeLabel","STROKE","gridGutters","areas","titleHeights","edges","tokens","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 type { LayoutTokens } 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 tokens: LayoutTokens,\n): GridGutters {\n const minimums = labelMinimums(edges, areas.nodes, tokens);\n const chrome = 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) : 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, tokens),\n col: axisGutters(areas.cols, spans('col'), minimums.col, tokens),\n };\n}\n\nfunction axisGutters(\n count: number,\n spans: GroupSpan[],\n minimums: Map<number, number>,\n tokens: LayoutTokens,\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 tokens,\n );\n const opening = slotWidths(\n spans.filter((span) => span.start === boundary),\n (span) => span.openingChrome,\n tokens,\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 : 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 tokens: LayoutTokens,\n): Map<number, number> {\n const widths = new Map<number, number>();\n for (const span of spans) {\n const width = chromeOf(span) + 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 tokens: LayoutTokens,\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, tokens);\n const side = sideBySide(from, to);\n if (side) raise('col', side, label.w + 2 * tokens.STUB);\n const stacked = sideBySide(transpose(from), transpose(to));\n if (stacked) raise('row', stacked, label.h + 2 * 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":[]}
|
|
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","outer","middle","Math","max","GAP","closingEdges","Map","offset","width","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 outer = boundary === 0 || boundary === count;\n const middle = Math.max(\n outer ? 0 : LAYOUT_TOKENS.GAP,\n minimums.get(boundary) ?? 0,\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. The label must not straddle the border of a group that\n * opens or closes there, so the middle of that gutter, outside all their\n * chrome, must hold the label and a stub on each 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);\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":"AACA,SAASA,gBAAgB,QAAQ,6BAA6B;AAE9D,SAASC,gBAAgB,QAAQ,cAAc;AAC/C,SAASC,aAAa,QAAQ,aAAa;;AAI3C;AACA;AACA;AACA;;AAWA;AACA,MAAMC,MAAM,GAAG,CAAC;AAUhB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CACzBC,KAAgB,EAChBC,YAAiC,EACjCC,KAAoB,EACP;EACb,MAAMC,QAAQ,GAAGC,aAAa,CAACF,KAAK,EAAEF,KAAK,CAACK,KAAK,CAAC;EAClD,MAAMC,MAAM,GAAGT,aAAa,CAACU,SAAS,GAAGT,MAAM;EAC/C,MAAMU,KAAK,GAAIC,IAAU,IACvBT,KAAK,CAACU,MAAM,CAACC,GAAG,CAAC,CAAC;IAAEC,KAAK;IAAEC,KAAK;IAAEC;EAAK,CAAC,KAAK;IAC3C,MAAM,CAACC,KAAK,EAAEC,IAAI,CAAC,GACjBP,IAAI,KAAK,KAAK,GAAG,CAACK,IAAI,CAACG,GAAG,EAAEH,IAAI,CAACI,OAAO,CAAC,GAAG,CAACJ,IAAI,CAACK,GAAG,EAAEL,IAAI,CAACM,OAAO,CAAC;IACtE,MAAMC,KAAK,GAAGZ,IAAI,KAAK,KAAK,GAAGR,YAAY,CAACqB,GAAG,CAACV,KAAK,CAACW,EAAE,CAAC,GAAI,CAAC;IAC9D,MAAMC,UAAU,GAAGZ,KAAK,CAACa,SAAS,KAAK,QAAQ;IAC/C,OAAO;MACLZ,KAAK;MACLE,KAAK;MACLW,GAAG,EAAEX,KAAK,GAAGC,IAAI;MACjBW,aAAa,EAAErB,MAAM,IAAIkB,UAAU,GAAG,CAAC,GAAGH,KAAK,CAAC;MAChDO,aAAa,EAAEtB,MAAM,IAAIkB,UAAU,GAAGH,KAAK,GAAG,CAAC;IACjD,CAAC;EACH,CAAC,CAAC;EACJ,OAAO;IACLJ,GAAG,EAAEY,WAAW,CAAC7B,KAAK,CAAC8B,IAAI,EAAEtB,KAAK,CAAC,KAAK,CAAC,EAAEL,QAAQ,CAACc,GAAG,CAAC;IACxDE,GAAG,EAAEU,WAAW,CAAC7B,KAAK,CAAC+B,IAAI,EAAEvB,KAAK,CAAC,KAAK,CAAC,EAAEL,QAAQ,CAACgB,GAAG;EACzD,CAAC;AACH;AAEA,SAASU,WAAWA,CAClBG,KAAa,EACbxB,KAAkB,EAClBL,QAA6B,EACnB;EACV,OAAO8B,KAAK,CAACC,IAAI,CAAC;IAAEC,MAAM,EAAEH,KAAK,GAAG;EAAE,CAAC,EAAE,CAACI,CAAC,EAAEC,QAAQ,KAAK;IACxD,MAAMC,OAAO,GAAGC,UAAU,CACxB/B,KAAK,CAACgC,MAAM,CAAExB,IAAI,IAAKA,IAAI,CAACU,GAAG,KAAKW,QAAQ,CAAC,EAC5CrB,IAAI,IAAKA,IAAI,CAACY,aACjB,CAAC;IACD,MAAMa,OAAO,GAAGF,UAAU,CACxB/B,KAAK,CAACgC,MAAM,CAAExB,IAAI,IAAKA,IAAI,CAACD,KAAK,KAAKsB,QAAQ,CAAC,EAC9CrB,IAAI,IAAKA,IAAI,CAACW,aACjB,CAAC;IACD,MAAMe,KAAK,GAAGL,QAAQ,KAAK,CAAC,IAAIA,QAAQ,KAAKL,KAAK;IAClD,MAAMW,MAAM,GAAGC,IAAI,CAACC,GAAG,CACrBH,KAAK,GAAG,CAAC,GAAG7C,aAAa,CAACiD,GAAG,EAC7B3C,QAAQ,CAACmB,GAAG,CAACe,QAAQ,CAAC,IAAI,CAC5B,CAAC;IAED,MAAMU,YAAY,GAAG,IAAIC,GAAG,CAAiB,CAAC;IAC9C,IAAIC,MAAM,GAAG,CAAC;IACd,KAAK,MAAM,CAACpC,KAAK,EAAEqC,KAAK,CAAC,IAAI,CAAC,GAAGZ,OAAO,CAAC,CAACa,IAAI,CAAC,CAAC,CAACC,CAAC,CAAC,EAAE,CAACC,CAAC,CAAC,KAAKA,CAAC,GAAGD,CAAC,CAAC,EAAE;MACnEH,MAAM,IAAIC,KAAK;MACfH,YAAY,CAACO,GAAG,CAACzC,KAAK,EAAEoC,MAAM,CAAC;IACjC;IACAA,MAAM,IAAIN,MAAM;IAChB,MAAMY,YAAY,GAAG,IAAIP,GAAG,CAAiB,CAAC;IAC9C,KAAK,MAAM,CAACnC,KAAK,EAAEqC,KAAK,CAAC,IAAI,CAAC,GAAGT,OAAO,CAAC,CAACU,IAAI,CAAC,CAAC,CAACC,CAAC,CAAC,EAAE,CAACC,CAAC,CAAC,KAAKD,CAAC,GAAGC,CAAC,CAAC,EAAE;MACnEE,YAAY,CAACD,GAAG,CAACzC,KAAK,EAAEoC,MAAM,CAAC;MAC/BA,MAAM,IAAIC,KAAK;IACjB;IACA,OAAO;MAAEM,IAAI,EAAEP,MAAM;MAAEX,OAAO,EAAES,YAAY;MAAEN,OAAO,EAAEc;IAAa,CAAC;EACvE,CAAC,CAAC;AACJ;;AAEA;AACA,SAAShB,UAAUA,CACjB/B,KAAkB,EAClBiD,QAAqC,EAChB;EACrB,MAAMC,MAAM,GAAG,IAAIV,GAAG,CAAiB,CAAC;EACxC,KAAK,MAAMhC,IAAI,IAAIR,KAAK,EAAE;IACxB,MAAM0C,KAAK,GAAGO,QAAQ,CAACzC,IAAI,CAAC,GAAGnB,aAAa,CAAC8D,OAAO;IACpDD,MAAM,CAACJ,GAAG,CAACtC,IAAI,CAACH,KAAK,EAAE+B,IAAI,CAACC,GAAG,CAACa,MAAM,CAACpC,GAAG,CAACN,IAAI,CAACH,KAAK,CAAC,IAAI,CAAC,EAAEqC,KAAK,CAAC,CAAC;EACtE;EACA,OAAOQ,MAAM;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAStD,aAAaA,CACpBF,KAAoB,EACpBG,KAA4B,EACO;EACnC,MAAMF,QAA2C,GAAG;IAClDc,GAAG,EAAE,IAAI+B,GAAG,CAAC,CAAC;IACd7B,GAAG,EAAE,IAAI6B,GAAG,CAAC;EACf,CAAC;EACD,MAAMY,KAAK,GAAGA,CAACnD,IAAU,EAAE4B,QAAgB,EAAEwB,IAAY,KACvD1D,QAAQ,CAACM,IAAI,CAAC,CAAC6C,GAAG,CAChBjB,QAAQ,EACRO,IAAI,CAACC,GAAG,CAAC1C,QAAQ,CAACM,IAAI,CAAC,CAACa,GAAG,CAACe,QAAQ,CAAC,IAAI,CAAC,EAAEwB,IAAI,CAClD,CAAC;EACH,KAAK,MAAMC,IAAI,IAAI5D,KAAK,EAAE;IACxB,IAAI,CAAC4D,IAAI,CAACC,KAAK,EAAE5B,MAAM,EAAE;IACzB,MAAMD,IAAI,GAAG7B,KAAK,CAACiB,GAAG,CAAC3B,gBAAgB,CAACmE,IAAI,CAAC5B,IAAI,CAAC,CAAC8B,MAAM,CAAC;IAC1D,MAAMC,EAAE,GAAG5D,KAAK,CAACiB,GAAG,CAAC3B,gBAAgB,CAACmE,IAAI,CAACG,EAAE,CAAC,CAACD,MAAM,CAAC;IACtD,IAAI,CAAC9B,IAAI,IAAI,CAAC+B,EAAE,EAAE;IAClB,MAAMF,KAAK,GAAGnE,gBAAgB,CAACkE,IAAI,CAAC;IACpC,MAAMI,IAAI,GAAGC,UAAU,CAACjC,IAAI,EAAE+B,EAAE,CAAC;IACjC,IAAIC,IAAI,EAAEN,KAAK,CAAC,KAAK,EAAEM,IAAI,EAAEH,KAAK,CAACK,CAAC,GAAG,CAAC,GAAGvE,aAAa,CAACwE,IAAI,CAAC;IAC9D,MAAMC,OAAO,GAAGH,UAAU,CAACI,SAAS,CAACrC,IAAI,CAAC,EAAEqC,SAAS,CAACN,EAAE,CAAC,CAAC;IAC1D,IAAIK,OAAO,EAAEV,KAAK,CAAC,KAAK,EAAEU,OAAO,EAAEP,KAAK,CAACS,CAAC,GAAG,CAAC,GAAG3E,aAAa,CAACwE,IAAI,CAAC;EACtE;EACA,OAAOlE,QAAQ;AACjB;;AAEA;AACA,SAASgE,UAAUA,CAACf,CAAW,EAAEC,CAAW,EAAsB;EAChE,MAAMoB,SAAS,GACb7B,IAAI,CAACC,GAAG,CAACO,CAAC,CAACnC,GAAG,EAAEoC,CAAC,CAACpC,GAAG,CAAC,GAAG2B,IAAI,CAAC8B,GAAG,CAACtB,CAAC,CAACnC,GAAG,GAAGmC,CAAC,CAAClC,OAAO,EAAEmC,CAAC,CAACpC,GAAG,GAAGoC,CAAC,CAACnC,OAAO,CAAC;EACzE,IAAI,CAACuD,SAAS,EAAE,OAAOE,SAAS;EAChC,IAAIvB,CAAC,CAACjC,GAAG,GAAGiC,CAAC,CAAChC,OAAO,KAAKiC,CAAC,CAAClC,GAAG,EAAE,OAAOkC,CAAC,CAAClC,GAAG;EAC7C,IAAIkC,CAAC,CAAClC,GAAG,GAAGkC,CAAC,CAACjC,OAAO,KAAKgC,CAAC,CAACjC,GAAG,EAAE,OAAOiC,CAAC,CAACjC,GAAG;EAC7C,OAAOwD,SAAS;AAClB;AAEA,SAASJ,SAASA,CAACzD,IAAc,EAAY;EAC3C,OAAO;IACLG,GAAG,EAAEH,IAAI,CAACK,GAAG;IACbA,GAAG,EAAEL,IAAI,CAACG,GAAG;IACbC,OAAO,EAAEJ,IAAI,CAACM,OAAO;IACrBA,OAAO,EAAEN,IAAI,CAACI;EAChB,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Box, Point } from '../../model/diagram-ir.ts';
|
|
2
|
+
export type TagPosition = {
|
|
3
|
+
box: Box;
|
|
4
|
+
segment: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The first free position for a tag of `size` on the route: the longest
|
|
8
|
+
* segment first, and on each segment the fractions in FRACTIONS order. A
|
|
9
|
+
* label sits LABEL_GAP beside the segment (above, then below a horizontal
|
|
10
|
+
* one; right, then left of a vertical one). A badge sits centred on it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function tagPosition(size: {
|
|
13
|
+
w: number;
|
|
14
|
+
h: number;
|
|
15
|
+
}, points: Point[], placement: 'beside' | 'on', isFree: (box: Box) => boolean): TagPosition | undefined;
|
|
16
|
+
//# sourceMappingURL=labels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/labels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAM5D,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9B,MAAM,EAAE,KAAK,EAAE,EACf,SAAS,EAAE,QAAQ,GAAG,IAAI,EAC1B,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,GAC5B,WAAW,GAAG,SAAS,CAoBzB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
2
|
+
|
|
3
|
+
/** Where along a segment a tag is tried, in order. */
|
|
4
|
+
const FRACTIONS = [0.5, 0.3, 0.7, 0.15, 0.85];
|
|
5
|
+
/**
|
|
6
|
+
* The first free position for a tag of `size` on the route: the longest
|
|
7
|
+
* segment first, and on each segment the fractions in FRACTIONS order. A
|
|
8
|
+
* label sits LABEL_GAP beside the segment (above, then below a horizontal
|
|
9
|
+
* one; right, then left of a vertical one). A badge sits centred on it.
|
|
10
|
+
*/
|
|
11
|
+
export function tagPosition(size, points, placement, isFree) {
|
|
12
|
+
const segments = points.slice(1).map((to, segment) => ({
|
|
13
|
+
from: points[segment],
|
|
14
|
+
to,
|
|
15
|
+
segment
|
|
16
|
+
})).sort((a, b) => length(b.from, b.to) - length(a.from, a.to) || a.segment - b.segment);
|
|
17
|
+
for (const {
|
|
18
|
+
from,
|
|
19
|
+
to,
|
|
20
|
+
segment
|
|
21
|
+
} of segments) {
|
|
22
|
+
for (const t of FRACTIONS) {
|
|
23
|
+
const at = {
|
|
24
|
+
x: from.x + (to.x - from.x) * t,
|
|
25
|
+
y: from.y + (to.y - from.y) * t
|
|
26
|
+
};
|
|
27
|
+
for (const box of candidates(size, at, from.y === to.y, placement)) {
|
|
28
|
+
if (isFree(box)) return {
|
|
29
|
+
box,
|
|
30
|
+
segment
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
function candidates({
|
|
38
|
+
w,
|
|
39
|
+
h
|
|
40
|
+
}, at, horizontal, placement) {
|
|
41
|
+
const gap = LAYOUT_TOKENS.LABEL_GAP;
|
|
42
|
+
if (placement === 'on') return [{
|
|
43
|
+
x: at.x - w / 2,
|
|
44
|
+
y: at.y - h / 2,
|
|
45
|
+
w,
|
|
46
|
+
h
|
|
47
|
+
}];
|
|
48
|
+
if (horizontal) {
|
|
49
|
+
return [{
|
|
50
|
+
x: at.x - w / 2,
|
|
51
|
+
y: at.y - gap - h,
|
|
52
|
+
w,
|
|
53
|
+
h
|
|
54
|
+
}, {
|
|
55
|
+
x: at.x - w / 2,
|
|
56
|
+
y: at.y + gap,
|
|
57
|
+
w,
|
|
58
|
+
h
|
|
59
|
+
}];
|
|
60
|
+
}
|
|
61
|
+
return [{
|
|
62
|
+
x: at.x + gap,
|
|
63
|
+
y: at.y - h / 2,
|
|
64
|
+
w,
|
|
65
|
+
h
|
|
66
|
+
}, {
|
|
67
|
+
x: at.x - gap - w,
|
|
68
|
+
y: at.y - h / 2,
|
|
69
|
+
w,
|
|
70
|
+
h
|
|
71
|
+
}];
|
|
72
|
+
}
|
|
73
|
+
function length(a, b) {
|
|
74
|
+
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","names":["LAYOUT_TOKENS","FRACTIONS","tagPosition","size","points","placement","isFree","segments","slice","map","to","segment","from","sort","a","b","length","t","at","x","y","box","candidates","undefined","w","h","horizontal","gap","LABEL_GAP","Math","abs"],"sources":["../../../../src/lib/layouts/graph/labels.ts"],"sourcesContent":["import type { Box, Point } from '../../model/diagram-ir.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\n\n/** Where along a segment a tag is tried, in order. */\nconst FRACTIONS = [0.5, 0.3, 0.7, 0.15, 0.85];\n\nexport type TagPosition = { box: Box; segment: number };\n\n/**\n * The first free position for a tag of `size` on the route: the longest\n * segment first, and on each segment the fractions in FRACTIONS order. A\n * label sits LABEL_GAP beside the segment (above, then below a horizontal\n * one; right, then left of a vertical one). A badge sits centred on it.\n */\nexport function tagPosition(\n size: { w: number; h: number },\n points: Point[],\n placement: 'beside' | 'on',\n isFree: (box: Box) => boolean,\n): TagPosition | undefined {\n const segments = points\n .slice(1)\n .map((to, segment) => ({ from: points[segment]!, to, segment }))\n .sort(\n (a, b) =>\n length(b.from, b.to) - length(a.from, a.to) || a.segment - b.segment,\n );\n for (const { from, to, segment } of segments) {\n for (const t of FRACTIONS) {\n const at = {\n x: from.x + (to.x - from.x) * t,\n y: from.y + (to.y - from.y) * t,\n };\n for (const box of candidates(size, at, from.y === to.y, placement)) {\n if (isFree(box)) return { box, segment };\n }\n }\n }\n return undefined;\n}\n\nfunction candidates(\n { w, h }: { w: number; h: number },\n at: Point,\n horizontal: boolean,\n placement: 'beside' | 'on',\n): Box[] {\n const gap = LAYOUT_TOKENS.LABEL_GAP;\n if (placement === 'on') return [{ x: at.x - w / 2, y: at.y - h / 2, w, h }];\n if (horizontal) {\n return [\n { x: at.x - w / 2, y: at.y - gap - h, w, h },\n { x: at.x - w / 2, y: at.y + gap, w, h },\n ];\n }\n return [\n { x: at.x + gap, y: at.y - h / 2, w, h },\n { x: at.x - gap - w, y: at.y - h / 2, w, h },\n ];\n}\n\nfunction length(a: Point, b: Point): number {\n return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +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,
|
|
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,EAEV,WAAW,EAIZ,MAAM,0BAA0B,CAAC;AAalC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,GAAG,WAAW,CAoE3D"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { gridAreas } from "./areas.js";
|
|
2
2
|
import { gridGutters } from "./gutters.js";
|
|
3
|
-
import { measureGroupTitle, measureNode } from "./measure.js";
|
|
4
|
-
import {
|
|
3
|
+
import { measureGroupTitle, measureNode, placeGroupPorts } from "./measure.js";
|
|
4
|
+
import { routeGraph } from "./route.js";
|
|
5
|
+
import { LAYOUT_TOKENS } from "./tokens.js";
|
|
5
6
|
import { sizeTracks } from "./tracks.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -11,11 +12,10 @@ import { sizeTracks } from "./tracks.js";
|
|
|
11
12
|
* drawn without overlap.
|
|
12
13
|
*/
|
|
13
14
|
export function layoutGraph(ir) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const titles = new Map(ir.groups.map(group => [group.id, measureGroupTitle(group, tokens)]));
|
|
15
|
+
const measured = new Map(ir.nodes.map(node => [node.id, measureNode(node)]));
|
|
16
|
+
const titles = new Map(ir.groups.map(group => [group.id, measureGroupTitle(group)]));
|
|
17
17
|
const areas = gridAreas(ir);
|
|
18
|
-
const gutters = gridGutters(areas, new Map([...titles].map(([id, title]) => [id, title.height])), ir.edges
|
|
18
|
+
const gutters = gridGutters(areas, new Map([...titles].map(([id, title]) => [id, title.height])), ir.edges);
|
|
19
19
|
const items = axis => ir.nodes.map(node => {
|
|
20
20
|
const area = areas.nodes.get(node.id);
|
|
21
21
|
const {
|
|
@@ -46,12 +46,17 @@ export function layoutGraph(ir) {
|
|
|
46
46
|
};
|
|
47
47
|
});
|
|
48
48
|
const groups = areas.groups.map(groupArea => placeGroup(groupArea, titles.get(groupArea.group.id), lines, gutters));
|
|
49
|
+
const widestGutter = Math.max(...[...gutters.row, ...gutters.col].map(gutter => gutter.size));
|
|
50
|
+
const {
|
|
51
|
+
edges,
|
|
52
|
+
leaders
|
|
53
|
+
} = routeGraph(ir, nodes, groups, areas, 2 * widestGutter);
|
|
49
54
|
return {
|
|
50
55
|
nodes,
|
|
51
56
|
groups,
|
|
52
|
-
edges
|
|
53
|
-
leaders
|
|
54
|
-
viewBox: viewBoxOf(nodes, groups,
|
|
57
|
+
edges,
|
|
58
|
+
leaders,
|
|
59
|
+
viewBox: viewBoxOf(nodes, groups, edges, leaders)
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
62
|
function areaBox(area, lines) {
|
|
@@ -109,7 +114,8 @@ function placeGroup({
|
|
|
109
114
|
depth,
|
|
110
115
|
rect,
|
|
111
116
|
...title.place(rect),
|
|
112
|
-
dividers: group.dividers ? dividers(rect, area, title, group.labelSide, lines, gutters) : []
|
|
117
|
+
dividers: group.dividers ? dividers(rect, area, title, group.labelSide, lines, gutters) : [],
|
|
118
|
+
ports: placeGroupPorts(group.ports ?? [], rect)
|
|
113
119
|
};
|
|
114
120
|
}
|
|
115
121
|
|
|
@@ -142,9 +148,24 @@ function dividers(rect, area, title, labelSide, lines, gutters) {
|
|
|
142
148
|
}];
|
|
143
149
|
})];
|
|
144
150
|
}
|
|
145
|
-
function viewBoxOf(nodes, groups,
|
|
146
|
-
const
|
|
147
|
-
|
|
151
|
+
function viewBoxOf(nodes, groups, edges, leaders) {
|
|
152
|
+
const pointBox = ({
|
|
153
|
+
x,
|
|
154
|
+
y
|
|
155
|
+
}) => ({
|
|
156
|
+
x,
|
|
157
|
+
y,
|
|
158
|
+
w: 0,
|
|
159
|
+
h: 0
|
|
160
|
+
});
|
|
161
|
+
const boxes = [...nodes.map(nodeLayout => nodeLayout.visual), ...groups.map(groupLayout => groupLayout.rect), ...edges.flatMap(({
|
|
162
|
+
points,
|
|
163
|
+
label,
|
|
164
|
+
badge
|
|
165
|
+
}) => [...points.map(pointBox), ...(label ? [label.box] : []), ...(badge ? [badge.box] : [])]), ...leaders.flatMap(({
|
|
166
|
+
points
|
|
167
|
+
}) => points.map(pointBox))];
|
|
168
|
+
const pad = LAYOUT_TOKENS.CONTENT_PAD;
|
|
148
169
|
if (boxes.length === 0) return {
|
|
149
170
|
x: -pad,
|
|
150
171
|
y: -pad,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","names":["gridAreas","gridGutters","measureGroupTitle","measureNode","layoutTokens","sizeTracks","layoutGraph","ir","tokens","density","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 { type LayoutTokens, layoutTokens } 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 tokens = layoutTokens(ir.density);\n const measured = new Map(\n ir.nodes.map((node) => [node.id, measureNode(node, tokens)] as const),\n );\n const titles = new Map(\n ir.groups.map(\n (group) => [group.id, measureGroupTitle(group, 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 tokens,\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, tokens),\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(\n nodes: NodeLayout[],\n groups: GroupLayout[],\n tokens: LayoutTokens,\n): Box {\n const boxes = [\n ...nodes.map((nodeLayout) => nodeLayout.visual),\n ...groups.map((groupLayout) => groupLayout.rect),\n ];\n const pad = 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":["gridAreas","gridGutters","measureGroupTitle","measureNode","placeGroupPorts","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 { type CellArea, type GroupArea, gridAreas } from './areas.ts';\nimport type {\n EdgeLayout,\n GraphLayout,\n GroupLayout,\n LeaderLayout,\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 { 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.\n */\nexport function layoutGraph(ir: DiagramGraphIR): GraphLayout {\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 {\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: EdgeLayout[],\n leaders: LeaderLayout[],\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';
|
|
1
|
+
import type { Box, DiagramEdge, DiagramGroup, DiagramNode, DiagramNodePort, DiagramSide } from '../../model/diagram-ir.ts';
|
|
2
2
|
import type { NodeLayout, TextRun } from './graph-layout-result.ts';
|
|
3
|
-
import type { LayoutTokens } from './tokens.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,7 +14,9 @@ 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;
|
|
@@ -24,13 +25,13 @@ export type MeasuredGroupTitle = {
|
|
|
24
25
|
label: TextRun[];
|
|
25
26
|
};
|
|
26
27
|
};
|
|
27
|
-
export declare function measureGroupTitle(group: DiagramGroup
|
|
28
|
+
export declare function measureGroupTitle(group: DiagramGroup): MeasuredGroupTitle;
|
|
28
29
|
export type MeasuredEdgeLabel = {
|
|
29
30
|
w: number;
|
|
30
31
|
h: number;
|
|
31
32
|
place(box: Box): TextRun[];
|
|
32
33
|
};
|
|
33
|
-
export declare function measureEdgeLabel(edge: DiagramEdge
|
|
34
|
+
export declare function measureEdgeLabel(edge: DiagramEdge): MeasuredEdgeLabel;
|
|
34
35
|
export type MeasuredEdgeBadge = {
|
|
35
36
|
w: number;
|
|
36
37
|
h: number;
|
|
@@ -39,6 +40,6 @@ export type MeasuredEdgeBadge = {
|
|
|
39
40
|
text: TextRun[];
|
|
40
41
|
};
|
|
41
42
|
};
|
|
42
|
-
export declare function measureEdgeBadge(edge: DiagramEdge
|
|
43
|
+
export declare function measureEdgeBadge(edge: DiagramEdge): MeasuredEdgeBadge;
|
|
43
44
|
export {};
|
|
44
45
|
//# 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,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAKpE,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,CAiD3D;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;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,kBAAkB,CA2BzE;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"}
|