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