bpmn-elk-layout 1.0.2 → 1.1.2
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/bin/bpmn-elk-layout.js +149 -4
- package/dist/bin/bpmn-elk-layout.js.map +1 -1
- package/dist/index.js +148 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -3
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.js +148 -3
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +148 -3
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.js
CHANGED
|
@@ -309,7 +309,6 @@ function isDebugEnabled() {
|
|
|
309
309
|
if (cliMode) return false;
|
|
310
310
|
return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
311
311
|
}
|
|
312
|
-
var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
313
312
|
|
|
314
313
|
// src/layout/edge-routing/edge-fixer.ts
|
|
315
314
|
var EdgeFixer = class {
|
|
@@ -380,6 +379,10 @@ var EdgeFixer = class {
|
|
|
380
379
|
const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
|
|
381
380
|
for (const edge of node.edges) {
|
|
382
381
|
if (edge.sections && edge.sections.length > 0) {
|
|
382
|
+
const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
|
|
383
|
+
if (hasPoolRelativeCoords) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
383
386
|
this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
|
|
384
387
|
}
|
|
385
388
|
}
|
|
@@ -2505,7 +2508,15 @@ var LaneArranger = class {
|
|
|
2505
2508
|
const waypoints = [];
|
|
2506
2509
|
waypoints.push({ x: startX, y: startY });
|
|
2507
2510
|
if (Math.abs(startY - endY) > 10) {
|
|
2508
|
-
const midX = (
|
|
2511
|
+
const midX = this.findClearMidX(
|
|
2512
|
+
startX,
|
|
2513
|
+
endX,
|
|
2514
|
+
startY,
|
|
2515
|
+
endY,
|
|
2516
|
+
sourceId,
|
|
2517
|
+
targetId,
|
|
2518
|
+
nodePositions
|
|
2519
|
+
);
|
|
2509
2520
|
waypoints.push({ x: midX, y: startY });
|
|
2510
2521
|
waypoints.push({ x: midX, y: endY });
|
|
2511
2522
|
}
|
|
@@ -2523,6 +2534,109 @@ var LaneArranger = class {
|
|
|
2523
2534
|
}
|
|
2524
2535
|
}
|
|
2525
2536
|
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Find a clear X position for vertical edge segment that avoids obstacles.
|
|
2539
|
+
* Checks all three segments of the L-shaped path:
|
|
2540
|
+
* 1. Horizontal from (startX, startY) to (midX, startY)
|
|
2541
|
+
* 2. Vertical from (midX, startY) to (midX, endY)
|
|
2542
|
+
* 3. Horizontal from (midX, endY) to (endX, endY)
|
|
2543
|
+
*/
|
|
2544
|
+
findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
|
|
2545
|
+
const margin = 15;
|
|
2546
|
+
const minY = Math.min(startY, endY);
|
|
2547
|
+
const maxY = Math.max(startY, endY);
|
|
2548
|
+
const rangeMinX = Math.min(startX, endX);
|
|
2549
|
+
const rangeMaxX = Math.max(startX, endX);
|
|
2550
|
+
if (isDebugEnabled()) {
|
|
2551
|
+
console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
|
|
2552
|
+
}
|
|
2553
|
+
const allObstacles = [];
|
|
2554
|
+
for (const [nodeId, pos] of nodePositions) {
|
|
2555
|
+
if (nodeId === sourceId || nodeId === targetId) continue;
|
|
2556
|
+
const nodeLeft = pos.x;
|
|
2557
|
+
const nodeRight = pos.x + pos.width;
|
|
2558
|
+
const nodeTop = pos.y;
|
|
2559
|
+
const nodeBottom = pos.y + pos.height;
|
|
2560
|
+
const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
|
|
2561
|
+
const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
|
|
2562
|
+
const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
|
|
2563
|
+
const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
|
|
2564
|
+
if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
|
|
2565
|
+
allObstacles.push({
|
|
2566
|
+
x: nodeLeft,
|
|
2567
|
+
y: nodeTop,
|
|
2568
|
+
width: pos.width,
|
|
2569
|
+
height: pos.height,
|
|
2570
|
+
right: nodeRight,
|
|
2571
|
+
bottom: nodeBottom,
|
|
2572
|
+
id: nodeId
|
|
2573
|
+
});
|
|
2574
|
+
if (isDebugEnabled()) {
|
|
2575
|
+
console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
if (allObstacles.length === 0) {
|
|
2580
|
+
return (startX + endX) / 2;
|
|
2581
|
+
}
|
|
2582
|
+
const isValidMidX = (midX) => {
|
|
2583
|
+
for (const obs of allObstacles) {
|
|
2584
|
+
const seg1MinX = Math.min(startX, midX);
|
|
2585
|
+
const seg1MaxX = Math.max(startX, midX);
|
|
2586
|
+
if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
|
|
2587
|
+
obs.right > seg1MinX && obs.x < seg1MaxX) {
|
|
2588
|
+
return false;
|
|
2589
|
+
}
|
|
2590
|
+
if (obs.x <= midX && obs.right >= midX && // X range contains midX
|
|
2591
|
+
obs.bottom > minY && obs.y < maxY) {
|
|
2592
|
+
return false;
|
|
2593
|
+
}
|
|
2594
|
+
const seg2MinX = Math.min(midX, endX);
|
|
2595
|
+
const seg2MaxX = Math.max(midX, endX);
|
|
2596
|
+
if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
|
|
2597
|
+
obs.right > seg2MinX && obs.x < seg2MaxX) {
|
|
2598
|
+
return false;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
return true;
|
|
2602
|
+
};
|
|
2603
|
+
const candidates = [];
|
|
2604
|
+
candidates.push((startX + endX) / 2);
|
|
2605
|
+
candidates.push(startX + margin);
|
|
2606
|
+
candidates.push(endX - margin);
|
|
2607
|
+
for (const obs of allObstacles) {
|
|
2608
|
+
candidates.push(obs.x - margin);
|
|
2609
|
+
candidates.push(obs.right + margin);
|
|
2610
|
+
}
|
|
2611
|
+
const simpleMidX = (startX + endX) / 2;
|
|
2612
|
+
const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
|
|
2613
|
+
for (const candidate of validCandidates) {
|
|
2614
|
+
if (isValidMidX(candidate)) {
|
|
2615
|
+
if (isDebugEnabled()) {
|
|
2616
|
+
console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
|
|
2617
|
+
}
|
|
2618
|
+
return candidate;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
|
|
2622
|
+
const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
|
|
2623
|
+
if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
|
|
2624
|
+
if (isDebugEnabled()) {
|
|
2625
|
+
console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
|
|
2626
|
+
}
|
|
2627
|
+
return leftMost;
|
|
2628
|
+
}
|
|
2629
|
+
if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
|
|
2630
|
+
if (isDebugEnabled()) {
|
|
2631
|
+
console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
|
|
2632
|
+
}
|
|
2633
|
+
return rightMost;
|
|
2634
|
+
}
|
|
2635
|
+
if (isDebugEnabled()) {
|
|
2636
|
+
console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
|
|
2637
|
+
}
|
|
2638
|
+
return simpleMidX;
|
|
2639
|
+
}
|
|
2526
2640
|
};
|
|
2527
2641
|
|
|
2528
2642
|
// src/layout/post-processing/pool-arranger.ts
|
|
@@ -2603,7 +2717,7 @@ var PoolArranger = class {
|
|
|
2603
2717
|
pool.y = currentY;
|
|
2604
2718
|
if (isBlackBox) {
|
|
2605
2719
|
pool.width = maxPoolWidth;
|
|
2606
|
-
pool.height =
|
|
2720
|
+
pool.height = 60;
|
|
2607
2721
|
} else if (hasLanes) {
|
|
2608
2722
|
pool.width = maxPoolWidth;
|
|
2609
2723
|
} else {
|
|
@@ -5115,6 +5229,7 @@ var DiagramBuilder = class {
|
|
|
5115
5229
|
}
|
|
5116
5230
|
}
|
|
5117
5231
|
}
|
|
5232
|
+
this.ensureOrthogonalWaypoints(waypoints);
|
|
5118
5233
|
const edgeModel = {
|
|
5119
5234
|
id: `${edge.id}_di`,
|
|
5120
5235
|
bpmnElement: edge.id,
|
|
@@ -5181,6 +5296,36 @@ var DiagramBuilder = class {
|
|
|
5181
5296
|
y: (lastPoint?.y ?? 0) - labelHeight - 4
|
|
5182
5297
|
};
|
|
5183
5298
|
}
|
|
5299
|
+
/**
|
|
5300
|
+
* Ensure all waypoint segments are orthogonal (horizontal or vertical)
|
|
5301
|
+
* If a diagonal segment is found, insert intermediate bend points to create
|
|
5302
|
+
* an L-shaped orthogonal path.
|
|
5303
|
+
*
|
|
5304
|
+
* Strategy: For diagonal segments, we use "horizontal first" - go horizontally
|
|
5305
|
+
* to the target X, then vertically to the target Y.
|
|
5306
|
+
*/
|
|
5307
|
+
ensureOrthogonalWaypoints(waypoints) {
|
|
5308
|
+
if (waypoints.length < 2) return;
|
|
5309
|
+
const tolerance = 1;
|
|
5310
|
+
let i = 0;
|
|
5311
|
+
while (i < waypoints.length - 1) {
|
|
5312
|
+
const current = waypoints[i];
|
|
5313
|
+
const next = waypoints[i + 1];
|
|
5314
|
+
if (!current || !next) {
|
|
5315
|
+
i++;
|
|
5316
|
+
continue;
|
|
5317
|
+
}
|
|
5318
|
+
const dx = Math.abs(next.x - current.x);
|
|
5319
|
+
const dy = Math.abs(next.y - current.y);
|
|
5320
|
+
if (dx > tolerance && dy > tolerance) {
|
|
5321
|
+
const bendPoint = { x: next.x, y: current.y };
|
|
5322
|
+
waypoints.splice(i + 1, 0, bendPoint);
|
|
5323
|
+
i++;
|
|
5324
|
+
} else {
|
|
5325
|
+
i++;
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5184
5329
|
};
|
|
5185
5330
|
|
|
5186
5331
|
// src/transform/model-builder.ts
|