@crazyhappyone/auto-graph 0.0.2 → 0.0.4
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/cli/index.cjs +737 -28
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +737 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +737 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +737 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1200,6 +1200,7 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1200
1200
|
const measurer = options.textMeasurer ?? createDefaultTextMeasurer();
|
|
1201
1201
|
const routeKind = dsl.routing?.kind ?? "orthogonal";
|
|
1202
1202
|
const portShifting = normalizePortShifting(dsl.routing?.portShifting);
|
|
1203
|
+
const primaryReadingDirection = dsl.layout?.primaryReadingDirection;
|
|
1203
1204
|
const diagram = {
|
|
1204
1205
|
id: options.id ?? dsl.id ?? "diagram",
|
|
1205
1206
|
...dsl.title === void 0 ? {} : { title: dsl.title },
|
|
@@ -1213,6 +1214,7 @@ function normalizeDiagramDsl(dslValue, options = {}) {
|
|
|
1213
1214
|
...dsl.frame === void 0 ? {} : { frame: normalizeFrame(dsl.frame) },
|
|
1214
1215
|
metadata: {
|
|
1215
1216
|
routeKind,
|
|
1217
|
+
...primaryReadingDirection === void 0 ? {} : { primaryReadingDirection },
|
|
1216
1218
|
...portShifting === void 0 ? {} : { portShifting }
|
|
1217
1219
|
}
|
|
1218
1220
|
};
|
|
@@ -1383,14 +1385,17 @@ function formatCompartmentEntry(value) {
|
|
|
1383
1385
|
return `${entry[0]}: ${entry[1]}`;
|
|
1384
1386
|
}
|
|
1385
1387
|
function normalizeSwimlanes(dsl) {
|
|
1386
|
-
return Object.keys(dsl.swimlanes ?? {}).
|
|
1388
|
+
return Object.keys(dsl.swimlanes ?? {}).map((id) => {
|
|
1387
1389
|
const swimlane = dsl.swimlanes?.[id];
|
|
1388
1390
|
const label = toLabel(swimlane?.label);
|
|
1389
1391
|
return {
|
|
1390
1392
|
id,
|
|
1391
1393
|
...label === void 0 ? {} : { label },
|
|
1392
1394
|
orientation: swimlane?.orientation ?? "vertical",
|
|
1393
|
-
|
|
1395
|
+
layout: swimlane?.layout ?? "overlay",
|
|
1396
|
+
...swimlane?.headerHeight === void 0 ? {} : { headerHeight: swimlane.headerHeight },
|
|
1397
|
+
...swimlane?.padding === void 0 ? {} : { padding: swimlane.padding },
|
|
1398
|
+
lanes: Object.keys(swimlane?.lanes ?? {}).map((laneId) => {
|
|
1394
1399
|
const lane = swimlane?.lanes[laneId];
|
|
1395
1400
|
const laneLabel = toLabel(lane?.label);
|
|
1396
1401
|
return {
|
|
@@ -1468,11 +1473,6 @@ function validateReferences(dsl) {
|
|
|
1468
1473
|
const diagnostics = [];
|
|
1469
1474
|
const nodeIds = new Set(Object.keys(dsl.nodes));
|
|
1470
1475
|
const groupIds = new Set(Object.keys(dsl.groups ?? {}));
|
|
1471
|
-
const swimlaneLaneIds = new Set(
|
|
1472
|
-
Object.entries(dsl.swimlanes ?? {}).flatMap(
|
|
1473
|
-
([swimlaneId, swimlane]) => Object.keys(swimlane.lanes).map((laneId) => `${swimlaneId}.${laneId}`)
|
|
1474
|
-
)
|
|
1475
|
-
);
|
|
1476
1476
|
(dsl.edges ?? []).forEach((edge, index) => {
|
|
1477
1477
|
if (typeof edge === "string") {
|
|
1478
1478
|
return;
|
|
@@ -1580,10 +1580,12 @@ function validateReferences(dsl) {
|
|
|
1580
1580
|
break;
|
|
1581
1581
|
case "containment": {
|
|
1582
1582
|
const container = constraint.containerId ?? constraint.container;
|
|
1583
|
-
if (container !== void 0
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1583
|
+
if (container !== void 0) {
|
|
1584
|
+
if (!nodeIds.has(container)) {
|
|
1585
|
+
diagnostics.push(
|
|
1586
|
+
referenceMissing(["constraints", index, "container"], container)
|
|
1587
|
+
);
|
|
1588
|
+
}
|
|
1587
1589
|
}
|
|
1588
1590
|
(constraint.childIds ?? constraint.children ?? []).forEach(
|
|
1589
1591
|
(child, childIndex) => {
|
|
@@ -1660,6 +1662,10 @@ var routeKindSchema = zod.z.enum(["orthogonal", "straight"]);
|
|
|
1660
1662
|
var outputFormatSchema = zod.z.enum(["svg", "excalidraw"]);
|
|
1661
1663
|
var edgeStrokeStyleSchema = zod.z.enum(["solid", "dashed"]);
|
|
1662
1664
|
var edgeArrowheadSchema = zod.z.enum(["triangle", "hollowTriangle"]);
|
|
1665
|
+
var primaryReadingDirectionSchema = zod.z.enum([
|
|
1666
|
+
"top_to_bottom",
|
|
1667
|
+
"top-to-bottom"
|
|
1668
|
+
]);
|
|
1663
1669
|
var nodeShapeSchema = zod.z.enum([
|
|
1664
1670
|
"rectangle",
|
|
1665
1671
|
"rounded-rectangle",
|
|
@@ -1670,6 +1676,7 @@ var nodeShapeSchema = zod.z.enum([
|
|
|
1670
1676
|
"cylinder"
|
|
1671
1677
|
]);
|
|
1672
1678
|
var finiteNumberSchema = zod.z.number().finite();
|
|
1679
|
+
var nonNegativeNumberSchema = finiteNumberSchema.min(0);
|
|
1673
1680
|
var pointSchema = zod.z.object({
|
|
1674
1681
|
x: finiteNumberSchema,
|
|
1675
1682
|
y: finiteNumberSchema
|
|
@@ -1756,6 +1763,9 @@ var groupSchema = zod.z.object({
|
|
|
1756
1763
|
var swimlaneSchema = zod.z.object({
|
|
1757
1764
|
label: labelSchema.optional(),
|
|
1758
1765
|
orientation: zod.z.enum(["vertical", "horizontal"]).optional(),
|
|
1766
|
+
layout: zod.z.enum(["overlay", "contract"]).optional(),
|
|
1767
|
+
headerHeight: nonNegativeNumberSchema.optional(),
|
|
1768
|
+
padding: nonNegativeNumberSchema.optional(),
|
|
1759
1769
|
lanes: zod.z.record(
|
|
1760
1770
|
zod.z.string(),
|
|
1761
1771
|
zod.z.object({
|
|
@@ -1821,7 +1831,8 @@ var diagramDslSchema = zod.z.object({
|
|
|
1821
1831
|
title: zod.z.string().optional(),
|
|
1822
1832
|
direction: directionSchema.optional(),
|
|
1823
1833
|
layout: zod.z.object({
|
|
1824
|
-
direction: directionSchema.optional()
|
|
1834
|
+
direction: directionSchema.optional(),
|
|
1835
|
+
primaryReadingDirection: primaryReadingDirectionSchema.optional()
|
|
1825
1836
|
}).optional(),
|
|
1826
1837
|
routing: zod.z.object({
|
|
1827
1838
|
kind: routeKindSchema.optional(),
|
|
@@ -2351,15 +2362,30 @@ function renderSwimlane(swimlane) {
|
|
|
2351
2362
|
lines.push(
|
|
2352
2363
|
` <rect class="swimlane-lane" data-lane="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.box.x)}" y="${formatNumber(lane.box.y)}" width="${formatNumber(lane.box.width)}" height="${formatNumber(lane.box.height)}" fill="none" stroke="${STROKE}"/>`
|
|
2353
2364
|
);
|
|
2354
|
-
if (lane.
|
|
2365
|
+
if (lane.headerBox !== void 0) {
|
|
2366
|
+
lines.push(
|
|
2367
|
+
` <rect class="swimlane-header" data-lane-header="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.headerBox.x)}" y="${formatNumber(lane.headerBox.y)}" width="${formatNumber(lane.headerBox.width)}" height="${formatNumber(lane.headerBox.height)}" fill="#f3f4f6" stroke="${STROKE}"/>`
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
if (lane.contentBox !== void 0) {
|
|
2355
2371
|
lines.push(
|
|
2356
|
-
` <
|
|
2372
|
+
` <rect class="swimlane-content" data-lane-content="${escapeAttribute(`${swimlane.id}.${lane.id}`)}" x="${formatNumber(lane.contentBox.x)}" y="${formatNumber(lane.contentBox.y)}" width="${formatNumber(lane.contentBox.width)}" height="${formatNumber(lane.contentBox.height)}" fill="none" stroke="none"/>`
|
|
2357
2373
|
);
|
|
2358
2374
|
}
|
|
2375
|
+
if (lane.label?.text !== void 0) {
|
|
2376
|
+
const labelBox = lane.headerBox ?? lane.box;
|
|
2377
|
+
lines.push(renderSwimlaneLabel(swimlane, lane.label.text, labelBox));
|
|
2378
|
+
}
|
|
2359
2379
|
}
|
|
2360
2380
|
lines.push(" </g>");
|
|
2361
2381
|
return lines;
|
|
2362
2382
|
}
|
|
2383
|
+
function renderSwimlaneLabel(swimlane, text, labelBox) {
|
|
2384
|
+
const x = labelBox.x + labelBox.width / 2;
|
|
2385
|
+
const y = labelBox.y + labelBox.height / 2;
|
|
2386
|
+
const transform = swimlane.orientation === "horizontal" ? ` transform="rotate(-90 ${formatNumber(x)} ${formatNumber(y)})"` : "";
|
|
2387
|
+
return ` <text class="swimlane-label" x="${formatNumber(x)}" y="${formatNumber(y)}" text-anchor="middle" dominant-baseline="middle"${transform} font-family="${FONT_FAMILY}" font-size="12" fill="#111827">${escapeXml(text)}</text>`;
|
|
2388
|
+
}
|
|
2363
2389
|
function renderPorts(node) {
|
|
2364
2390
|
return (node.ports ?? []).flatMap((port) => [
|
|
2365
2391
|
` <rect class="port" data-kind="${escapeAttribute(port.kind)}" data-port="${escapeAttribute(`${node.id}.${port.id}`)}" x="${formatNumber(port.box.x)}" y="${formatNumber(port.box.y)}" width="${formatNumber(port.box.width)}" height="${formatNumber(port.box.height)}" fill="${escapeAttribute(port.style?.fill ?? "#d9ead3")}" stroke="${escapeAttribute(port.style?.stroke ?? STROKE)}"/>`,
|
|
@@ -2425,7 +2451,7 @@ function renderRect(box, attributes) {
|
|
|
2425
2451
|
function renderLabel(label, box, item) {
|
|
2426
2452
|
const labelLayout = item.labelLayout;
|
|
2427
2453
|
if (labelLayout?.lines !== void 0 && labelLayout.lines.length > 0) {
|
|
2428
|
-
const offset =
|
|
2454
|
+
const offset = { x: box.x, y: box.y };
|
|
2429
2455
|
return [
|
|
2430
2456
|
` <text class="label" data-for="${escapeAttribute(item.id)}" font-family="${FONT_FAMILY}" font-size="${formatNumber(labelLayout.font.fontSize)}" fill="#111827">`,
|
|
2431
2457
|
...labelLayout.lines.map(
|
|
@@ -2524,9 +2550,6 @@ function pathPointsBeforeArrowhead(points) {
|
|
|
2524
2550
|
};
|
|
2525
2551
|
return [...points.slice(0, -1), base];
|
|
2526
2552
|
}
|
|
2527
|
-
function isAbsoluteLabelLayout(labelBox, itemBox) {
|
|
2528
|
-
return labelBox.x >= itemBox.x && labelBox.y >= itemBox.y && labelBox.x + labelBox.width <= itemBox.x + itemBox.width && labelBox.y + labelBox.height <= itemBox.y + itemBox.height;
|
|
2529
|
-
}
|
|
2530
2553
|
function shapePoints(shape, box) {
|
|
2531
2554
|
const left = box.x;
|
|
2532
2555
|
const right = box.x + box.width;
|
|
@@ -2940,6 +2963,19 @@ function solveDiagram(diagram, options = {}) {
|
|
|
2940
2963
|
constraints
|
|
2941
2964
|
});
|
|
2942
2965
|
diagnostics.push(...constrained.diagnostics);
|
|
2966
|
+
const swimlaneContracts = applySwimlaneLayoutContracts(
|
|
2967
|
+
diagram.swimlanes ?? [],
|
|
2968
|
+
constraints,
|
|
2969
|
+
edges,
|
|
2970
|
+
isTopToBottomReadingDirection(diagram.metadata?.primaryReadingDirection),
|
|
2971
|
+
constrained.boxes,
|
|
2972
|
+
constrained.locks,
|
|
2973
|
+
options?.overlapSpacing ?? 40
|
|
2974
|
+
);
|
|
2975
|
+
if (swimlaneContracts.layouts.size > 0) {
|
|
2976
|
+
removeResolvedOverlapDiagnostics(diagnostics, constrained.boxes);
|
|
2977
|
+
}
|
|
2978
|
+
diagnostics.push(...swimlaneContracts.diagnostics);
|
|
2943
2979
|
const coordinatedNodes = coordinateNodes(
|
|
2944
2980
|
nodes,
|
|
2945
2981
|
constrained.boxes,
|
|
@@ -2964,7 +3000,8 @@ function solveDiagram(diagram, options = {}) {
|
|
|
2964
3000
|
);
|
|
2965
3001
|
const coordinatedSwimlanes = coordinateSwimlanes(
|
|
2966
3002
|
diagram.swimlanes ?? [],
|
|
2967
|
-
constrained.boxes
|
|
3003
|
+
constrained.boxes,
|
|
3004
|
+
swimlaneContracts.layouts
|
|
2968
3005
|
);
|
|
2969
3006
|
const groupBoxes = new Map(
|
|
2970
3007
|
coordinatedGroups.map((group) => [group.id, group.box])
|
|
@@ -3006,6 +3043,591 @@ function solveDiagram(diagram, options = {}) {
|
|
|
3006
3043
|
...diagram.metadata === void 0 ? {} : { metadata: diagram.metadata }
|
|
3007
3044
|
};
|
|
3008
3045
|
}
|
|
3046
|
+
function applySwimlaneLayoutContracts(swimlanes, constraints, edges, topToBottomFlow, nodeBoxes, locks, overlapSpacing) {
|
|
3047
|
+
const layouts = /* @__PURE__ */ new Map();
|
|
3048
|
+
const diagnostics = [];
|
|
3049
|
+
const movedChildIds = /* @__PURE__ */ new Set();
|
|
3050
|
+
for (const swimlane of swimlanes) {
|
|
3051
|
+
if ((swimlane.layout ?? "overlay") !== "contract") {
|
|
3052
|
+
continue;
|
|
3053
|
+
}
|
|
3054
|
+
if (swimlane.lanes.length === 0) {
|
|
3055
|
+
continue;
|
|
3056
|
+
}
|
|
3057
|
+
const layout2 = applySingleSwimlaneContract(
|
|
3058
|
+
swimlane,
|
|
3059
|
+
edges,
|
|
3060
|
+
topToBottomFlow,
|
|
3061
|
+
nodeBoxes,
|
|
3062
|
+
locks,
|
|
3063
|
+
diagnostics,
|
|
3064
|
+
movedChildIds
|
|
3065
|
+
);
|
|
3066
|
+
if (layout2 !== void 0) {
|
|
3067
|
+
layouts.set(swimlane.id, layout2);
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
if (layouts.size > 0) {
|
|
3071
|
+
diagnostics.push(
|
|
3072
|
+
...reportSwimlaneOverlaps(nodeBoxes, locks, overlapSpacing),
|
|
3073
|
+
...reportSwimlaneConstraintInvalidations(
|
|
3074
|
+
constraints,
|
|
3075
|
+
nodeBoxes,
|
|
3076
|
+
movedChildIds
|
|
3077
|
+
)
|
|
3078
|
+
);
|
|
3079
|
+
}
|
|
3080
|
+
return { layouts, diagnostics, movedChildIds };
|
|
3081
|
+
}
|
|
3082
|
+
function applySingleSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, locks, diagnostics, movedChildIds) {
|
|
3083
|
+
const headerHeight = swimlane.headerHeight ?? 28;
|
|
3084
|
+
const padding = swimlane.padding ?? 16;
|
|
3085
|
+
const laneBounds = swimlane.lanes.map((lane) => {
|
|
3086
|
+
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
3087
|
+
return childBoxes.length === 0 ? void 0 : unionBoxes(childBoxes);
|
|
3088
|
+
});
|
|
3089
|
+
const populatedBounds = laneBounds.filter(
|
|
3090
|
+
(box) => box !== void 0
|
|
3091
|
+
);
|
|
3092
|
+
if (populatedBounds.length === 0) {
|
|
3093
|
+
return void 0;
|
|
3094
|
+
}
|
|
3095
|
+
if (swimlane.orientation === "vertical") {
|
|
3096
|
+
return applyVerticalSwimlaneContract(
|
|
3097
|
+
swimlane,
|
|
3098
|
+
edges,
|
|
3099
|
+
topToBottomFlow,
|
|
3100
|
+
nodeBoxes,
|
|
3101
|
+
laneBounds,
|
|
3102
|
+
headerHeight,
|
|
3103
|
+
padding,
|
|
3104
|
+
locks,
|
|
3105
|
+
diagnostics,
|
|
3106
|
+
movedChildIds
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
return applyHorizontalSwimlaneContract(
|
|
3110
|
+
swimlane,
|
|
3111
|
+
nodeBoxes,
|
|
3112
|
+
laneBounds,
|
|
3113
|
+
headerHeight,
|
|
3114
|
+
padding,
|
|
3115
|
+
locks,
|
|
3116
|
+
diagnostics,
|
|
3117
|
+
movedChildIds
|
|
3118
|
+
);
|
|
3119
|
+
}
|
|
3120
|
+
function applyVerticalSwimlaneContract(swimlane, edges, topToBottomFlow, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds) {
|
|
3121
|
+
const populatedBounds = laneBounds.filter(
|
|
3122
|
+
(box) => box !== void 0
|
|
3123
|
+
);
|
|
3124
|
+
const top = Math.min(...populatedBounds.map((box) => box.y));
|
|
3125
|
+
const left = Math.min(...populatedBounds.map((box) => box.x));
|
|
3126
|
+
const maxChildHeight = Math.max(...populatedBounds.map((box) => box.height));
|
|
3127
|
+
const flowRanks = topToBottomFlow ? rankVerticalSwimlaneChildren(swimlane, edges) : /* @__PURE__ */ new Map();
|
|
3128
|
+
const maxRank = flowRanks.size === 0 ? 0 : Math.max(...Array.from(flowRanks.values()));
|
|
3129
|
+
const rankStackGap = Math.max(8, padding / 2);
|
|
3130
|
+
const maxRankStackHeight = maxVerticalRankStackHeight(
|
|
3131
|
+
swimlane,
|
|
3132
|
+
nodeBoxes,
|
|
3133
|
+
flowRanks,
|
|
3134
|
+
rankStackGap
|
|
3135
|
+
);
|
|
3136
|
+
const rankSpacing = Math.max(96, maxRankStackHeight + padding);
|
|
3137
|
+
const contentHeight = maxRank === 0 ? maxChildHeight : maxRankStackHeight + maxRank * rankSpacing;
|
|
3138
|
+
const slotWidth = Math.max(...populatedBounds.map((box) => box.width)) + padding * 2;
|
|
3139
|
+
const laneContentTop = top + headerHeight + padding;
|
|
3140
|
+
for (let index = 0; index < swimlane.lanes.length; index += 1) {
|
|
3141
|
+
const lane = swimlane.lanes[index];
|
|
3142
|
+
const bounds = laneBounds[index];
|
|
3143
|
+
if (lane === void 0 || bounds === void 0) {
|
|
3144
|
+
continue;
|
|
3145
|
+
}
|
|
3146
|
+
const target = {
|
|
3147
|
+
x: left + slotWidth * index + padding,
|
|
3148
|
+
y: laneContentTop
|
|
3149
|
+
};
|
|
3150
|
+
if (maxRank === 0) {
|
|
3151
|
+
moveLaneChildren(
|
|
3152
|
+
lane.children,
|
|
3153
|
+
nodeBoxes,
|
|
3154
|
+
locks,
|
|
3155
|
+
diagnostics,
|
|
3156
|
+
movedChildIds,
|
|
3157
|
+
{
|
|
3158
|
+
x: target.x - bounds.x,
|
|
3159
|
+
y: target.y - bounds.y
|
|
3160
|
+
}
|
|
3161
|
+
);
|
|
3162
|
+
continue;
|
|
3163
|
+
}
|
|
3164
|
+
moveRankedVerticalLaneChildren(
|
|
3165
|
+
lane.children,
|
|
3166
|
+
nodeBoxes,
|
|
3167
|
+
locks,
|
|
3168
|
+
diagnostics,
|
|
3169
|
+
movedChildIds,
|
|
3170
|
+
flowRanks,
|
|
3171
|
+
rankSpacing,
|
|
3172
|
+
rankStackGap,
|
|
3173
|
+
{
|
|
3174
|
+
x: target.x - bounds.x,
|
|
3175
|
+
y: laneContentTop
|
|
3176
|
+
}
|
|
3177
|
+
);
|
|
3178
|
+
}
|
|
3179
|
+
return {
|
|
3180
|
+
box: {
|
|
3181
|
+
x: left,
|
|
3182
|
+
y: top,
|
|
3183
|
+
width: slotWidth * swimlane.lanes.length,
|
|
3184
|
+
height: contentHeight + padding * 2 + headerHeight
|
|
3185
|
+
},
|
|
3186
|
+
slotWidth,
|
|
3187
|
+
slotHeight: contentHeight + padding * 2 + headerHeight
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
function isTopToBottomReadingDirection(value) {
|
|
3191
|
+
return value === "top_to_bottom" || value === "top-to-bottom";
|
|
3192
|
+
}
|
|
3193
|
+
function rankVerticalSwimlaneChildren(swimlane, edges) {
|
|
3194
|
+
const childOrder = /* @__PURE__ */ new Map();
|
|
3195
|
+
for (const lane of swimlane.lanes) {
|
|
3196
|
+
for (const childId of lane.children) {
|
|
3197
|
+
if (!childOrder.has(childId)) {
|
|
3198
|
+
childOrder.set(childId, childOrder.size);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
if (childOrder.size === 0) {
|
|
3203
|
+
return /* @__PURE__ */ new Map();
|
|
3204
|
+
}
|
|
3205
|
+
const childIds = new Set(childOrder.keys());
|
|
3206
|
+
const relevantEdges = edges.filter(
|
|
3207
|
+
(edge) => childIds.has(edge.source.nodeId) && childIds.has(edge.target.nodeId) && edge.source.nodeId !== edge.target.nodeId
|
|
3208
|
+
);
|
|
3209
|
+
if (relevantEdges.length === 0) {
|
|
3210
|
+
return /* @__PURE__ */ new Map();
|
|
3211
|
+
}
|
|
3212
|
+
const ranks = new Map([...childIds].map((id) => [id, 0]));
|
|
3213
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
3214
|
+
const inDegree = new Map([...childIds].map((id) => [id, 0]));
|
|
3215
|
+
for (const edge of relevantEdges) {
|
|
3216
|
+
const targets = outgoing.get(edge.source.nodeId) ?? [];
|
|
3217
|
+
targets.push(edge.target.nodeId);
|
|
3218
|
+
outgoing.set(edge.source.nodeId, targets);
|
|
3219
|
+
inDegree.set(
|
|
3220
|
+
edge.target.nodeId,
|
|
3221
|
+
(inDegree.get(edge.target.nodeId) ?? 0) + 1
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
const queue = [...childIds].filter((id) => (inDegree.get(id) ?? 0) === 0).sort((a, b) => (childOrder.get(a) ?? 0) - (childOrder.get(b) ?? 0));
|
|
3225
|
+
let visited = 0;
|
|
3226
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
3227
|
+
const sourceId = queue[cursor];
|
|
3228
|
+
if (sourceId === void 0) {
|
|
3229
|
+
continue;
|
|
3230
|
+
}
|
|
3231
|
+
visited += 1;
|
|
3232
|
+
for (const targetId of outgoing.get(sourceId) ?? []) {
|
|
3233
|
+
ranks.set(
|
|
3234
|
+
targetId,
|
|
3235
|
+
Math.max(ranks.get(targetId) ?? 0, (ranks.get(sourceId) ?? 0) + 1)
|
|
3236
|
+
);
|
|
3237
|
+
const nextInDegree = (inDegree.get(targetId) ?? 0) - 1;
|
|
3238
|
+
inDegree.set(targetId, nextInDegree);
|
|
3239
|
+
if (nextInDegree === 0) {
|
|
3240
|
+
queue.push(targetId);
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
return visited === childIds.size ? ranks : rankCyclicSwimlaneChildren(childIds, relevantEdges);
|
|
3245
|
+
}
|
|
3246
|
+
function rankCyclicSwimlaneChildren(childIds, edges) {
|
|
3247
|
+
const maxRank = Math.max(0, childIds.size - 1);
|
|
3248
|
+
const ranks = new Map([...childIds].map((id) => [id, 0]));
|
|
3249
|
+
for (let iteration = 0; iteration < childIds.size; iteration += 1) {
|
|
3250
|
+
let changed = false;
|
|
3251
|
+
for (const edge of edges) {
|
|
3252
|
+
const nextRank = Math.min(
|
|
3253
|
+
maxRank,
|
|
3254
|
+
(ranks.get(edge.source.nodeId) ?? 0) + 1
|
|
3255
|
+
);
|
|
3256
|
+
if (nextRank > (ranks.get(edge.target.nodeId) ?? 0)) {
|
|
3257
|
+
ranks.set(edge.target.nodeId, nextRank);
|
|
3258
|
+
changed = true;
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
if (!changed) {
|
|
3262
|
+
break;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
return ranks;
|
|
3266
|
+
}
|
|
3267
|
+
function maxVerticalRankStackHeight(swimlane, nodeBoxes, flowRanks, gap) {
|
|
3268
|
+
let maxHeight = 0;
|
|
3269
|
+
for (const lane of swimlane.lanes) {
|
|
3270
|
+
for (const stack of rankStacks(
|
|
3271
|
+
lane.children,
|
|
3272
|
+
nodeBoxes,
|
|
3273
|
+
flowRanks
|
|
3274
|
+
).values()) {
|
|
3275
|
+
const height = stack.reduce(
|
|
3276
|
+
(total, item, index) => total + item.box.height + (index === 0 ? 0 : gap),
|
|
3277
|
+
0
|
|
3278
|
+
);
|
|
3279
|
+
maxHeight = Math.max(maxHeight, height);
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
return maxHeight;
|
|
3283
|
+
}
|
|
3284
|
+
function moveRankedVerticalLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, flowRanks, rankSpacing, rankStackGap, target) {
|
|
3285
|
+
for (const [rank, stack] of rankStacks(childIds, nodeBoxes, flowRanks)) {
|
|
3286
|
+
let yOffset = 0;
|
|
3287
|
+
for (const item of stack) {
|
|
3288
|
+
const { childId, box } = item;
|
|
3289
|
+
if (locks.has(childId)) {
|
|
3290
|
+
diagnostics.push({
|
|
3291
|
+
severity: "warning",
|
|
3292
|
+
code: "constraints.locked-target-not-moved",
|
|
3293
|
+
message: `Locked child ${childId} was not moved into contract swimlane slot.`,
|
|
3294
|
+
path: ["swimlanes"],
|
|
3295
|
+
detail: { nodeId: childId }
|
|
3296
|
+
});
|
|
3297
|
+
continue;
|
|
3298
|
+
}
|
|
3299
|
+
const next = {
|
|
3300
|
+
...box,
|
|
3301
|
+
x: box.x + target.x,
|
|
3302
|
+
y: target.y + rank * rankSpacing + yOffset
|
|
3303
|
+
};
|
|
3304
|
+
if (next.x !== box.x || next.y !== box.y) {
|
|
3305
|
+
movedChildIds.add(childId);
|
|
3306
|
+
}
|
|
3307
|
+
nodeBoxes.set(childId, next);
|
|
3308
|
+
yOffset += box.height + rankStackGap;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
function rankStacks(childIds, nodeBoxes, flowRanks) {
|
|
3313
|
+
const stacks = /* @__PURE__ */ new Map();
|
|
3314
|
+
for (const childId of childIds) {
|
|
3315
|
+
const box = nodeBoxes.get(childId);
|
|
3316
|
+
if (box === void 0) {
|
|
3317
|
+
continue;
|
|
3318
|
+
}
|
|
3319
|
+
const rank = flowRanks.get(childId) ?? 0;
|
|
3320
|
+
const stack = stacks.get(rank) ?? [];
|
|
3321
|
+
stack.push({ childId, box });
|
|
3322
|
+
stacks.set(rank, stack);
|
|
3323
|
+
}
|
|
3324
|
+
for (const stack of stacks.values()) {
|
|
3325
|
+
stack.sort((a, b) => {
|
|
3326
|
+
const deltaY = a.box.y - b.box.y;
|
|
3327
|
+
return deltaY === 0 ? a.childId.localeCompare(b.childId) : deltaY;
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
return stacks;
|
|
3331
|
+
}
|
|
3332
|
+
function applyHorizontalSwimlaneContract(swimlane, nodeBoxes, laneBounds, headerHeight, padding, locks, diagnostics, movedChildIds) {
|
|
3333
|
+
const populatedBounds = laneBounds.filter(
|
|
3334
|
+
(box) => box !== void 0
|
|
3335
|
+
);
|
|
3336
|
+
const top = Math.min(...populatedBounds.map((box) => box.y));
|
|
3337
|
+
const left = Math.min(...populatedBounds.map((box) => box.x));
|
|
3338
|
+
const slotWidth = Math.max(...populatedBounds.map((box) => box.width)) + headerHeight + padding * 2;
|
|
3339
|
+
const slotHeight = Math.max(...populatedBounds.map((box) => box.height)) + padding * 2;
|
|
3340
|
+
for (let index = 0; index < swimlane.lanes.length; index += 1) {
|
|
3341
|
+
const lane = swimlane.lanes[index];
|
|
3342
|
+
const bounds = laneBounds[index];
|
|
3343
|
+
if (lane === void 0 || bounds === void 0) {
|
|
3344
|
+
continue;
|
|
3345
|
+
}
|
|
3346
|
+
const target = {
|
|
3347
|
+
x: left + headerHeight + padding,
|
|
3348
|
+
y: top + slotHeight * index + padding
|
|
3349
|
+
};
|
|
3350
|
+
moveLaneChildren(
|
|
3351
|
+
lane.children,
|
|
3352
|
+
nodeBoxes,
|
|
3353
|
+
locks,
|
|
3354
|
+
diagnostics,
|
|
3355
|
+
movedChildIds,
|
|
3356
|
+
{
|
|
3357
|
+
x: target.x - bounds.x,
|
|
3358
|
+
y: target.y - bounds.y
|
|
3359
|
+
}
|
|
3360
|
+
);
|
|
3361
|
+
}
|
|
3362
|
+
return {
|
|
3363
|
+
box: {
|
|
3364
|
+
x: left,
|
|
3365
|
+
y: top,
|
|
3366
|
+
width: slotWidth,
|
|
3367
|
+
height: slotHeight * swimlane.lanes.length
|
|
3368
|
+
},
|
|
3369
|
+
slotWidth,
|
|
3370
|
+
slotHeight
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
function moveLaneChildren(childIds, nodeBoxes, locks, diagnostics, movedChildIds, offset) {
|
|
3374
|
+
for (const childId of childIds) {
|
|
3375
|
+
const box = nodeBoxes.get(childId);
|
|
3376
|
+
if (box === void 0) {
|
|
3377
|
+
continue;
|
|
3378
|
+
}
|
|
3379
|
+
if (locks.has(childId)) {
|
|
3380
|
+
diagnostics.push({
|
|
3381
|
+
severity: "warning",
|
|
3382
|
+
code: "constraints.locked-target-not-moved",
|
|
3383
|
+
message: `Locked child ${childId} was not moved into contract swimlane slot.`,
|
|
3384
|
+
path: ["swimlanes"],
|
|
3385
|
+
detail: { nodeId: childId }
|
|
3386
|
+
});
|
|
3387
|
+
continue;
|
|
3388
|
+
}
|
|
3389
|
+
if (offset.x !== 0 || offset.y !== 0) {
|
|
3390
|
+
movedChildIds.add(childId);
|
|
3391
|
+
}
|
|
3392
|
+
nodeBoxes.set(childId, {
|
|
3393
|
+
...box,
|
|
3394
|
+
x: box.x + offset.x,
|
|
3395
|
+
y: box.y + offset.y
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
function removeResolvedOverlapDiagnostics(diagnostics, nodeBoxes) {
|
|
3400
|
+
for (let index = diagnostics.length - 1; index >= 0; index -= 1) {
|
|
3401
|
+
const diagnostic = diagnostics[index];
|
|
3402
|
+
if (diagnostic?.code !== "constraints.overlap.unresolved") {
|
|
3403
|
+
continue;
|
|
3404
|
+
}
|
|
3405
|
+
const firstId = detailString(diagnostic, "firstId");
|
|
3406
|
+
const secondId = detailString(diagnostic, "secondId");
|
|
3407
|
+
const first = firstId === void 0 ? void 0 : nodeBoxes.get(firstId);
|
|
3408
|
+
const second = secondId === void 0 ? void 0 : nodeBoxes.get(secondId);
|
|
3409
|
+
if (first !== void 0 && second !== void 0 && !intersectsAabb(first, second)) {
|
|
3410
|
+
diagnostics.splice(index, 1);
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
function reportSwimlaneConstraintInvalidations(constraints, nodeBoxes, movedChildIds) {
|
|
3415
|
+
const diagnostics = [];
|
|
3416
|
+
for (const constraint of constraints) {
|
|
3417
|
+
const invalidatedNodeIds = movedConstraintNodeIds(
|
|
3418
|
+
constraint,
|
|
3419
|
+
nodeBoxes,
|
|
3420
|
+
movedChildIds
|
|
3421
|
+
);
|
|
3422
|
+
if (invalidatedNodeIds.length === 0) {
|
|
3423
|
+
continue;
|
|
3424
|
+
}
|
|
3425
|
+
diagnostics.push({
|
|
3426
|
+
severity: "warning",
|
|
3427
|
+
code: "constraints.swimlane-contract.invalidated",
|
|
3428
|
+
message: `Contract swimlane placement moved node(s) after ${constraint.kind} constraint solving; final geometry no longer satisfies that constraint.`,
|
|
3429
|
+
path: ["swimlanes"],
|
|
3430
|
+
detail: {
|
|
3431
|
+
constraintKind: constraint.kind,
|
|
3432
|
+
...constraint.id === void 0 ? {} : { constraintId: constraint.id },
|
|
3433
|
+
nodeIds: invalidatedNodeIds
|
|
3434
|
+
}
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
return diagnostics;
|
|
3438
|
+
}
|
|
3439
|
+
function movedConstraintNodeIds(constraint, nodeBoxes, movedChildIds) {
|
|
3440
|
+
switch (constraint.kind) {
|
|
3441
|
+
case "exact-position":
|
|
3442
|
+
return [];
|
|
3443
|
+
case "containment":
|
|
3444
|
+
return movedContainmentViolations(constraint, nodeBoxes, movedChildIds);
|
|
3445
|
+
case "relative-position":
|
|
3446
|
+
return movedRelativeViolations(constraint, nodeBoxes, movedChildIds);
|
|
3447
|
+
case "align":
|
|
3448
|
+
return movedAlignViolations(constraint, nodeBoxes, movedChildIds);
|
|
3449
|
+
case "distribute":
|
|
3450
|
+
return movedDistributeViolations(constraint, nodeBoxes, movedChildIds);
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
function movedContainmentViolations(constraint, nodeBoxes, movedChildIds) {
|
|
3454
|
+
const container = nodeBoxes.get(constraint.containerId);
|
|
3455
|
+
if (container === void 0) {
|
|
3456
|
+
return [];
|
|
3457
|
+
}
|
|
3458
|
+
const content = paddedContentBox(container, constraint.padding);
|
|
3459
|
+
return constraint.childIds.filter((childId) => {
|
|
3460
|
+
if (!movedChildIds.has(childId)) {
|
|
3461
|
+
return false;
|
|
3462
|
+
}
|
|
3463
|
+
const child = nodeBoxes.get(childId);
|
|
3464
|
+
return child !== void 0 && !boxInside(child, content);
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
function movedRelativeViolations(constraint, nodeBoxes, movedChildIds) {
|
|
3468
|
+
if (!movedChildIds.has(constraint.sourceId) && !movedChildIds.has(constraint.referenceId)) {
|
|
3469
|
+
return [];
|
|
3470
|
+
}
|
|
3471
|
+
const source = nodeBoxes.get(constraint.sourceId);
|
|
3472
|
+
const reference = nodeBoxes.get(constraint.referenceId);
|
|
3473
|
+
if (source === void 0 || reference === void 0) {
|
|
3474
|
+
return [];
|
|
3475
|
+
}
|
|
3476
|
+
return sameBoxPosition(
|
|
3477
|
+
source,
|
|
3478
|
+
expectedRelativeBox(source, reference, constraint)
|
|
3479
|
+
) ? [] : [constraint.sourceId];
|
|
3480
|
+
}
|
|
3481
|
+
function movedAlignViolations(constraint, nodeBoxes, movedChildIds) {
|
|
3482
|
+
if (!constraint.targetIds.some((id) => movedChildIds.has(id))) {
|
|
3483
|
+
return [];
|
|
3484
|
+
}
|
|
3485
|
+
const targets = constraint.targetIds.map((id) => ({ id, box: nodeBoxes.get(id) })).filter(
|
|
3486
|
+
(target) => target.box !== void 0
|
|
3487
|
+
);
|
|
3488
|
+
const anchor = targets[0];
|
|
3489
|
+
if (anchor === void 0) {
|
|
3490
|
+
return [];
|
|
3491
|
+
}
|
|
3492
|
+
const expected = alignmentValue2(anchor.box, constraint.axis);
|
|
3493
|
+
return targets.filter(
|
|
3494
|
+
(target) => movedChildIds.has(target.id) && !sameNumber(alignmentValue2(target.box, constraint.axis), expected)
|
|
3495
|
+
).map((target) => target.id);
|
|
3496
|
+
}
|
|
3497
|
+
function movedDistributeViolations(constraint, nodeBoxes, movedChildIds) {
|
|
3498
|
+
if (!constraint.targetIds.some((id) => movedChildIds.has(id))) {
|
|
3499
|
+
return [];
|
|
3500
|
+
}
|
|
3501
|
+
const targets = constraint.targetIds.map((id) => ({ id, box: nodeBoxes.get(id) })).filter(
|
|
3502
|
+
(target) => target.box !== void 0
|
|
3503
|
+
).sort((a, b) => {
|
|
3504
|
+
const delta = constraint.axis === "horizontal" ? a.box.x - b.box.x : a.box.y - b.box.y;
|
|
3505
|
+
return delta === 0 ? a.id.localeCompare(b.id) : delta;
|
|
3506
|
+
});
|
|
3507
|
+
if (targets.length < 3) {
|
|
3508
|
+
return [];
|
|
3509
|
+
}
|
|
3510
|
+
const first = targets[0];
|
|
3511
|
+
const last = targets.at(-1);
|
|
3512
|
+
if (first === void 0 || last === void 0) {
|
|
3513
|
+
return [];
|
|
3514
|
+
}
|
|
3515
|
+
const expectedSpacing = constraint.spacing ?? (distributionStart2(last.box, constraint.axis) - distributionStart2(first.box, constraint.axis)) / (targets.length - 1);
|
|
3516
|
+
return targets.slice(1).filter((target, index) => {
|
|
3517
|
+
const previous = targets[index];
|
|
3518
|
+
if (previous === void 0 || !movedChildIds.has(target.id)) {
|
|
3519
|
+
return false;
|
|
3520
|
+
}
|
|
3521
|
+
return !sameNumber(
|
|
3522
|
+
distributionStart2(target.box, constraint.axis) - distributionStart2(previous.box, constraint.axis),
|
|
3523
|
+
expectedSpacing
|
|
3524
|
+
);
|
|
3525
|
+
}).map((target) => target.id);
|
|
3526
|
+
}
|
|
3527
|
+
function expectedRelativeBox(source, reference, constraint) {
|
|
3528
|
+
const offset = constraint.offset ?? { x: 0, y: 0 };
|
|
3529
|
+
switch (constraint.relation) {
|
|
3530
|
+
case "above":
|
|
3531
|
+
return {
|
|
3532
|
+
...source,
|
|
3533
|
+
x: reference.x + offset.x,
|
|
3534
|
+
y: reference.y - source.height + offset.y
|
|
3535
|
+
};
|
|
3536
|
+
case "right-of":
|
|
3537
|
+
return {
|
|
3538
|
+
...source,
|
|
3539
|
+
x: reference.x + reference.width + offset.x,
|
|
3540
|
+
y: reference.y + offset.y
|
|
3541
|
+
};
|
|
3542
|
+
case "below":
|
|
3543
|
+
return {
|
|
3544
|
+
...source,
|
|
3545
|
+
x: reference.x + offset.x,
|
|
3546
|
+
y: reference.y + reference.height + offset.y
|
|
3547
|
+
};
|
|
3548
|
+
case "left-of":
|
|
3549
|
+
return {
|
|
3550
|
+
...source,
|
|
3551
|
+
x: reference.x - source.width + offset.x,
|
|
3552
|
+
y: reference.y + offset.y
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
function paddedContentBox(container, padding) {
|
|
3557
|
+
const margin = padding ?? { top: 0, right: 0, bottom: 0, left: 0 };
|
|
3558
|
+
return {
|
|
3559
|
+
x: container.x + margin.left,
|
|
3560
|
+
y: container.y + margin.top,
|
|
3561
|
+
width: container.width - margin.left - margin.right,
|
|
3562
|
+
height: container.height - margin.top - margin.bottom
|
|
3563
|
+
};
|
|
3564
|
+
}
|
|
3565
|
+
function boxInside(child, container) {
|
|
3566
|
+
return child.x >= container.x && child.y >= container.y && child.x + child.width <= container.x + container.width && child.y + child.height <= container.y + container.height;
|
|
3567
|
+
}
|
|
3568
|
+
function sameBoxPosition(first, second) {
|
|
3569
|
+
return sameNumber(first.x, second.x) && sameNumber(first.y, second.y);
|
|
3570
|
+
}
|
|
3571
|
+
function sameNumber(first, second) {
|
|
3572
|
+
return Math.abs(first - second) < 1e-3;
|
|
3573
|
+
}
|
|
3574
|
+
function alignmentValue2(box, axis) {
|
|
3575
|
+
switch (axis) {
|
|
3576
|
+
case "x":
|
|
3577
|
+
case "left":
|
|
3578
|
+
return box.x;
|
|
3579
|
+
case "y":
|
|
3580
|
+
case "top":
|
|
3581
|
+
return box.y;
|
|
3582
|
+
case "center-x":
|
|
3583
|
+
return box.x + box.width / 2;
|
|
3584
|
+
case "center-y":
|
|
3585
|
+
return box.y + box.height / 2;
|
|
3586
|
+
case "right":
|
|
3587
|
+
return box.x + box.width;
|
|
3588
|
+
case "bottom":
|
|
3589
|
+
return box.y + box.height;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
function distributionStart2(box, axis) {
|
|
3593
|
+
return axis === "horizontal" ? box.x : box.y;
|
|
3594
|
+
}
|
|
3595
|
+
function detailString(diagnostic, key) {
|
|
3596
|
+
const value = diagnostic.detail?.[key];
|
|
3597
|
+
return typeof value === "string" ? value : void 0;
|
|
3598
|
+
}
|
|
3599
|
+
function reportSwimlaneOverlaps(nodeBoxes, locks, overlapSpacing) {
|
|
3600
|
+
const diagnostics = [];
|
|
3601
|
+
const ids = [...nodeBoxes.keys()].sort();
|
|
3602
|
+
for (const firstId of ids) {
|
|
3603
|
+
for (const secondId of ids) {
|
|
3604
|
+
if (firstId >= secondId) {
|
|
3605
|
+
continue;
|
|
3606
|
+
}
|
|
3607
|
+
const first = nodeBoxes.get(firstId);
|
|
3608
|
+
const second = nodeBoxes.get(secondId);
|
|
3609
|
+
if (first === void 0 || second === void 0) {
|
|
3610
|
+
continue;
|
|
3611
|
+
}
|
|
3612
|
+
if (!intersectsAabb(first, second)) {
|
|
3613
|
+
continue;
|
|
3614
|
+
}
|
|
3615
|
+
diagnostics.push({
|
|
3616
|
+
severity: "warning",
|
|
3617
|
+
code: "constraints.overlap.unresolved",
|
|
3618
|
+
message: `Boxes ${firstId} and ${secondId} still overlap after contract swimlane placement with configured spacing ${overlapSpacing}.`,
|
|
3619
|
+
path: ["swimlanes"],
|
|
3620
|
+
detail: {
|
|
3621
|
+
firstId,
|
|
3622
|
+
secondId,
|
|
3623
|
+
firstLocked: locks.has(firstId),
|
|
3624
|
+
secondLocked: locks.has(secondId)
|
|
3625
|
+
}
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
return diagnostics;
|
|
3630
|
+
}
|
|
3009
3631
|
function coordinateNodes(nodes, boxes, options, diagnostics) {
|
|
3010
3632
|
const coordinated = [];
|
|
3011
3633
|
for (const node of nodes) {
|
|
@@ -3120,16 +3742,70 @@ function portLabelBox(port) {
|
|
|
3120
3742
|
height
|
|
3121
3743
|
};
|
|
3122
3744
|
}
|
|
3123
|
-
function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
3124
|
-
const titleSize = 28;
|
|
3125
|
-
const padding = 16;
|
|
3745
|
+
function coordinateSwimlanes(swimlanes, nodeBoxes, layouts) {
|
|
3126
3746
|
return swimlanes.map((swimlane) => {
|
|
3127
|
-
const
|
|
3747
|
+
const layout2 = swimlane.layout ?? "overlay";
|
|
3748
|
+
const headerHeight = swimlane.headerHeight ?? 28;
|
|
3749
|
+
const padding = swimlane.padding ?? 16;
|
|
3750
|
+
const contractLayout = layouts.get(swimlane.id);
|
|
3751
|
+
if (layout2 === "contract" && contractLayout !== void 0) {
|
|
3752
|
+
const lanes2 = swimlane.lanes.map((lane, index) => {
|
|
3753
|
+
const box = swimlane.orientation === "vertical" ? {
|
|
3754
|
+
x: contractLayout.box.x + contractLayout.slotWidth * index,
|
|
3755
|
+
y: contractLayout.box.y,
|
|
3756
|
+
width: contractLayout.slotWidth,
|
|
3757
|
+
height: contractLayout.box.height
|
|
3758
|
+
} : {
|
|
3759
|
+
x: contractLayout.box.x,
|
|
3760
|
+
y: contractLayout.box.y + contractLayout.slotHeight * index,
|
|
3761
|
+
width: contractLayout.box.width,
|
|
3762
|
+
height: contractLayout.slotHeight
|
|
3763
|
+
};
|
|
3764
|
+
const headerBox = swimlane.orientation === "vertical" ? {
|
|
3765
|
+
x: box.x,
|
|
3766
|
+
y: box.y,
|
|
3767
|
+
width: box.width,
|
|
3768
|
+
height: headerHeight
|
|
3769
|
+
} : {
|
|
3770
|
+
x: box.x,
|
|
3771
|
+
y: box.y,
|
|
3772
|
+
width: headerHeight,
|
|
3773
|
+
height: box.height
|
|
3774
|
+
};
|
|
3775
|
+
const contentBox2 = swimlane.orientation === "vertical" ? {
|
|
3776
|
+
x: box.x,
|
|
3777
|
+
y: box.y + headerHeight,
|
|
3778
|
+
width: box.width,
|
|
3779
|
+
height: Math.max(0, box.height - headerHeight)
|
|
3780
|
+
} : {
|
|
3781
|
+
x: box.x + headerHeight,
|
|
3782
|
+
y: box.y,
|
|
3783
|
+
width: Math.max(0, box.width - headerHeight),
|
|
3784
|
+
height: box.height
|
|
3785
|
+
};
|
|
3786
|
+
return {
|
|
3787
|
+
...lane,
|
|
3788
|
+
box,
|
|
3789
|
+
headerBox,
|
|
3790
|
+
contentBox: contentBox2
|
|
3791
|
+
};
|
|
3792
|
+
});
|
|
3793
|
+
return {
|
|
3794
|
+
...swimlane,
|
|
3795
|
+
lanes: lanes2,
|
|
3796
|
+
box: contractLayout.box,
|
|
3797
|
+
...headerHeight === void 0 ? {} : { headerHeight },
|
|
3798
|
+
...padding === void 0 ? {} : { padding }
|
|
3799
|
+
};
|
|
3800
|
+
}
|
|
3801
|
+
const laneContentBoxes = swimlane.lanes.map((lane) => {
|
|
3128
3802
|
const childBoxes = lane.children.map((child) => nodeBoxes.get(child)).filter((box) => box !== void 0);
|
|
3129
|
-
return childBoxes.length === 0 ?
|
|
3803
|
+
return childBoxes.length === 0 ? void 0 : unionBoxes(childBoxes);
|
|
3130
3804
|
});
|
|
3131
|
-
const laneUnion =
|
|
3132
|
-
|
|
3805
|
+
const laneUnion = laneContentBoxes.filter((box) => box !== void 0).length === 0 ? { x: 0, y: 0, width: 120, height: 80 } : unionBoxes(
|
|
3806
|
+
laneContentBoxes.filter((box) => box !== void 0)
|
|
3807
|
+
);
|
|
3808
|
+
const outer = expand(laneUnion, padding, headerHeight);
|
|
3133
3809
|
const laneCount = Math.max(1, swimlane.lanes.length);
|
|
3134
3810
|
const lanes = swimlane.lanes.map((lane, index) => {
|
|
3135
3811
|
const box = swimlane.orientation === "vertical" ? {
|
|
@@ -3143,9 +3819,42 @@ function coordinateSwimlanes(swimlanes, nodeBoxes) {
|
|
|
3143
3819
|
width: outer.width,
|
|
3144
3820
|
height: outer.height / laneCount
|
|
3145
3821
|
};
|
|
3146
|
-
|
|
3822
|
+
const headerBox = layout2 === "contract" ? swimlane.orientation === "vertical" ? {
|
|
3823
|
+
x: box.x,
|
|
3824
|
+
y: box.y,
|
|
3825
|
+
width: box.width,
|
|
3826
|
+
height: headerHeight
|
|
3827
|
+
} : {
|
|
3828
|
+
x: box.x,
|
|
3829
|
+
y: box.y,
|
|
3830
|
+
width: headerHeight,
|
|
3831
|
+
height: box.height
|
|
3832
|
+
} : void 0;
|
|
3833
|
+
const contentBox2 = layout2 === "contract" ? swimlane.orientation === "vertical" ? {
|
|
3834
|
+
x: box.x,
|
|
3835
|
+
y: box.y + headerHeight,
|
|
3836
|
+
width: box.width,
|
|
3837
|
+
height: Math.max(0, box.height - headerHeight)
|
|
3838
|
+
} : {
|
|
3839
|
+
x: box.x + headerHeight,
|
|
3840
|
+
y: box.y,
|
|
3841
|
+
width: Math.max(0, box.width - headerHeight),
|
|
3842
|
+
height: box.height
|
|
3843
|
+
} : void 0;
|
|
3844
|
+
return {
|
|
3845
|
+
...lane,
|
|
3846
|
+
box,
|
|
3847
|
+
...headerBox === void 0 ? {} : { headerBox },
|
|
3848
|
+
...contentBox2 === void 0 ? {} : { contentBox: contentBox2 }
|
|
3849
|
+
};
|
|
3147
3850
|
});
|
|
3148
|
-
return {
|
|
3851
|
+
return {
|
|
3852
|
+
...swimlane,
|
|
3853
|
+
lanes,
|
|
3854
|
+
box: outer,
|
|
3855
|
+
...headerHeight === void 0 ? {} : { headerHeight },
|
|
3856
|
+
...padding === void 0 ? {} : { padding }
|
|
3857
|
+
};
|
|
3149
3858
|
});
|
|
3150
3859
|
}
|
|
3151
3860
|
function coordinateFrame(frame, contentBounds) {
|