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.js
CHANGED
|
@@ -303,7 +303,6 @@ function isDebugEnabled() {
|
|
|
303
303
|
if (cliMode) return false;
|
|
304
304
|
return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
305
305
|
}
|
|
306
|
-
var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
|
|
307
306
|
|
|
308
307
|
// src/layout/edge-routing/edge-fixer.ts
|
|
309
308
|
var EdgeFixer = class {
|
|
@@ -374,6 +373,10 @@ var EdgeFixer = class {
|
|
|
374
373
|
const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
|
|
375
374
|
for (const edge of node.edges) {
|
|
376
375
|
if (edge.sections && edge.sections.length > 0) {
|
|
376
|
+
const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
|
|
377
|
+
if (hasPoolRelativeCoords) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
377
380
|
this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
|
|
378
381
|
}
|
|
379
382
|
}
|
|
@@ -2499,7 +2502,15 @@ var LaneArranger = class {
|
|
|
2499
2502
|
const waypoints = [];
|
|
2500
2503
|
waypoints.push({ x: startX, y: startY });
|
|
2501
2504
|
if (Math.abs(startY - endY) > 10) {
|
|
2502
|
-
const midX = (
|
|
2505
|
+
const midX = this.findClearMidX(
|
|
2506
|
+
startX,
|
|
2507
|
+
endX,
|
|
2508
|
+
startY,
|
|
2509
|
+
endY,
|
|
2510
|
+
sourceId,
|
|
2511
|
+
targetId,
|
|
2512
|
+
nodePositions
|
|
2513
|
+
);
|
|
2503
2514
|
waypoints.push({ x: midX, y: startY });
|
|
2504
2515
|
waypoints.push({ x: midX, y: endY });
|
|
2505
2516
|
}
|
|
@@ -2517,6 +2528,109 @@ var LaneArranger = class {
|
|
|
2517
2528
|
}
|
|
2518
2529
|
}
|
|
2519
2530
|
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Find a clear X position for vertical edge segment that avoids obstacles.
|
|
2533
|
+
* Checks all three segments of the L-shaped path:
|
|
2534
|
+
* 1. Horizontal from (startX, startY) to (midX, startY)
|
|
2535
|
+
* 2. Vertical from (midX, startY) to (midX, endY)
|
|
2536
|
+
* 3. Horizontal from (midX, endY) to (endX, endY)
|
|
2537
|
+
*/
|
|
2538
|
+
findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
|
|
2539
|
+
const margin = 15;
|
|
2540
|
+
const minY = Math.min(startY, endY);
|
|
2541
|
+
const maxY = Math.max(startY, endY);
|
|
2542
|
+
const rangeMinX = Math.min(startX, endX);
|
|
2543
|
+
const rangeMaxX = Math.max(startX, endX);
|
|
2544
|
+
if (isDebugEnabled()) {
|
|
2545
|
+
console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
|
|
2546
|
+
}
|
|
2547
|
+
const allObstacles = [];
|
|
2548
|
+
for (const [nodeId, pos] of nodePositions) {
|
|
2549
|
+
if (nodeId === sourceId || nodeId === targetId) continue;
|
|
2550
|
+
const nodeLeft = pos.x;
|
|
2551
|
+
const nodeRight = pos.x + pos.width;
|
|
2552
|
+
const nodeTop = pos.y;
|
|
2553
|
+
const nodeBottom = pos.y + pos.height;
|
|
2554
|
+
const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
|
|
2555
|
+
const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
|
|
2556
|
+
const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
|
|
2557
|
+
const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
|
|
2558
|
+
if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
|
|
2559
|
+
allObstacles.push({
|
|
2560
|
+
x: nodeLeft,
|
|
2561
|
+
y: nodeTop,
|
|
2562
|
+
width: pos.width,
|
|
2563
|
+
height: pos.height,
|
|
2564
|
+
right: nodeRight,
|
|
2565
|
+
bottom: nodeBottom,
|
|
2566
|
+
id: nodeId
|
|
2567
|
+
});
|
|
2568
|
+
if (isDebugEnabled()) {
|
|
2569
|
+
console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
if (allObstacles.length === 0) {
|
|
2574
|
+
return (startX + endX) / 2;
|
|
2575
|
+
}
|
|
2576
|
+
const isValidMidX = (midX) => {
|
|
2577
|
+
for (const obs of allObstacles) {
|
|
2578
|
+
const seg1MinX = Math.min(startX, midX);
|
|
2579
|
+
const seg1MaxX = Math.max(startX, midX);
|
|
2580
|
+
if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
|
|
2581
|
+
obs.right > seg1MinX && obs.x < seg1MaxX) {
|
|
2582
|
+
return false;
|
|
2583
|
+
}
|
|
2584
|
+
if (obs.x <= midX && obs.right >= midX && // X range contains midX
|
|
2585
|
+
obs.bottom > minY && obs.y < maxY) {
|
|
2586
|
+
return false;
|
|
2587
|
+
}
|
|
2588
|
+
const seg2MinX = Math.min(midX, endX);
|
|
2589
|
+
const seg2MaxX = Math.max(midX, endX);
|
|
2590
|
+
if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
|
|
2591
|
+
obs.right > seg2MinX && obs.x < seg2MaxX) {
|
|
2592
|
+
return false;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
return true;
|
|
2596
|
+
};
|
|
2597
|
+
const candidates = [];
|
|
2598
|
+
candidates.push((startX + endX) / 2);
|
|
2599
|
+
candidates.push(startX + margin);
|
|
2600
|
+
candidates.push(endX - margin);
|
|
2601
|
+
for (const obs of allObstacles) {
|
|
2602
|
+
candidates.push(obs.x - margin);
|
|
2603
|
+
candidates.push(obs.right + margin);
|
|
2604
|
+
}
|
|
2605
|
+
const simpleMidX = (startX + endX) / 2;
|
|
2606
|
+
const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
|
|
2607
|
+
for (const candidate of validCandidates) {
|
|
2608
|
+
if (isValidMidX(candidate)) {
|
|
2609
|
+
if (isDebugEnabled()) {
|
|
2610
|
+
console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
|
|
2611
|
+
}
|
|
2612
|
+
return candidate;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
|
|
2616
|
+
const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
|
|
2617
|
+
if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
|
|
2618
|
+
if (isDebugEnabled()) {
|
|
2619
|
+
console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
|
|
2620
|
+
}
|
|
2621
|
+
return leftMost;
|
|
2622
|
+
}
|
|
2623
|
+
if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
|
|
2624
|
+
if (isDebugEnabled()) {
|
|
2625
|
+
console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
|
|
2626
|
+
}
|
|
2627
|
+
return rightMost;
|
|
2628
|
+
}
|
|
2629
|
+
if (isDebugEnabled()) {
|
|
2630
|
+
console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
|
|
2631
|
+
}
|
|
2632
|
+
return simpleMidX;
|
|
2633
|
+
}
|
|
2520
2634
|
};
|
|
2521
2635
|
|
|
2522
2636
|
// src/layout/post-processing/pool-arranger.ts
|
|
@@ -2597,7 +2711,7 @@ var PoolArranger = class {
|
|
|
2597
2711
|
pool.y = currentY;
|
|
2598
2712
|
if (isBlackBox) {
|
|
2599
2713
|
pool.width = maxPoolWidth;
|
|
2600
|
-
pool.height =
|
|
2714
|
+
pool.height = 60;
|
|
2601
2715
|
} else if (hasLanes) {
|
|
2602
2716
|
pool.width = maxPoolWidth;
|
|
2603
2717
|
} else {
|
|
@@ -5109,6 +5223,7 @@ var DiagramBuilder = class {
|
|
|
5109
5223
|
}
|
|
5110
5224
|
}
|
|
5111
5225
|
}
|
|
5226
|
+
this.ensureOrthogonalWaypoints(waypoints);
|
|
5112
5227
|
const edgeModel = {
|
|
5113
5228
|
id: `${edge.id}_di`,
|
|
5114
5229
|
bpmnElement: edge.id,
|
|
@@ -5175,6 +5290,36 @@ var DiagramBuilder = class {
|
|
|
5175
5290
|
y: (lastPoint?.y ?? 0) - labelHeight - 4
|
|
5176
5291
|
};
|
|
5177
5292
|
}
|
|
5293
|
+
/**
|
|
5294
|
+
* Ensure all waypoint segments are orthogonal (horizontal or vertical)
|
|
5295
|
+
* If a diagonal segment is found, insert intermediate bend points to create
|
|
5296
|
+
* an L-shaped orthogonal path.
|
|
5297
|
+
*
|
|
5298
|
+
* Strategy: For diagonal segments, we use "horizontal first" - go horizontally
|
|
5299
|
+
* to the target X, then vertically to the target Y.
|
|
5300
|
+
*/
|
|
5301
|
+
ensureOrthogonalWaypoints(waypoints) {
|
|
5302
|
+
if (waypoints.length < 2) return;
|
|
5303
|
+
const tolerance = 1;
|
|
5304
|
+
let i = 0;
|
|
5305
|
+
while (i < waypoints.length - 1) {
|
|
5306
|
+
const current = waypoints[i];
|
|
5307
|
+
const next = waypoints[i + 1];
|
|
5308
|
+
if (!current || !next) {
|
|
5309
|
+
i++;
|
|
5310
|
+
continue;
|
|
5311
|
+
}
|
|
5312
|
+
const dx = Math.abs(next.x - current.x);
|
|
5313
|
+
const dy = Math.abs(next.y - current.y);
|
|
5314
|
+
if (dx > tolerance && dy > tolerance) {
|
|
5315
|
+
const bendPoint = { x: next.x, y: current.y };
|
|
5316
|
+
waypoints.splice(i + 1, 0, bendPoint);
|
|
5317
|
+
i++;
|
|
5318
|
+
} else {
|
|
5319
|
+
i++;
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5178
5323
|
};
|
|
5179
5324
|
|
|
5180
5325
|
// src/transform/model-builder.ts
|