@synergenius/flow-weaver 0.33.1 → 0.33.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/README.md +1 -0
- package/dist/cli/commands/diagram.js +1 -1
- package/dist/cli/flow-weaver.mjs +299 -413
- package/dist/diagram/geometry.d.ts +7 -2
- package/dist/diagram/geometry.js +15 -56
- package/dist/diagram/html-viewer.js +98 -42
- package/dist/diagram/orthogonal-router.d.ts +16 -51
- package/dist/diagram/orthogonal-router.js +138 -248
- package/dist/diagram/renderer.js +79 -65
- package/dist/diagram/theme.d.ts +2 -0
- package/dist/diagram/theme.js +17 -17
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/package.json +1 -1
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -5987,7 +5987,7 @@ var VERSION;
|
|
|
5987
5987
|
var init_generated_version = __esm({
|
|
5988
5988
|
"src/generated-version.ts"() {
|
|
5989
5989
|
"use strict";
|
|
5990
|
-
VERSION = "0.33.
|
|
5990
|
+
VERSION = "0.33.2";
|
|
5991
5991
|
}
|
|
5992
5992
|
});
|
|
5993
5993
|
|
|
@@ -30483,19 +30483,6 @@ function getPortColor(dataType, isFailure, theme = "dark") {
|
|
|
30483
30483
|
const colors2 = theme === "dark" ? DARK_PORT_COLORS : LIGHT_PORT_COLORS;
|
|
30484
30484
|
return colors2[dataType] ?? colors2.ANY;
|
|
30485
30485
|
}
|
|
30486
|
-
function getPortRingColor(dataType, isFailure, theme = "dark") {
|
|
30487
|
-
const color = getPortColor(dataType, isFailure, theme);
|
|
30488
|
-
return darkenHex(color, 0.4);
|
|
30489
|
-
}
|
|
30490
|
-
function darkenHex(hex, amount) {
|
|
30491
|
-
const r = parseInt(hex.slice(1, 3), 16);
|
|
30492
|
-
const g = parseInt(hex.slice(3, 5), 16);
|
|
30493
|
-
const b = parseInt(hex.slice(5, 7), 16);
|
|
30494
|
-
const nr = Math.round(r * (1 - amount));
|
|
30495
|
-
const ng = Math.round(g * (1 - amount));
|
|
30496
|
-
const nb = Math.round(b * (1 - amount));
|
|
30497
|
-
return `#${nr.toString(16).padStart(2, "0")}${ng.toString(16).padStart(2, "0")}${nb.toString(16).padStart(2, "0")}`;
|
|
30498
|
-
}
|
|
30499
30486
|
var DARK_PORT_COLORS, LIGHT_PORT_COLORS, DARK_FAILURE_COLOR, LIGHT_FAILURE_COLOR, NODE_DEFAULT_COLOR, NODE_VARIANT_COLORS, DARK_PALETTE, LIGHT_PALETTE, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, VALID_NODE_ICONS;
|
|
30500
30487
|
var init_theme = __esm({
|
|
30501
30488
|
"src/diagram/theme.ts"() {
|
|
@@ -30540,23 +30527,23 @@ var init_theme = __esm({
|
|
|
30540
30527
|
LIGHT_FAILURE_COLOR = "#e34646";
|
|
30541
30528
|
NODE_DEFAULT_COLOR = "#334155";
|
|
30542
30529
|
NODE_VARIANT_COLORS = {
|
|
30543
|
-
blue: { border: "#548ce3", darkBorder: "#5e9eff" },
|
|
30544
|
-
// blue-shade-2 / blue-dark-shade-1
|
|
30545
|
-
purple: { border: "#9f5fe3", darkBorder: "#b36bff" },
|
|
30530
|
+
blue: { border: "#548ce3", darkBorder: "#5e9eff", icon: "#3a6bbf", darkIcon: "#4a7ad4" },
|
|
30531
|
+
// blue-shade-2 / blue-dark-shade-1 / blue-shade-3 / blue-dark-shade-3
|
|
30532
|
+
purple: { border: "#9f5fe3", darkBorder: "#b36bff", icon: "#7d44bf", darkIcon: "#9050d4" },
|
|
30546
30533
|
// purple-shade-2 / purple-dark-shade-1
|
|
30547
|
-
cyan: { border: "#63ccc4", darkBorder: "#6fe5dc" },
|
|
30534
|
+
cyan: { border: "#63ccc4", darkBorder: "#6fe5dc", icon: "#4aada6", darkIcon: "#56c4bb" },
|
|
30548
30535
|
// cyan-shade-2 / cyan-dark-shade-1
|
|
30549
|
-
teal: { border: "#63ccc4", darkBorder: "#6fe5dc" },
|
|
30536
|
+
teal: { border: "#63ccc4", darkBorder: "#6fe5dc", icon: "#4aada6", darkIcon: "#56c4bb" },
|
|
30550
30537
|
// alias for cyan
|
|
30551
|
-
orange: { border: "#e3732d", darkBorder: "#ff8133" },
|
|
30538
|
+
orange: { border: "#e3732d", darkBorder: "#ff8133", icon: "#bf5a1e", darkIcon: "#d46a28" },
|
|
30552
30539
|
// orange-shade-2 / orange-dark-shade-1
|
|
30553
|
-
pink: { border: "#e349c2", darkBorder: "#ff52da" },
|
|
30540
|
+
pink: { border: "#e349c2", darkBorder: "#ff52da", icon: "#bf349f", darkIcon: "#d43fb5" },
|
|
30554
30541
|
// pink-shade-2 / pink-dark-shade-1
|
|
30555
|
-
green: { border: "#0ec850", darkBorder: "#10e15a" },
|
|
30542
|
+
green: { border: "#0ec850", darkBorder: "#10e15a", icon: "#0aa53f", darkIcon: "#0dbd4a" },
|
|
30556
30543
|
// green-shade-2 / green-dark-shade-1
|
|
30557
|
-
red: { border: "#e34646", darkBorder: "#ff4f4f" },
|
|
30544
|
+
red: { border: "#e34646", darkBorder: "#ff4f4f", icon: "#bf3333", darkIcon: "#d43b3b" },
|
|
30558
30545
|
// red-shade-2 / red-dark-shade-1
|
|
30559
|
-
yellow: { border: "#e3a82b", darkBorder: "#ffbd30" }
|
|
30546
|
+
yellow: { border: "#e3a82b", darkBorder: "#ffbd30", icon: "#bf8c21", darkIcon: "#d49e28" }
|
|
30560
30547
|
// yellow-shade-2 / yellow-dark-shade-1
|
|
30561
30548
|
};
|
|
30562
30549
|
DARK_PALETTE = {
|
|
@@ -30572,18 +30559,18 @@ var init_theme = __esm({
|
|
|
30572
30559
|
// color-text-subtle = dark-shade-30
|
|
30573
30560
|
connectionColor: "#5f5f6d",
|
|
30574
30561
|
// color-border-subtle = dark-shade-70
|
|
30575
|
-
dotColor: "#
|
|
30576
|
-
// color-background-dots = primary-dark-tint-
|
|
30562
|
+
dotColor: "#7b8cd9",
|
|
30563
|
+
// color-background-dots-secondary = primary-dark-tint-2
|
|
30577
30564
|
labelBadgeFill: "#252538",
|
|
30578
30565
|
// color-surface-low = dark-shade-95
|
|
30579
30566
|
labelBadgeBorder: "#313143",
|
|
30580
30567
|
// color-surface-lowest = dark-shade-90
|
|
30581
|
-
nodeIconColor: "#
|
|
30582
|
-
//
|
|
30568
|
+
nodeIconColor: "#8e9eff",
|
|
30569
|
+
// color-brand-main = primary-dark-tint-1
|
|
30583
30570
|
scopeAreaStroke: "#5f5f6d",
|
|
30584
30571
|
// color-border-subtle = dark-shade-70
|
|
30585
|
-
nodeShadowOpacity: 0
|
|
30586
|
-
dotOpacity: 0.
|
|
30572
|
+
nodeShadowOpacity: 0,
|
|
30573
|
+
dotOpacity: 0.4
|
|
30587
30574
|
};
|
|
30588
30575
|
LIGHT_PALETTE = {
|
|
30589
30576
|
background: "#f6f7ff",
|
|
@@ -30598,18 +30585,18 @@ var init_theme = __esm({
|
|
|
30598
30585
|
// shade-50
|
|
30599
30586
|
connectionColor: "#b3b3b3",
|
|
30600
30587
|
// shade-30
|
|
30601
|
-
dotColor: "#
|
|
30602
|
-
// color-background-dots = primary-shade-
|
|
30588
|
+
dotColor: "#4a5ce0",
|
|
30589
|
+
// color-background-dots-secondary = primary-shade-2
|
|
30603
30590
|
labelBadgeFill: "#ffffff",
|
|
30604
30591
|
// surface-main — 80% opacity applied in renderer
|
|
30605
30592
|
labelBadgeBorder: "#e6e6e6",
|
|
30606
30593
|
// shade-10
|
|
30607
30594
|
nodeIconColor: "#5468ff",
|
|
30608
|
-
// primary-base
|
|
30595
|
+
// color-brand-main = primary-base
|
|
30609
30596
|
scopeAreaStroke: "#cccccc",
|
|
30610
30597
|
// color-border-default
|
|
30611
|
-
nodeShadowOpacity: 0
|
|
30612
|
-
dotOpacity: 0.
|
|
30598
|
+
nodeShadowOpacity: 0,
|
|
30599
|
+
dotOpacity: 0.4
|
|
30613
30600
|
};
|
|
30614
30601
|
TYPE_ABBREVIATIONS = {
|
|
30615
30602
|
STEP: "STP",
|
|
@@ -48175,7 +48162,9 @@ function segmentOverlapsBox(xMin, xMax, y, box) {
|
|
|
48175
48162
|
return xMin < box.right && xMax > box.left && y >= box.top && y <= box.bottom;
|
|
48176
48163
|
}
|
|
48177
48164
|
function verticalSegmentClear(x2, yMin, yMax, boxes) {
|
|
48178
|
-
return !boxes.some(
|
|
48165
|
+
return !boxes.some(
|
|
48166
|
+
(box) => x2 >= box.left && x2 <= box.right && yMin < box.bottom && yMax > box.top
|
|
48167
|
+
);
|
|
48179
48168
|
}
|
|
48180
48169
|
function findClearY(xMin, xMax, candidateY, boxes) {
|
|
48181
48170
|
const isBlocked = (y) => boxes.some((box) => segmentOverlapsBox(xMin, xMax, y, box));
|
|
@@ -48205,7 +48194,7 @@ function findClearY(xMin, xMax, candidateY, boxes) {
|
|
|
48205
48194
|
if (bestDist === Infinity) {
|
|
48206
48195
|
const allMin = Math.min(...edges) - EDGE_OFFSET * 2;
|
|
48207
48196
|
const allMax = Math.max(...edges) + EDGE_OFFSET * 2;
|
|
48208
|
-
bestY = Math.abs(allMin - candidateY)
|
|
48197
|
+
bestY = Math.abs(allMin - candidateY) < Math.abs(allMax - candidateY) ? allMin : allMax;
|
|
48209
48198
|
if (isBlocked(bestY)) {
|
|
48210
48199
|
for (let offset = TRACK_SPACING; offset < 800; offset += TRACK_SPACING) {
|
|
48211
48200
|
if (!isBlocked(bestY - offset)) {
|
|
@@ -48275,25 +48264,27 @@ function simplifyWaypoints(waypoints) {
|
|
|
48275
48264
|
const a = pts[i], b = pts[i + 1], c = pts[i + 2], d = pts[i + 3];
|
|
48276
48265
|
const jogH = Math.abs(b[1] - c[1]);
|
|
48277
48266
|
if (Math.abs(a[1] - b[1]) < 0.5 && Math.abs(b[0] - c[0]) < 0.5 && Math.abs(c[1] - d[1]) < 0.5 && jogH > 0.5 && jogH < JOG_THRESHOLD) {
|
|
48278
|
-
|
|
48279
|
-
|
|
48280
|
-
|
|
48281
|
-
|
|
48282
|
-
|
|
48283
|
-
|
|
48284
|
-
|
|
48285
|
-
|
|
48267
|
+
if (Math.abs(a[1] - d[1]) < 0.5) {
|
|
48268
|
+
const snapY = a[1];
|
|
48269
|
+
const newPts = pts.slice();
|
|
48270
|
+
newPts[i + 1] = [b[0], snapY];
|
|
48271
|
+
newPts[i + 2] = [c[0], snapY];
|
|
48272
|
+
pts = newPts;
|
|
48273
|
+
jogFound = true;
|
|
48274
|
+
break;
|
|
48275
|
+
}
|
|
48286
48276
|
}
|
|
48287
48277
|
const jogW = Math.abs(b[0] - c[0]);
|
|
48288
48278
|
if (Math.abs(a[0] - b[0]) < 0.5 && Math.abs(b[1] - c[1]) < 0.5 && Math.abs(c[0] - d[0]) < 0.5 && jogW > 0.5 && jogW < JOG_THRESHOLD) {
|
|
48289
|
-
|
|
48290
|
-
|
|
48291
|
-
|
|
48292
|
-
|
|
48293
|
-
|
|
48294
|
-
|
|
48295
|
-
|
|
48296
|
-
|
|
48279
|
+
if (Math.abs(a[0] - d[0]) < 0.5) {
|
|
48280
|
+
const snapX = a[0];
|
|
48281
|
+
const newPts = pts.slice();
|
|
48282
|
+
newPts[i + 1] = [snapX, b[1]];
|
|
48283
|
+
newPts[i + 2] = [snapX, c[1]];
|
|
48284
|
+
pts = newPts;
|
|
48285
|
+
jogFound = true;
|
|
48286
|
+
break;
|
|
48287
|
+
}
|
|
48297
48288
|
}
|
|
48298
48289
|
}
|
|
48299
48290
|
}
|
|
@@ -48303,7 +48294,10 @@ function simplifyWaypoints(waypoints) {
|
|
|
48303
48294
|
const curr = pts[i];
|
|
48304
48295
|
const next = pts[i + 1];
|
|
48305
48296
|
const distToPrev = Math.abs(prev[0] - curr[0]) + Math.abs(prev[1] - curr[1]);
|
|
48306
|
-
if (distToPrev < MIN_SEGMENT_LENGTH)
|
|
48297
|
+
if (distToPrev < MIN_SEGMENT_LENGTH) {
|
|
48298
|
+
const wouldDiag = Math.abs(prev[0] - next[0]) > 0.5 && Math.abs(prev[1] - next[1]) > 0.5;
|
|
48299
|
+
if (!wouldDiag) continue;
|
|
48300
|
+
}
|
|
48307
48301
|
const sameX = Math.abs(prev[0] - curr[0]) < 0.01 && Math.abs(curr[0] - next[0]) < 0.01;
|
|
48308
48302
|
const sameY = Math.abs(prev[1] - curr[1]) < 0.01 && Math.abs(curr[1] - next[1]) < 0.01;
|
|
48309
48303
|
if (!sameX && !sameY) {
|
|
@@ -48344,7 +48338,7 @@ function waypointsToSvgPath(waypoints, cornerRadius) {
|
|
|
48344
48338
|
const curr = waypoints[i];
|
|
48345
48339
|
const next = waypoints[i + 1];
|
|
48346
48340
|
const r = radii[i];
|
|
48347
|
-
if (r <
|
|
48341
|
+
if (r < 0.01) {
|
|
48348
48342
|
path54 += ` L ${curr[0]},${curr[1]}`;
|
|
48349
48343
|
continue;
|
|
48350
48344
|
}
|
|
@@ -48354,89 +48348,82 @@ function waypointsToSvgPath(waypoints, cornerRadius) {
|
|
|
48354
48348
|
const lenNext = Math.sqrt(dNext[0] * dNext[0] + dNext[1] * dNext[1]);
|
|
48355
48349
|
const uPrev = [dPrev[0] / lenPrev, dPrev[1] / lenPrev];
|
|
48356
48350
|
const uNext = [dNext[0] / lenNext, dNext[1] / lenNext];
|
|
48357
|
-
const
|
|
48358
|
-
const
|
|
48359
|
-
const
|
|
48351
|
+
const cross = uPrev[0] * uNext[1] - uPrev[1] * uNext[0];
|
|
48352
|
+
const deflection = Math.abs(cross);
|
|
48353
|
+
const scaledR = r * deflection;
|
|
48354
|
+
if (scaledR < 0.5) {
|
|
48355
|
+
path54 += ` L ${curr[0]},${curr[1]}`;
|
|
48356
|
+
continue;
|
|
48357
|
+
}
|
|
48358
|
+
const arcStart = [curr[0] + uPrev[0] * scaledR, curr[1] + uPrev[1] * scaledR];
|
|
48359
|
+
const arcEnd = [curr[0] + uNext[0] * scaledR, curr[1] + uNext[1] * scaledR];
|
|
48360
48360
|
const sweep = cross > 0 ? 0 : 1;
|
|
48361
48361
|
path54 += ` L ${arcStart[0]},${arcStart[1]}`;
|
|
48362
|
-
path54 += ` A ${
|
|
48362
|
+
path54 += ` A ${scaledR} ${scaledR} 0 0 ${sweep} ${arcEnd[0]},${arcEnd[1]}`;
|
|
48363
48363
|
}
|
|
48364
48364
|
const last = waypoints[waypoints.length - 1];
|
|
48365
48365
|
path54 += ` L ${last[0]},${last[1]}`;
|
|
48366
48366
|
return path54;
|
|
48367
48367
|
}
|
|
48368
|
-
function computeWaypoints(from, to, nodeBoxes, sourceNodeId, targetNodeId, padding, exitStub, entryStub, allocator) {
|
|
48369
|
-
const isSelfConnection = sourceNodeId === targetNodeId;
|
|
48370
|
-
const inflatedBoxes = nodeBoxes.
|
|
48368
|
+
function computeWaypoints(from, to, nodeBoxes, sourceNodeId, targetNodeId, padding, exitStub, entryStub, scopedInternal, allocator) {
|
|
48369
|
+
const isSelfConnection = sourceNodeId === targetNodeId && !scopedInternal;
|
|
48370
|
+
const inflatedBoxes = nodeBoxes.map((box) => inflateBox(box, padding));
|
|
48371
48371
|
const stubExit = [from[0] + exitStub, from[1]];
|
|
48372
48372
|
const stubEntry = [to[0] - entryStub, to[1]];
|
|
48373
48373
|
const xMin = Math.min(stubExit[0], stubEntry[0]);
|
|
48374
48374
|
const xMax = Math.max(stubExit[0], stubEntry[0]);
|
|
48375
|
-
if (!isSelfConnection && to[0]
|
|
48376
|
-
let candidateY = (from[1] + to[1]) / 2;
|
|
48377
|
-
const intermediateBoxes = inflatedBoxes.filter(
|
|
48378
|
-
(box) => box.left < xMax && box.right > xMin
|
|
48379
|
-
);
|
|
48375
|
+
if (!isSelfConnection && to[0] >= from[0] - exitStub) {
|
|
48376
|
+
let candidateY = (from[1] + to[1]) / 2 + BELOW_BIAS;
|
|
48377
|
+
const intermediateBoxes = inflatedBoxes.filter((box) => box.left < xMax && box.right > xMin);
|
|
48380
48378
|
if (intermediateBoxes.length >= 2) {
|
|
48381
48379
|
const clusterTop = Math.min(...intermediateBoxes.map((b) => b.top));
|
|
48382
48380
|
const clusterBottom = Math.max(...intermediateBoxes.map((b) => b.bottom));
|
|
48383
48381
|
if (candidateY > clusterTop && candidateY < clusterBottom) {
|
|
48384
48382
|
const distToTop = candidateY - clusterTop;
|
|
48385
48383
|
const distToBottom = clusterBottom - candidateY;
|
|
48386
|
-
candidateY = distToTop
|
|
48384
|
+
candidateY = distToTop < distToBottom ? clusterTop - padding : clusterBottom + padding;
|
|
48387
48385
|
}
|
|
48388
48386
|
}
|
|
48389
|
-
|
|
48390
|
-
if (Math.abs(from[1] - to[1]) < JOG_THRESHOLD && Math.abs(clearY - from[1]) < JOG_THRESHOLD) {
|
|
48391
|
-
return null;
|
|
48392
|
-
}
|
|
48393
|
-
const midX = (stubExit[0] + stubEntry[0]) / 2;
|
|
48387
|
+
const clearY = allocator ? allocator.claim(xMin, xMax, findClearY(xMin, xMax, candidateY, inflatedBoxes)) : findClearY(xMin, xMax, candidateY, inflatedBoxes);
|
|
48394
48388
|
const yMin = Math.min(from[1], to[1]);
|
|
48395
48389
|
const yMax = Math.max(from[1], to[1]);
|
|
48396
|
-
const
|
|
48397
|
-
const
|
|
48398
|
-
|
|
48399
|
-
|
|
48400
|
-
|
|
48401
|
-
allocator.claimVertical(yMin, yMax, freeMidX);
|
|
48390
|
+
const stubsCross = stubExit[0] >= stubEntry[0];
|
|
48391
|
+
const midX = stubsCross ? (from[0] + to[0]) / 2 : stubExit[0] + (stubEntry[0] - stubExit[0]) * 0.75;
|
|
48392
|
+
const freeMidX = findClearX(yMin, yMax || yMin + 1, midX, inflatedBoxes);
|
|
48393
|
+
const lShapeXValid = stubsCross ? freeMidX >= Math.min(from[0], to[0]) && freeMidX <= Math.max(from[0], to[0]) : freeMidX > stubExit[0] && freeMidX < stubEntry[0];
|
|
48394
|
+
if (lShapeXValid && verticalSegmentClear(freeMidX, yMin, yMax, inflatedBoxes) && !inflatedBoxes.some((box) => segmentOverlapsBox(stubExit[0], freeMidX, from[1], box)) && !inflatedBoxes.some((box) => segmentOverlapsBox(freeMidX, stubEntry[0], to[1], box))) {
|
|
48402
48395
|
return simplifyWaypoints([from, [freeMidX, from[1]], [freeMidX, to[1]], to]);
|
|
48403
48396
|
}
|
|
48404
|
-
clearY = allocator.findFreeY(xMin, xMax, clearY, inflatedBoxes);
|
|
48405
48397
|
if (Math.abs(clearY - from[1]) < JOG_THRESHOLD && !inflatedBoxes.some((box) => segmentOverlapsBox(xMin, xMax, from[1], box))) {
|
|
48406
|
-
|
|
48398
|
+
candidateY = from[1];
|
|
48407
48399
|
} else if (Math.abs(clearY - to[1]) < JOG_THRESHOLD && !inflatedBoxes.some((box) => segmentOverlapsBox(xMin, xMax, to[1], box))) {
|
|
48408
|
-
|
|
48400
|
+
candidateY = to[1];
|
|
48401
|
+
} else {
|
|
48402
|
+
candidateY = clearY;
|
|
48409
48403
|
}
|
|
48410
|
-
|
|
48411
|
-
const
|
|
48412
|
-
const exitYMax = Math.max(from[1], clearY);
|
|
48404
|
+
const exitYMin = Math.min(from[1], candidateY);
|
|
48405
|
+
const exitYMax = Math.max(from[1], candidateY);
|
|
48413
48406
|
let exitX = findClearX(exitYMin, exitYMax, stubExit[0], inflatedBoxes);
|
|
48414
|
-
exitX = allocator.findFreeX(exitYMin, exitYMax, exitX, inflatedBoxes);
|
|
48415
48407
|
if (exitX < from[0]) {
|
|
48416
48408
|
exitX = stubExit[0];
|
|
48417
48409
|
if (!verticalSegmentClear(exitX, exitYMin, exitYMax, inflatedBoxes)) {
|
|
48418
48410
|
exitX = findClearX(exitYMin, exitYMax, stubExit[0] + TRACK_SPACING, inflatedBoxes);
|
|
48419
|
-
exitX = allocator.findFreeX(exitYMin, exitYMax, exitX, inflatedBoxes);
|
|
48420
48411
|
}
|
|
48421
48412
|
}
|
|
48422
|
-
|
|
48423
|
-
const
|
|
48424
|
-
const entryYMax = Math.max(to[1], clearY);
|
|
48413
|
+
const entryYMin = Math.min(to[1], candidateY);
|
|
48414
|
+
const entryYMax = Math.max(to[1], candidateY);
|
|
48425
48415
|
let entryX = findClearX(entryYMin, entryYMax, stubEntry[0], inflatedBoxes);
|
|
48426
|
-
entryX = allocator.findFreeX(entryYMin, entryYMax, entryX, inflatedBoxes);
|
|
48427
48416
|
if (entryX > to[0]) {
|
|
48428
48417
|
entryX = stubEntry[0];
|
|
48429
48418
|
if (!verticalSegmentClear(entryX, entryYMin, entryYMax, inflatedBoxes)) {
|
|
48430
48419
|
entryX = findClearX(entryYMin, entryYMax, stubEntry[0] - TRACK_SPACING, inflatedBoxes);
|
|
48431
|
-
entryX = allocator.findFreeX(entryYMin, entryYMax, entryX, inflatedBoxes);
|
|
48432
48420
|
}
|
|
48433
48421
|
}
|
|
48434
|
-
allocator.claimVertical(entryYMin, entryYMax, entryX);
|
|
48435
48422
|
return simplifyWaypoints([
|
|
48436
48423
|
from,
|
|
48437
48424
|
[exitX, from[1]],
|
|
48438
|
-
[exitX,
|
|
48439
|
-
[entryX,
|
|
48425
|
+
[exitX, candidateY],
|
|
48426
|
+
[entryX, candidateY],
|
|
48440
48427
|
[entryX, to[1]],
|
|
48441
48428
|
to
|
|
48442
48429
|
]);
|
|
@@ -48456,23 +48443,17 @@ function computeWaypoints(from, to, nodeBoxes, sourceNodeId, targetNodeId, paddi
|
|
|
48456
48443
|
}
|
|
48457
48444
|
const maxBottom = Math.max(...bottoms, from[1] + 50, to[1] + 50);
|
|
48458
48445
|
const minTop = Math.min(...tops, from[1] - 50, to[1] - 50);
|
|
48459
|
-
const avgY = (from[1] + to[1]) / 2;
|
|
48446
|
+
const avgY = (from[1] + to[1]) / 2 + BELOW_BIAS;
|
|
48460
48447
|
const escapeBelow = maxBottom + padding;
|
|
48461
48448
|
const escapeAbove = minTop - padding;
|
|
48462
|
-
let escapeY = Math.abs(escapeAbove - avgY)
|
|
48463
|
-
escapeY = findClearY(xMin, xMax, escapeY, inflatedBoxes);
|
|
48464
|
-
escapeY = allocator.findFreeY(xMin, xMax, escapeY, inflatedBoxes);
|
|
48465
|
-
allocator.claim(xMin, xMax, escapeY);
|
|
48449
|
+
let escapeY = Math.abs(escapeAbove - avgY) < Math.abs(escapeBelow - avgY) ? escapeAbove : escapeBelow;
|
|
48450
|
+
escapeY = allocator ? allocator.claim(xMin, xMax, findClearY(xMin, xMax, escapeY, inflatedBoxes)) : findClearY(xMin, xMax, escapeY, inflatedBoxes);
|
|
48466
48451
|
const bwExitYMin = Math.min(from[1], escapeY);
|
|
48467
48452
|
const bwExitYMax = Math.max(from[1], escapeY);
|
|
48468
|
-
|
|
48469
|
-
bwExitX = allocator.findFreeX(bwExitYMin, bwExitYMax, bwExitX, inflatedBoxes);
|
|
48470
|
-
allocator.claimVertical(bwExitYMin, bwExitYMax, bwExitX);
|
|
48453
|
+
const bwExitX = findClearX(bwExitYMin, bwExitYMax, stubExit[0], inflatedBoxes);
|
|
48471
48454
|
const bwEntryYMin = Math.min(to[1], escapeY);
|
|
48472
48455
|
const bwEntryYMax = Math.max(to[1], escapeY);
|
|
48473
|
-
|
|
48474
|
-
bwEntryX = allocator.findFreeX(bwEntryYMin, bwEntryYMax, bwEntryX, inflatedBoxes);
|
|
48475
|
-
allocator.claimVertical(bwEntryYMin, bwEntryYMax, bwEntryX);
|
|
48456
|
+
const bwEntryX = findClearX(bwEntryYMin, bwEntryYMax, stubEntry[0], inflatedBoxes);
|
|
48476
48457
|
return simplifyWaypoints([
|
|
48477
48458
|
from,
|
|
48478
48459
|
[bwExitX, from[1]],
|
|
@@ -48483,7 +48464,7 @@ function computeWaypoints(from, to, nodeBoxes, sourceNodeId, targetNodeId, paddi
|
|
|
48483
48464
|
]);
|
|
48484
48465
|
}
|
|
48485
48466
|
}
|
|
48486
|
-
function calculateOrthogonalPath(from, to, nodeBoxes, sourceNodeId, targetNodeId, options
|
|
48467
|
+
function calculateOrthogonalPath(from, to, nodeBoxes, sourceNodeId, targetNodeId, options) {
|
|
48487
48468
|
const cornerRadius = options?.cornerRadius ?? 10;
|
|
48488
48469
|
const padding = options?.padding ?? 15;
|
|
48489
48470
|
const stubLength = options?.stubLength ?? 20;
|
|
@@ -48493,7 +48474,6 @@ function calculateOrthogonalPath(from, to, nodeBoxes, sourceNodeId, targetNodeId
|
|
|
48493
48474
|
const toPortIndex = options?.toPortIndex ?? 0;
|
|
48494
48475
|
const exitStub = Math.min(stubLength + fromPortIndex * stubSpacing, maxStubLength);
|
|
48495
48476
|
const entryStub = Math.min(stubLength + toPortIndex * stubSpacing, maxStubLength);
|
|
48496
|
-
const alloc = allocator ?? new TrackAllocator();
|
|
48497
48477
|
const waypoints = computeWaypoints(
|
|
48498
48478
|
from,
|
|
48499
48479
|
to,
|
|
@@ -48503,167 +48483,53 @@ function calculateOrthogonalPath(from, to, nodeBoxes, sourceNodeId, targetNodeId
|
|
|
48503
48483
|
padding,
|
|
48504
48484
|
exitStub,
|
|
48505
48485
|
entryStub,
|
|
48506
|
-
|
|
48486
|
+
options?.scopedInternal,
|
|
48487
|
+
options?.allocator
|
|
48507
48488
|
);
|
|
48508
48489
|
if (!waypoints) return null;
|
|
48509
48490
|
return waypointsToSvgPath(waypoints, cornerRadius);
|
|
48510
48491
|
}
|
|
48511
|
-
function calculateOrthogonalPathSafe(from, to, nodeBoxes, sourceNodeId, targetNodeId, options
|
|
48492
|
+
function calculateOrthogonalPathSafe(from, to, nodeBoxes, sourceNodeId, targetNodeId, options) {
|
|
48512
48493
|
try {
|
|
48513
|
-
const path54 = calculateOrthogonalPath(
|
|
48514
|
-
from,
|
|
48515
|
-
to,
|
|
48516
|
-
nodeBoxes,
|
|
48517
|
-
sourceNodeId,
|
|
48518
|
-
targetNodeId,
|
|
48519
|
-
options,
|
|
48520
|
-
allocator
|
|
48521
|
-
);
|
|
48494
|
+
const path54 = calculateOrthogonalPath(from, to, nodeBoxes, sourceNodeId, targetNodeId, options);
|
|
48522
48495
|
if (!path54 || path54.length < 5) return null;
|
|
48523
48496
|
return path54;
|
|
48524
48497
|
} catch {
|
|
48525
48498
|
return null;
|
|
48526
48499
|
}
|
|
48527
48500
|
}
|
|
48528
|
-
var TRACK_SPACING, EDGE_OFFSET,
|
|
48501
|
+
var TRACK_SPACING, EDGE_OFFSET, BELOW_BIAS, TrackAllocator, MIN_SEGMENT_LENGTH, JOG_THRESHOLD;
|
|
48529
48502
|
var init_orthogonal_router = __esm({
|
|
48530
48503
|
"src/diagram/orthogonal-router.ts"() {
|
|
48531
48504
|
"use strict";
|
|
48532
48505
|
TRACK_SPACING = 15;
|
|
48533
48506
|
EDGE_OFFSET = 5;
|
|
48534
|
-
|
|
48507
|
+
BELOW_BIAS = 40;
|
|
48535
48508
|
TrackAllocator = class {
|
|
48536
|
-
claims =
|
|
48537
|
-
|
|
48538
|
-
|
|
48539
|
-
|
|
48540
|
-
|
|
48541
|
-
if (
|
|
48542
|
-
|
|
48543
|
-
|
|
48544
|
-
|
|
48545
|
-
|
|
48546
|
-
|
|
48547
|
-
|
|
48548
|
-
|
|
48549
|
-
|
|
48550
|
-
|
|
48551
|
-
|
|
48552
|
-
|
|
48553
|
-
|
|
48554
|
-
|
|
48555
|
-
|
|
48556
|
-
|
|
48557
|
-
isBlockedByNode(xMin, xMax, y, boxes) {
|
|
48558
|
-
for (const box of boxes) {
|
|
48559
|
-
if (xMin < box.right && xMax > box.left && y >= box.top && y <= box.bottom) {
|
|
48560
|
-
return true;
|
|
48561
|
-
}
|
|
48562
|
-
}
|
|
48563
|
-
return false;
|
|
48564
|
-
}
|
|
48565
|
-
/** Check if a vertical segment at X passes through any inflated node box. */
|
|
48566
|
-
isBlockedByNodeVertical(yMin, yMax, x2, boxes) {
|
|
48567
|
-
for (const box of boxes) {
|
|
48568
|
-
if (x2 >= box.left && x2 <= box.right && yMin < box.bottom && yMax > box.top) {
|
|
48569
|
-
return true;
|
|
48570
|
-
}
|
|
48571
|
-
}
|
|
48572
|
-
return false;
|
|
48573
|
-
}
|
|
48574
|
-
/** Count claimed vertical segments that a horizontal segment at Y would cross. */
|
|
48575
|
-
countHorizontalCrossings(xMin, xMax, y) {
|
|
48576
|
-
let count = 0;
|
|
48577
|
-
for (const c of this.verticalClaims) {
|
|
48578
|
-
if (c.x > xMin && c.x < xMax && y >= c.yMin && y <= c.yMax) {
|
|
48579
|
-
count++;
|
|
48580
|
-
}
|
|
48581
|
-
}
|
|
48582
|
-
return count;
|
|
48583
|
-
}
|
|
48584
|
-
/** Count claimed horizontal segments that a vertical segment at X would cross. */
|
|
48585
|
-
countVerticalCrossings(yMin, yMax, x2) {
|
|
48586
|
-
let count = 0;
|
|
48587
|
-
for (const c of this.claims) {
|
|
48588
|
-
if (c.y > yMin && c.y < yMax && x2 >= c.xMin && x2 <= c.xMax) {
|
|
48589
|
-
count++;
|
|
48590
|
-
}
|
|
48591
|
-
}
|
|
48592
|
-
return count;
|
|
48593
|
-
}
|
|
48594
|
-
/**
|
|
48595
|
-
* Find the nearest free Y to candidateY in the given X range, preferring fewer crossings.
|
|
48596
|
-
* When nodeBoxes is provided, candidates inside inflated node boxes are rejected (hard constraint).
|
|
48597
|
-
*/
|
|
48598
|
-
findFreeY(xMin, xMax, candidateY, nodeBoxes) {
|
|
48599
|
-
const isFree = (y) => !this.isOccupied(xMin, xMax, y) && (!nodeBoxes || !this.isBlockedByNode(xMin, xMax, y, nodeBoxes));
|
|
48600
|
-
if (isFree(candidateY)) return candidateY;
|
|
48601
|
-
const candidates = [];
|
|
48602
|
-
for (let offset = TRACK_SPACING; offset < 800 && candidates.length < MAX_CANDIDATES * 2; offset += TRACK_SPACING) {
|
|
48603
|
-
const above = candidateY - offset;
|
|
48604
|
-
if (isFree(above)) {
|
|
48605
|
-
candidates.push({ y: above, dist: offset });
|
|
48606
|
-
}
|
|
48607
|
-
const below = candidateY + offset;
|
|
48608
|
-
if (isFree(below)) {
|
|
48609
|
-
candidates.push({ y: below, dist: offset });
|
|
48610
|
-
}
|
|
48611
|
-
}
|
|
48612
|
-
if (candidates.length === 0) return candidateY;
|
|
48613
|
-
let bestY = candidates[0].y;
|
|
48614
|
-
let bestCrossings = this.countHorizontalCrossings(xMin, xMax, candidates[0].y);
|
|
48615
|
-
let bestDist = candidates[0].dist;
|
|
48616
|
-
for (let i = 1; i < candidates.length; i++) {
|
|
48617
|
-
const c = candidates[i];
|
|
48618
|
-
const crossings = this.countHorizontalCrossings(xMin, xMax, c.y);
|
|
48619
|
-
if (crossings < bestCrossings || crossings === bestCrossings && c.dist < bestDist) {
|
|
48620
|
-
bestY = c.y;
|
|
48621
|
-
bestCrossings = crossings;
|
|
48622
|
-
bestDist = c.dist;
|
|
48623
|
-
}
|
|
48624
|
-
}
|
|
48625
|
-
return bestY;
|
|
48626
|
-
}
|
|
48627
|
-
/**
|
|
48628
|
-
* Find the nearest free X to candidateX in the given Y range, preferring fewer crossings.
|
|
48629
|
-
* When nodeBoxes is provided, candidates inside inflated node boxes are rejected (hard constraint).
|
|
48630
|
-
*/
|
|
48631
|
-
findFreeX(yMin, yMax, candidateX, nodeBoxes) {
|
|
48632
|
-
const isFree = (x2) => !this.isOccupiedVertical(yMin, yMax, x2) && (!nodeBoxes || !this.isBlockedByNodeVertical(yMin, yMax, x2, nodeBoxes));
|
|
48633
|
-
if (isFree(candidateX)) return candidateX;
|
|
48634
|
-
const candidates = [];
|
|
48635
|
-
for (let offset = TRACK_SPACING; offset < 800 && candidates.length < MAX_CANDIDATES * 2; offset += TRACK_SPACING) {
|
|
48636
|
-
const left = candidateX - offset;
|
|
48637
|
-
if (isFree(left)) {
|
|
48638
|
-
candidates.push({ x: left, dist: offset });
|
|
48639
|
-
}
|
|
48640
|
-
const right = candidateX + offset;
|
|
48641
|
-
if (isFree(right)) {
|
|
48642
|
-
candidates.push({ x: right, dist: offset });
|
|
48643
|
-
}
|
|
48644
|
-
}
|
|
48645
|
-
if (candidates.length === 0) return candidateX;
|
|
48646
|
-
let bestX = candidates[0].x;
|
|
48647
|
-
let bestCrossings = this.countVerticalCrossings(yMin, yMax, candidates[0].x);
|
|
48648
|
-
let bestDist = candidates[0].dist;
|
|
48649
|
-
for (let i = 1; i < candidates.length; i++) {
|
|
48650
|
-
const c = candidates[i];
|
|
48651
|
-
const crossings = this.countVerticalCrossings(yMin, yMax, c.x);
|
|
48652
|
-
if (crossings < bestCrossings || crossings === bestCrossings && c.dist < bestDist) {
|
|
48653
|
-
bestX = c.x;
|
|
48654
|
-
bestCrossings = crossings;
|
|
48655
|
-
bestDist = c.dist;
|
|
48509
|
+
claims = /* @__PURE__ */ new Map();
|
|
48510
|
+
claim(xMin, xMax, candidateY) {
|
|
48511
|
+
const snap = (y) => Math.round(y / TRACK_SPACING) * TRACK_SPACING;
|
|
48512
|
+
const overlaps = (slot) => {
|
|
48513
|
+
const intervals = this.claims.get(slot);
|
|
48514
|
+
if (!intervals) return false;
|
|
48515
|
+
return intervals.some(([a, b]) => xMin < b && xMax > a);
|
|
48516
|
+
};
|
|
48517
|
+
const take = (slot) => {
|
|
48518
|
+
if (!this.claims.has(slot)) this.claims.set(slot, []);
|
|
48519
|
+
const slotClaims = this.claims.get(slot);
|
|
48520
|
+
if (slotClaims) slotClaims.push([xMin, xMax]);
|
|
48521
|
+
return slot;
|
|
48522
|
+
};
|
|
48523
|
+
const base = snap(candidateY);
|
|
48524
|
+
for (let i = 0; i < 60; i++) {
|
|
48525
|
+
const below = base + i * TRACK_SPACING;
|
|
48526
|
+
if (!overlaps(below)) return take(below);
|
|
48527
|
+
if (i > 0) {
|
|
48528
|
+
const above = base - i * TRACK_SPACING;
|
|
48529
|
+
if (!overlaps(above)) return take(above);
|
|
48656
48530
|
}
|
|
48657
48531
|
}
|
|
48658
|
-
return
|
|
48659
|
-
}
|
|
48660
|
-
/** Claim a horizontal segment so later connections avoid it. */
|
|
48661
|
-
claim(xMin, xMax, y) {
|
|
48662
|
-
this.claims.push({ xMin, xMax, y });
|
|
48663
|
-
}
|
|
48664
|
-
/** Claim a vertical segment so later connections avoid it. */
|
|
48665
|
-
claimVertical(yMin, yMax, x2) {
|
|
48666
|
-
this.verticalClaims.push({ yMin, yMax, x: x2 });
|
|
48532
|
+
return candidateY;
|
|
48667
48533
|
}
|
|
48668
48534
|
};
|
|
48669
48535
|
MIN_SEGMENT_LENGTH = 3;
|
|
@@ -48708,49 +48574,8 @@ function positionPortList(ports, cx, nodeY, _nodeHeight) {
|
|
|
48708
48574
|
ports[i].cy = nodeY + PORT_PADDING_Y + i * (PORT_SIZE + PORT_GAP) + PORT_SIZE / 2;
|
|
48709
48575
|
}
|
|
48710
48576
|
}
|
|
48711
|
-
function quadCurveControl(ax, ay, bx, by, ux, uy) {
|
|
48712
|
-
const dn = Math.abs(ay - by);
|
|
48713
|
-
const cx = bx + ux * dn / Math.abs(uy);
|
|
48714
|
-
const cy = ay;
|
|
48715
|
-
return [cx, cy];
|
|
48716
|
-
}
|
|
48717
48577
|
function computeConnectionPath(sx, sy, tx, ty) {
|
|
48718
|
-
|
|
48719
|
-
const ax = sx + e;
|
|
48720
|
-
const ay = sy + e;
|
|
48721
|
-
const hx = tx - e;
|
|
48722
|
-
const hy = ty - e;
|
|
48723
|
-
const ramp = Math.min(20, (hx - ax) / 10);
|
|
48724
|
-
const bx = ax + ramp;
|
|
48725
|
-
const by = ay + e;
|
|
48726
|
-
const gx = hx - ramp;
|
|
48727
|
-
const gy = hy - e;
|
|
48728
|
-
const curveSizeX = Math.min(60, Math.abs(ax - hx) / 4);
|
|
48729
|
-
const curveSizeY = Math.min(60, Math.abs(ay - hy) / 4);
|
|
48730
|
-
const curveMag = Math.sqrt(curveSizeX * curveSizeX + curveSizeY * curveSizeY);
|
|
48731
|
-
const bgX = gx - bx;
|
|
48732
|
-
const bgY = gy - by;
|
|
48733
|
-
const bgLen = Math.sqrt(bgX * bgX + bgY * bgY);
|
|
48734
|
-
const bgUx = bgX / bgLen;
|
|
48735
|
-
const bgUy = bgY / bgLen;
|
|
48736
|
-
const dx = bx + bgUx * curveMag;
|
|
48737
|
-
const dy = by + bgUy * curveMag / 2;
|
|
48738
|
-
const ex = gx - bgUx * curveMag;
|
|
48739
|
-
const ey = gy - bgUy * curveMag / 2;
|
|
48740
|
-
const deX = ex - dx;
|
|
48741
|
-
const deY = ey - dy;
|
|
48742
|
-
const deLen = Math.sqrt(deX * deX + deY * deY);
|
|
48743
|
-
const deUx = deX / deLen;
|
|
48744
|
-
const deUy = deY / deLen;
|
|
48745
|
-
const [cx, cy] = quadCurveControl(bx, by, dx, dy, -deUx, -deUy);
|
|
48746
|
-
const [fx, fy] = quadCurveControl(gx, gy, ex, ey, deUx, deUy);
|
|
48747
|
-
let path54 = `M ${cx},${cy} M ${ax},${ay}`;
|
|
48748
|
-
path54 += ` L ${bx},${by}`;
|
|
48749
|
-
path54 += ` Q ${cx},${cy} ${dx},${dy}`;
|
|
48750
|
-
path54 += ` L ${ex},${ey}`;
|
|
48751
|
-
path54 += ` Q ${fx},${fy} ${gx},${gy}`;
|
|
48752
|
-
path54 += ` L ${hx},${hy}`;
|
|
48753
|
-
return path54;
|
|
48578
|
+
return `M ${sx},${sy} L ${tx},${ty}`;
|
|
48754
48579
|
}
|
|
48755
48580
|
function orderedPorts(ports, direction) {
|
|
48756
48581
|
const cloned = {};
|
|
@@ -49510,22 +49335,22 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
49510
49335
|
color: targetColor,
|
|
49511
49336
|
dashed
|
|
49512
49337
|
};
|
|
49338
|
+
const isStaticSvg = options.format !== "html";
|
|
49339
|
+
const pathSx = isStaticSvg ? sx + srcLabelEnd : sx;
|
|
49340
|
+
const pathTx = isStaticSvg ? tx - tgtLabelEnd : tx;
|
|
49513
49341
|
let path54;
|
|
49514
49342
|
if (xDistance > STUB_DISTANCE_THRESHOLD) {
|
|
49515
49343
|
path54 = "";
|
|
49516
|
-
} else
|
|
49344
|
+
} else {
|
|
49517
49345
|
const orthoPath = calculateOrthogonalPathSafe(
|
|
49518
|
-
[
|
|
49519
|
-
[
|
|
49346
|
+
[pathSx, sy],
|
|
49347
|
+
[pathTx, ty],
|
|
49520
49348
|
nodeBoxes,
|
|
49521
49349
|
pc3.fromNodeId,
|
|
49522
49350
|
pc3.toNodeId,
|
|
49523
|
-
{ fromPortIndex: pc3.fromPortIndex, toPortIndex: pc3.toPortIndex }
|
|
49524
|
-
allocator
|
|
49351
|
+
{ fromPortIndex: pc3.fromPortIndex, toPortIndex: pc3.toPortIndex, allocator }
|
|
49525
49352
|
);
|
|
49526
|
-
path54 = orthoPath ?? computeConnectionPath(
|
|
49527
|
-
} else {
|
|
49528
|
-
path54 = computeConnectionPath(sx, sy, tx, ty);
|
|
49353
|
+
path54 = orthoPath ?? computeConnectionPath(pathSx, sy, pathTx, ty);
|
|
49529
49354
|
}
|
|
49530
49355
|
connections.push({
|
|
49531
49356
|
fromNode: pc3.fromNodeId,
|
|
@@ -49615,20 +49440,15 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
49615
49440
|
const ddy = ty - sy;
|
|
49616
49441
|
const dist = Math.sqrt(ddx * ddx + ddy * ddy);
|
|
49617
49442
|
const useCurve = spForceCurveSet.has(sp);
|
|
49618
|
-
|
|
49619
|
-
|
|
49620
|
-
|
|
49621
|
-
|
|
49622
|
-
|
|
49623
|
-
|
|
49624
|
-
|
|
49625
|
-
|
|
49626
|
-
|
|
49627
|
-
);
|
|
49628
|
-
sp.conn.path = orthoPath ?? computeConnectionPath(sx, sy, tx, ty);
|
|
49629
|
-
} else {
|
|
49630
|
-
sp.conn.path = computeConnectionPath(sx, sy, tx, ty);
|
|
49631
|
-
}
|
|
49443
|
+
const orthoPath = calculateOrthogonalPathSafe(
|
|
49444
|
+
[sx, sy],
|
|
49445
|
+
[tx, ty],
|
|
49446
|
+
nodeBoxes,
|
|
49447
|
+
sp.fromNodeId,
|
|
49448
|
+
sp.toNodeId,
|
|
49449
|
+
{ fromPortIndex: sp.fromPortIndex, toPortIndex: sp.toPortIndex, allocator }
|
|
49450
|
+
);
|
|
49451
|
+
sp.conn.path = orthoPath ?? computeConnectionPath(sx, sy, tx, ty);
|
|
49632
49452
|
}
|
|
49633
49453
|
}
|
|
49634
49454
|
let originX = 0;
|
|
@@ -49741,11 +49561,11 @@ var init_geometry = __esm({
|
|
|
49741
49561
|
LABEL_CLEARANCE = 42;
|
|
49742
49562
|
MIN_EDGE_GAP = 112;
|
|
49743
49563
|
NODE_GAP_Y = 60;
|
|
49744
|
-
LABEL_HEIGHT =
|
|
49564
|
+
LABEL_HEIGHT = 24;
|
|
49745
49565
|
LABEL_GAP = 12;
|
|
49746
49566
|
SCOPE_PADDING_X = 140;
|
|
49747
49567
|
SCOPE_PADDING_Y = 40;
|
|
49748
|
-
SCOPE_PORT_COLUMN =
|
|
49568
|
+
SCOPE_PORT_COLUMN = 45;
|
|
49749
49569
|
SCOPE_INNER_GAP_X = 240;
|
|
49750
49570
|
ORTHOGONAL_DISTANCE_THRESHOLD = 300;
|
|
49751
49571
|
STUB_DISTANCE_THRESHOLD = 500;
|
|
@@ -50646,6 +50466,15 @@ var init_describe = __esm({
|
|
|
50646
50466
|
function escapeXml(str2) {
|
|
50647
50467
|
return str2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
50648
50468
|
}
|
|
50469
|
+
function resolveIconColor(nodeColor, themeName, theme) {
|
|
50470
|
+
if (nodeColor === NODE_DEFAULT_COLOR) return theme.nodeIconColor;
|
|
50471
|
+
for (const v2 of Object.values(NODE_VARIANT_COLORS)) {
|
|
50472
|
+
if (v2.darkBorder === nodeColor || v2.border === nodeColor) {
|
|
50473
|
+
return themeName === "dark" ? v2.darkIcon : v2.icon;
|
|
50474
|
+
}
|
|
50475
|
+
}
|
|
50476
|
+
return nodeColor;
|
|
50477
|
+
}
|
|
50649
50478
|
function collectAllConnections(graph) {
|
|
50650
50479
|
const all = [...graph.connections];
|
|
50651
50480
|
for (const node of graph.nodes) {
|
|
@@ -50672,21 +50501,18 @@ function renderSVG(graph, options = {}) {
|
|
|
50672
50501
|
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${vbX} ${vbY} ${vbWidth} ${vbHeight}" width="${svgWidth}" height="${svgHeight}">`
|
|
50673
50502
|
);
|
|
50674
50503
|
parts.push(`<style>`);
|
|
50675
|
-
parts.push(` text { font-family: Montserrat, 'Segoe UI', Roboto, sans-serif; }`);
|
|
50676
|
-
parts.push(` .node-label { font-size:
|
|
50504
|
+
parts.push(` text { font-family: Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; }`);
|
|
50505
|
+
parts.push(` .node-label { font-size: 18px; font-weight: 600; fill: ${theme.labelColor}; }`);
|
|
50677
50506
|
parts.push(` .port-label { font-size: 10px; font-weight: 600; fill: ${theme.labelColor}; }`);
|
|
50678
50507
|
parts.push(` .port-type-label { font-size: 10px; font-weight: 600; }`);
|
|
50679
50508
|
parts.push(`</style>`);
|
|
50680
50509
|
parts.push(`<defs>`);
|
|
50681
50510
|
parts.push(` <pattern id="dot-grid" width="20" height="20" patternUnits="userSpaceOnUse">`);
|
|
50682
|
-
parts.push(` <circle cx="10" cy="10" r="
|
|
50511
|
+
parts.push(` <circle cx="10" cy="10" r="0.75" fill="${theme.dotColor}" opacity="${theme.dotOpacity}"/>`);
|
|
50683
50512
|
parts.push(` </pattern>`);
|
|
50684
|
-
parts.push(` <filter id="node-shadow" x="-10%" y="-10%" width="130%" height="140%">`);
|
|
50685
|
-
parts.push(` <feDropShadow dx="0" dy="2" stdDeviation="4" flood-opacity="${theme.nodeShadowOpacity}" flood-color="#000"/>`);
|
|
50686
|
-
parts.push(` </filter>`);
|
|
50687
50513
|
for (let i = 0; i < allConnections.length; i++) {
|
|
50688
50514
|
const conn = allConnections[i];
|
|
50689
|
-
parts.push(` <linearGradient id="conn-grad-${i}" x1="
|
|
50515
|
+
parts.push(` <linearGradient id="conn-grad-${i}" gradientUnits="userSpaceOnUse" x1="${vbX}" y1="0" x2="${vbX + vbWidth}" y2="0">`);
|
|
50690
50516
|
parts.push(` <stop offset="0%" stop-color="${conn.sourceColor}"/>`);
|
|
50691
50517
|
parts.push(` <stop offset="100%" stop-color="${conn.targetColor}"/>`);
|
|
50692
50518
|
parts.push(` </linearGradient>`);
|
|
@@ -50728,13 +50554,6 @@ function renderSVG(graph, options = {}) {
|
|
|
50728
50554
|
}
|
|
50729
50555
|
}
|
|
50730
50556
|
parts.push(`</g>`);
|
|
50731
|
-
const wmX = vbX + vbWidth - 16;
|
|
50732
|
-
const wmY = vbY + vbHeight - 14;
|
|
50733
|
-
const wmBrand = themeName === "dark" ? "#8e9eff" : "#5468ff";
|
|
50734
|
-
parts.push(`<g opacity="0.5">`);
|
|
50735
|
-
parts.push(` <svg x="${wmX - 118}" y="${wmY - 18}" width="22" height="22" viewBox="0 0 256 256" fill="none"><path d="M80 128C134 128 122 49 176 49" stroke="${wmBrand}" stroke-width="14" stroke-linecap="round"/><path d="M80 128C134 128 122 207 176 207" stroke="${wmBrand}" stroke-width="14" stroke-linecap="round"/><rect x="28" y="102" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/><rect x="176" y="23" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/><rect x="176" y="181" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/></svg>`);
|
|
50736
|
-
parts.push(` <text x="${wmX}" y="${wmY}" text-anchor="end" font-size="14" font-weight="700" fill="${wmBrand}" font-family="Montserrat, 'Segoe UI', Roboto, sans-serif">Flow Weaver</text>`);
|
|
50737
|
-
parts.push(`</g>`);
|
|
50738
50557
|
parts.push(`</svg>`);
|
|
50739
50558
|
return parts.join("\n");
|
|
50740
50559
|
}
|
|
@@ -50743,7 +50562,7 @@ function renderConnection(parts, conn, gradIndex, hidden = false) {
|
|
|
50743
50562
|
const displayAttr = hidden ? ' display="none"' : "";
|
|
50744
50563
|
const pathD = conn.path || "M0,0";
|
|
50745
50564
|
parts.push(
|
|
50746
|
-
` <path d="${pathD}" fill="none" stroke="url(#conn-grad-${gradIndex})" stroke-width="
|
|
50565
|
+
` <path d="${pathD}" fill="none" stroke="url(#conn-grad-${gradIndex})" stroke-width="1"${dashAttr} stroke-linecap="round" data-source="${escapeXml(conn.fromNode)}.${escapeXml(conn.fromPort)}:output" data-target="${escapeXml(conn.toNode)}.${escapeXml(conn.toPort)}:input"${displayAttr}/>`
|
|
50747
50566
|
);
|
|
50748
50567
|
}
|
|
50749
50568
|
function renderStub(parts, stub, conn, hidden = false) {
|
|
@@ -50763,17 +50582,17 @@ function renderScopeConnection(parts, conn, allConnections, parentNodeId) {
|
|
|
50763
50582
|
if (gradIndex < 0) return;
|
|
50764
50583
|
const dashAttr = conn.isStepConnection ? "" : ' stroke-dasharray="8 4"';
|
|
50765
50584
|
parts.push(
|
|
50766
|
-
` <path d="${conn.path}" fill="none" stroke="url(#conn-grad-${gradIndex})" stroke-width="
|
|
50585
|
+
` <path d="${conn.path}" fill="none" stroke="url(#conn-grad-${gradIndex})" stroke-width="1"${dashAttr} stroke-linecap="round" data-source="${escapeXml(conn.fromNode)}.${escapeXml(conn.fromPort)}:output" data-target="${escapeXml(conn.toNode)}.${escapeXml(conn.toPort)}:input" data-scope="${escapeXml(parentNodeId)}"/>`
|
|
50767
50586
|
);
|
|
50768
50587
|
}
|
|
50769
|
-
function renderNodeBody(parts, node, theme, indent) {
|
|
50588
|
+
function renderNodeBody(parts, node, theme, themeName, indent) {
|
|
50770
50589
|
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
50771
50590
|
parts.push(
|
|
50772
|
-
`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.
|
|
50591
|
+
`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.background}" stroke="${strokeColor}" stroke-width="2"/>`
|
|
50773
50592
|
);
|
|
50774
50593
|
const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
|
|
50775
|
-
const iconColor = node.color
|
|
50776
|
-
const iconSize =
|
|
50594
|
+
const iconColor = resolveIconColor(node.color, themeName, theme);
|
|
50595
|
+
const iconSize = 50;
|
|
50777
50596
|
const iconX = node.x + (node.width - iconSize) / 2;
|
|
50778
50597
|
const iconY = node.y + (node.height - iconSize) / 2;
|
|
50779
50598
|
parts.push(
|
|
@@ -50786,13 +50605,13 @@ function renderNode(node, theme, themeName, allConnections) {
|
|
|
50786
50605
|
if (node.scopeChildren && node.scopeChildren.length > 0) {
|
|
50787
50606
|
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
50788
50607
|
parts.push(
|
|
50789
|
-
` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.
|
|
50608
|
+
` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.background}" stroke="${strokeColor}" stroke-width="2"/>`
|
|
50790
50609
|
);
|
|
50791
50610
|
renderScopedContent(parts, node, theme, themeName, allConnections);
|
|
50792
50611
|
} else {
|
|
50793
|
-
renderNodeBody(parts, node, theme, " ");
|
|
50612
|
+
renderNodeBody(parts, node, theme, themeName, " ");
|
|
50794
50613
|
}
|
|
50795
|
-
renderPortDots(parts, node.id, node.inputs, node.outputs, themeName);
|
|
50614
|
+
renderPortDots(parts, node.id, node.inputs, node.outputs, themeName, theme);
|
|
50796
50615
|
parts.push(` </g>`);
|
|
50797
50616
|
return parts.join("\n");
|
|
50798
50617
|
}
|
|
@@ -50800,38 +50619,45 @@ function renderScopedContent(parts, node, theme, themeName, allConnections) {
|
|
|
50800
50619
|
const children = node.scopeChildren;
|
|
50801
50620
|
const scopePorts = node.scopePorts;
|
|
50802
50621
|
const scopeX = node.x + SCOPE_PORT_COLUMN;
|
|
50803
|
-
const scopeY = node.y + 4;
|
|
50804
50622
|
const scopeW = node.width - SCOPE_PORT_COLUMN * 2;
|
|
50805
|
-
const
|
|
50623
|
+
const scopeRightX = node.x + node.width - SCOPE_PORT_COLUMN;
|
|
50624
|
+
const lineY1 = node.y;
|
|
50625
|
+
const lineY2 = node.y + node.height;
|
|
50626
|
+
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
50806
50627
|
parts.push(
|
|
50807
|
-
` <
|
|
50628
|
+
` <line x1="${scopeX}" y1="${lineY1}" x2="${scopeX}" y2="${lineY2}" stroke="${strokeColor}" stroke-width="2" opacity="0.5"/>`
|
|
50629
|
+
);
|
|
50630
|
+
parts.push(
|
|
50631
|
+
` <line x1="${scopeRightX}" y1="${lineY1}" x2="${scopeRightX}" y2="${lineY2}" stroke="${strokeColor}" stroke-width="2" opacity="0.5"/>`
|
|
50632
|
+
);
|
|
50633
|
+
parts.push(
|
|
50634
|
+
` <line x1="${scopeX}" y1="${lineY1 + 2}" x2="${scopeRightX}" y2="${lineY1 + 2}" stroke="${theme.scopeAreaStroke}" stroke-width="1" opacity="0.3"/>`
|
|
50635
|
+
);
|
|
50636
|
+
parts.push(
|
|
50637
|
+
` <line x1="${scopeX}" y1="${lineY2 - 2}" x2="${scopeRightX}" y2="${lineY2 - 2}" stroke="${theme.scopeAreaStroke}" stroke-width="1" opacity="0.3"/>`
|
|
50808
50638
|
);
|
|
50809
50639
|
for (const conn of node.scopeConnections ?? []) {
|
|
50810
50640
|
renderScopeConnection(parts, conn, allConnections, node.id);
|
|
50811
50641
|
}
|
|
50812
50642
|
if (scopePorts) {
|
|
50813
|
-
renderPortDots(parts, node.id, scopePorts.inputs, scopePorts.outputs, themeName);
|
|
50643
|
+
renderPortDots(parts, node.id, scopePorts.inputs, scopePorts.outputs, themeName, theme);
|
|
50814
50644
|
}
|
|
50815
50645
|
for (const child of children) {
|
|
50816
50646
|
parts.push(` <g data-node-id="${escapeXml(child.id)}">`);
|
|
50817
|
-
renderNodeBody(parts, child, theme, " ");
|
|
50818
|
-
renderPortDots(parts, child.id, child.inputs, child.outputs, themeName);
|
|
50647
|
+
renderNodeBody(parts, child, theme, themeName, " ");
|
|
50648
|
+
renderPortDots(parts, child.id, child.inputs, child.outputs, themeName, theme);
|
|
50819
50649
|
parts.push(` </g>`);
|
|
50820
50650
|
}
|
|
50821
50651
|
}
|
|
50822
50652
|
function renderNodeLabel(parts, node, theme) {
|
|
50823
50653
|
const isScoped = !!(node.scopeChildren && node.scopeChildren.length > 0);
|
|
50824
50654
|
const labelText = escapeXml(node.label);
|
|
50825
|
-
const
|
|
50826
|
-
const
|
|
50827
|
-
const labelBgHeight = LABEL_HEIGHT;
|
|
50828
|
-
const labelBgX = isScoped ? node.x : node.x + node.width / 2 - labelBgWidth / 2;
|
|
50829
|
-
const labelBgY = node.y - LABEL_GAP - labelBgHeight;
|
|
50830
|
-
const labelTextX = isScoped ? node.x + 8 : node.x + node.width / 2;
|
|
50655
|
+
const labelTextX = isScoped ? node.x + 6 : node.x + node.width / 2;
|
|
50656
|
+
const labelTextY = node.y - LABEL_GAP;
|
|
50831
50657
|
const labelAnchor = isScoped ? "start" : "middle";
|
|
50658
|
+
const labelColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor;
|
|
50832
50659
|
parts.push(` <g data-label-for="${escapeXml(node.id)}">`);
|
|
50833
|
-
parts.push(` <
|
|
50834
|
-
parts.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor}">${labelText}</text>`);
|
|
50660
|
+
parts.push(` <text class="node-label" x="${labelTextX}" y="${labelTextY}" text-anchor="${labelAnchor}" fill="${labelColor}">${labelText}</text>`);
|
|
50835
50661
|
parts.push(` </g>`);
|
|
50836
50662
|
}
|
|
50837
50663
|
function renderPortLabelsForNode(parts, node, theme, themeName, showPortLabels) {
|
|
@@ -50839,46 +50665,50 @@ function renderPortLabelsForNode(parts, node, theme, themeName, showPortLabels)
|
|
|
50839
50665
|
renderPortLabels(parts, node.id, node.inputs, node.outputs, theme, themeName);
|
|
50840
50666
|
}
|
|
50841
50667
|
}
|
|
50842
|
-
function renderPortDots(parts, nodeId, inputs, outputs, themeName) {
|
|
50668
|
+
function renderPortDots(parts, nodeId, inputs, outputs, themeName, theme) {
|
|
50669
|
+
const barWidth = 2;
|
|
50670
|
+
const barHeight = 14;
|
|
50671
|
+
const ringWidth = 2;
|
|
50672
|
+
const outerW = barWidth + ringWidth * 2;
|
|
50673
|
+
const outerH = barHeight + ringWidth * 2;
|
|
50843
50674
|
for (const port of [...inputs, ...outputs]) {
|
|
50844
50675
|
const color = getPortColor(port.dataType, port.isFailure, themeName);
|
|
50845
|
-
const ringColor = getPortRingColor(port.dataType, port.isFailure, themeName);
|
|
50846
50676
|
const dir = port.direction === "INPUT" ? "input" : "output";
|
|
50847
|
-
|
|
50677
|
+
const ox = port.cx - outerW / 2;
|
|
50678
|
+
const oy = port.cy - outerH / 2;
|
|
50679
|
+
const ix = port.cx - barWidth / 2;
|
|
50680
|
+
const iy = port.cy - barHeight / 2;
|
|
50681
|
+
parts.push(` <rect x="${ox}" y="${oy}" width="${outerW}" height="${outerH}" rx="4" fill="${color}" data-port-id="${escapeXml(nodeId)}.${escapeXml(port.name)}:${dir}" data-direction="${dir}"/>`);
|
|
50682
|
+
parts.push(` <rect x="${ix}" y="${iy}" width="${barWidth}" height="${barHeight}" rx="2" fill="${theme.background}" pointer-events="none"/>`);
|
|
50848
50683
|
}
|
|
50849
50684
|
}
|
|
50850
50685
|
function renderPortLabels(parts, nodeId, inputs, outputs, theme, themeName) {
|
|
50851
50686
|
for (const port of [...inputs, ...outputs]) {
|
|
50852
50687
|
const color = getPortColor(port.dataType, port.isFailure, themeName);
|
|
50853
50688
|
const isInput = port.direction === "INPUT";
|
|
50854
|
-
const abbrev = TYPE_ABBREVIATIONS[port.dataType] ?? port.dataType;
|
|
50855
50689
|
const dir = isInput ? "input" : "output";
|
|
50856
50690
|
const portId = `${escapeXml(nodeId)}.${escapeXml(port.name)}:${dir}`;
|
|
50857
50691
|
const portLabel = port.label;
|
|
50858
|
-
const typeWidth = measureText(abbrev);
|
|
50859
50692
|
const labelWidth = measureText(portLabel);
|
|
50860
|
-
const pad2 =
|
|
50861
|
-
const
|
|
50862
|
-
const
|
|
50693
|
+
const pad2 = 6;
|
|
50694
|
+
const gap = 4;
|
|
50695
|
+
const abbrev = TYPE_ABBREVIATIONS[port.dataType] ?? port.dataType;
|
|
50696
|
+
const typeWidth = measureText(abbrev);
|
|
50697
|
+
const badgeWidth = pad2 + typeWidth + gap + labelWidth + pad2;
|
|
50863
50698
|
const badgeHeight = 16;
|
|
50864
50699
|
const badgeGap = 5;
|
|
50865
|
-
const rr = badgeHeight / 2;
|
|
50866
50700
|
const badgeX = isInput ? port.cx - PORT_RADIUS - badgeGap - badgeWidth : port.cx + PORT_RADIUS + badgeGap;
|
|
50867
50701
|
const badgeY = port.cy - badgeHeight / 2;
|
|
50868
50702
|
parts.push(` <g data-port-label="${portId}">`);
|
|
50869
|
-
parts.push(` <rect x="${badgeX}" y="${badgeY}" width="${badgeWidth}" height="${badgeHeight}" rx="
|
|
50703
|
+
parts.push(` <rect x="${badgeX}" y="${badgeY}" width="${badgeWidth}" height="${badgeHeight}" rx="3" fill="${theme.background}" stroke="${color}" stroke-width="1"/>`);
|
|
50870
50704
|
if (isInput) {
|
|
50871
50705
|
const typeX = badgeX + badgeWidth - pad2 - typeWidth / 2;
|
|
50872
|
-
const
|
|
50873
|
-
const nameX = divX - divGap;
|
|
50874
|
-
parts.push(` <line x1="${divX}" y1="${badgeY + 3}" x2="${divX}" y2="${badgeY + badgeHeight - 3}" stroke="${theme.labelBadgeBorder}" stroke-width="1"/>`);
|
|
50706
|
+
const nameX = typeX - typeWidth / 2 - gap;
|
|
50875
50707
|
parts.push(` <text class="port-label" x="${nameX}" y="${port.cy + 3.5}" text-anchor="end">${escapeXml(portLabel)}</text>`);
|
|
50876
50708
|
parts.push(` <text class="port-type-label" x="${typeX}" y="${port.cy + 3.5}" text-anchor="middle" fill="${color}">${escapeXml(abbrev)}</text>`);
|
|
50877
50709
|
} else {
|
|
50878
50710
|
const typeX = badgeX + pad2 + typeWidth / 2;
|
|
50879
|
-
const
|
|
50880
|
-
const nameX = divX + 1 + divGap;
|
|
50881
|
-
parts.push(` <line x1="${divX}" y1="${badgeY + 3}" x2="${divX}" y2="${badgeY + badgeHeight - 3}" stroke="${theme.labelBadgeBorder}" stroke-width="1"/>`);
|
|
50711
|
+
const nameX = typeX + typeWidth / 2 + gap;
|
|
50882
50712
|
parts.push(` <text class="port-type-label" x="${typeX}" y="${port.cy + 3.5}" text-anchor="middle" fill="${color}">${escapeXml(abbrev)}</text>`);
|
|
50883
50713
|
parts.push(` <text class="port-label" x="${nameX}" y="${port.cy + 3.5}" text-anchor="start">${escapeXml(portLabel)}</text>`);
|
|
50884
50714
|
}
|
|
@@ -50955,13 +50785,12 @@ body.node-active [data-source].dimmed,
|
|
|
50955
50785
|
body.port-active [data-source].dimmed { opacity: 0.1; }
|
|
50956
50786
|
body.port-hovered [data-source].dimmed { opacity: 0.25; }
|
|
50957
50787
|
|
|
50958
|
-
/* Port
|
|
50959
|
-
|
|
50960
|
-
circle[data-port-id]:hover { stroke-width: 3; filter: brightness(1.3); }
|
|
50788
|
+
/* Port indicators are interactive \u2014 expands to circle on hover (matches platform) */
|
|
50789
|
+
[data-port-id] { cursor: pointer; }
|
|
50961
50790
|
|
|
50962
50791
|
/* Port-click highlighting */
|
|
50963
50792
|
[data-source].highlighted { opacity: 1; }
|
|
50964
|
-
|
|
50793
|
+
[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor); }
|
|
50965
50794
|
|
|
50966
50795
|
/* Node selection glow */
|
|
50967
50796
|
@keyframes select-pop {
|
|
@@ -51166,7 +50995,7 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
51166
50995
|
<svg id="canvas" xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">
|
|
51167
50996
|
<defs>
|
|
51168
50997
|
<pattern id="viewer-dots" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
51169
|
-
<circle cx="10" cy="10" r="
|
|
50998
|
+
<circle cx="10" cy="10" r="0.75" fill="${dotColor}" opacity="0.4"/>
|
|
51170
50999
|
</pattern>
|
|
51171
51000
|
</defs>
|
|
51172
51001
|
<rect x="-100000" y="-100000" width="200000" height="200000" fill="${bg}" pointer-events="none"/>
|
|
@@ -51443,33 +51272,9 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
51443
51272
|
var MIN_SEG_LEN = 3, JOG_THRESHOLD = 10, ORTHO_THRESHOLD = 300;
|
|
51444
51273
|
var STUB_THRESHOLD = 500, STUB_LEN = 30;
|
|
51445
51274
|
|
|
51446
|
-
|
|
51447
|
-
var dn = Math.abs(ay - by);
|
|
51448
|
-
return [bx + (ux * dn) / Math.abs(uy), ay];
|
|
51449
|
-
}
|
|
51450
|
-
|
|
51275
|
+
// Straight-line fallback when orthogonal routing fails (matches platform)
|
|
51451
51276
|
function computeConnectionPath(sx, sy, tx, ty) {
|
|
51452
|
-
|
|
51453
|
-
var ax = sx + e, ay = sy + e, hx = tx - e, hy = ty - e;
|
|
51454
|
-
var ramp = Math.min(20, (hx - ax) / 10);
|
|
51455
|
-
var bx = ax + ramp, by = ay + e, gx = hx - ramp, gy = hy - e;
|
|
51456
|
-
var curveSizeX = Math.min(60, Math.abs(ax - hx) / 4);
|
|
51457
|
-
var curveSizeY = Math.min(60, Math.abs(ay - hy) / 4);
|
|
51458
|
-
var curveMag = Math.sqrt(curveSizeX * curveSizeX + curveSizeY * curveSizeY);
|
|
51459
|
-
var bgX = gx - bx, bgY = gy - by;
|
|
51460
|
-
var bgLen = Math.sqrt(bgX * bgX + bgY * bgY);
|
|
51461
|
-
var bgUx = bgX / bgLen, bgUy = bgY / bgLen;
|
|
51462
|
-
var dx = bx + bgUx * curveMag, dy = by + (bgUy * curveMag) / 2;
|
|
51463
|
-
var ex = gx - bgUx * curveMag, ey = gy - (bgUy * curveMag) / 2;
|
|
51464
|
-
var deX = ex - dx, deY = ey - dy;
|
|
51465
|
-
var deLen = Math.sqrt(deX * deX + deY * deY);
|
|
51466
|
-
var deUx = deX / deLen, deUy = deY / deLen;
|
|
51467
|
-
var c = quadCurveControl(bx, by, dx, dy, -deUx, -deUy);
|
|
51468
|
-
var f = quadCurveControl(gx, gy, ex, ey, deUx, deUy);
|
|
51469
|
-
return 'M ' + c[0] + ',' + c[1] + ' M ' + ax + ',' + ay +
|
|
51470
|
-
' L ' + bx + ',' + by + ' Q ' + c[0] + ',' + c[1] + ' ' + dx + ',' + dy +
|
|
51471
|
-
' L ' + ex + ',' + ey + ' Q ' + f[0] + ',' + f[1] + ' ' + gx + ',' + gy +
|
|
51472
|
-
' L ' + hx + ',' + hy;
|
|
51277
|
+
return 'M ' + sx + ',' + sy + ' L ' + tx + ',' + ty;
|
|
51473
51278
|
}
|
|
51474
51279
|
|
|
51475
51280
|
// ---- Orthogonal router (ported from orthogonal-router.ts) ----
|
|
@@ -51752,7 +51557,16 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
51752
51557
|
var portPositions = {};
|
|
51753
51558
|
content.querySelectorAll('[data-port-id]').forEach(function(el) {
|
|
51754
51559
|
var id = el.getAttribute('data-port-id');
|
|
51755
|
-
|
|
51560
|
+
// Ports may be circle (cx/cy) or rect (x/y/width/height) elements
|
|
51561
|
+
var cx, cy;
|
|
51562
|
+
if (el.tagName === 'circle') {
|
|
51563
|
+
cx = parseFloat(el.getAttribute('cx'));
|
|
51564
|
+
cy = parseFloat(el.getAttribute('cy'));
|
|
51565
|
+
} else {
|
|
51566
|
+
cx = parseFloat(el.getAttribute('x')) + parseFloat(el.getAttribute('width')) / 2;
|
|
51567
|
+
cy = parseFloat(el.getAttribute('y')) + parseFloat(el.getAttribute('height')) / 2;
|
|
51568
|
+
}
|
|
51569
|
+
portPositions[id] = { cx: cx, cy: cy };
|
|
51756
51570
|
});
|
|
51757
51571
|
|
|
51758
51572
|
// Extract node bounding boxes from SVG rect elements
|
|
@@ -51914,14 +51728,9 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
51914
51728
|
}
|
|
51915
51729
|
} else {
|
|
51916
51730
|
// Path mode: show path, hide stubs
|
|
51917
|
-
|
|
51918
|
-
var path;
|
|
51919
|
-
if (
|
|
51920
|
-
path = calcOrthogonalPath([sx, sy], [tx, ty], boxes, c.srcNode, c.tgtNode, c.srcIdx, c.tgtIdx, alloc);
|
|
51921
|
-
if (!path) path = computeConnectionPath(sx, sy, tx, ty);
|
|
51922
|
-
} else {
|
|
51923
|
-
path = computeConnectionPath(sx, sy, tx, ty);
|
|
51924
|
-
}
|
|
51731
|
+
// Always try orthogonal routing first (matches platform)
|
|
51732
|
+
var path = calcOrthogonalPath([sx, sy], [tx, ty], boxes, c.srcNode, c.tgtNode, c.srcIdx, c.tgtIdx, alloc);
|
|
51733
|
+
if (!path) path = computeConnectionPath(sx, sy, tx, ty);
|
|
51925
51734
|
c.el.setAttribute('d', path);
|
|
51926
51735
|
c.el.removeAttribute('display');
|
|
51927
51736
|
if (c.stubs) {
|
|
@@ -52204,14 +52013,79 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
52204
52013
|
});
|
|
52205
52014
|
});
|
|
52206
52015
|
|
|
52207
|
-
// Port hover:
|
|
52016
|
+
// Port hover: animated ring\u2192circle expansion (matches platform 0.12s ease-out)
|
|
52017
|
+
var OUTER_W = 6, OUTER_H = 18, OUTER_RX = 4;
|
|
52018
|
+
var HOVER_OUTER = 20, HOVER_OUTER_RX = 10;
|
|
52019
|
+
var HOVER_INNER = 14, HOVER_INNER_RX = 7;
|
|
52020
|
+
var PORT_ANIM_MS = 120; // matches platform transition duration
|
|
52021
|
+
|
|
52022
|
+
// Tween an SVG rect from current attrs to target attrs
|
|
52023
|
+
function tweenRect(el, target, duration, onDone) {
|
|
52024
|
+
if (!el) { if (onDone) onDone(); return; }
|
|
52025
|
+
var start = {
|
|
52026
|
+
x: parseFloat(el.getAttribute('x')),
|
|
52027
|
+
y: parseFloat(el.getAttribute('y')),
|
|
52028
|
+
w: parseFloat(el.getAttribute('width')),
|
|
52029
|
+
h: parseFloat(el.getAttribute('height')),
|
|
52030
|
+
rx: parseFloat(el.getAttribute('rx'))
|
|
52031
|
+
};
|
|
52032
|
+
var t0 = null;
|
|
52033
|
+
var frameId = el.__tweenFrame;
|
|
52034
|
+
if (frameId) cancelAnimationFrame(frameId);
|
|
52035
|
+
function step(ts) {
|
|
52036
|
+
if (!t0) t0 = ts;
|
|
52037
|
+
var p = Math.min((ts - t0) / duration, 1);
|
|
52038
|
+
// ease-out: cubic
|
|
52039
|
+
var e = 1 - Math.pow(1 - p, 3);
|
|
52040
|
+
el.setAttribute('x', String(start.x + (target.x - start.x) * e));
|
|
52041
|
+
el.setAttribute('y', String(start.y + (target.y - start.y) * e));
|
|
52042
|
+
el.setAttribute('width', String(start.w + (target.w - start.w) * e));
|
|
52043
|
+
el.setAttribute('height', String(start.h + (target.h - start.h) * e));
|
|
52044
|
+
el.setAttribute('rx', String(start.rx + (target.rx - start.rx) * e));
|
|
52045
|
+
if (p < 1) {
|
|
52046
|
+
el.__tweenFrame = requestAnimationFrame(step);
|
|
52047
|
+
} else {
|
|
52048
|
+
el.__tweenFrame = null;
|
|
52049
|
+
if (onDone) onDone();
|
|
52050
|
+
}
|
|
52051
|
+
}
|
|
52052
|
+
el.__tweenFrame = requestAnimationFrame(step);
|
|
52053
|
+
}
|
|
52054
|
+
|
|
52208
52055
|
content.querySelectorAll('[data-port-id]').forEach(function(portEl) {
|
|
52209
52056
|
var portId = portEl.getAttribute('data-port-id');
|
|
52210
52057
|
var nodeId = portId.split('.')[0];
|
|
52211
52058
|
var peers = (portConnections[portId] || []).concat(portId);
|
|
52212
52059
|
|
|
52060
|
+
var origX = parseFloat(portEl.getAttribute('x'));
|
|
52061
|
+
var origY = parseFloat(portEl.getAttribute('y'));
|
|
52062
|
+
var innerBar = portEl.nextElementSibling;
|
|
52063
|
+
var hasInner = innerBar && innerBar.getAttribute('pointer-events') === 'none';
|
|
52064
|
+
var innerOrig = hasInner ? {
|
|
52065
|
+
x: parseFloat(innerBar.getAttribute('x')),
|
|
52066
|
+
y: parseFloat(innerBar.getAttribute('y')),
|
|
52067
|
+
w: parseFloat(innerBar.getAttribute('width')),
|
|
52068
|
+
h: parseFloat(innerBar.getAttribute('height')),
|
|
52069
|
+
rx: parseFloat(innerBar.getAttribute('rx'))
|
|
52070
|
+
} : null;
|
|
52071
|
+
|
|
52072
|
+
var cx = origX + OUTER_W / 2;
|
|
52073
|
+
var cy = origY + OUTER_H / 2;
|
|
52074
|
+
|
|
52213
52075
|
portEl.addEventListener('mouseenter', function() {
|
|
52214
52076
|
hoveredPort = portId;
|
|
52077
|
+
if (portEl.tagName === 'rect') {
|
|
52078
|
+
tweenRect(portEl, {
|
|
52079
|
+
x: cx - HOVER_OUTER / 2, y: cy - HOVER_OUTER / 2,
|
|
52080
|
+
w: HOVER_OUTER, h: HOVER_OUTER, rx: HOVER_OUTER_RX
|
|
52081
|
+
}, PORT_ANIM_MS);
|
|
52082
|
+
if (hasInner) {
|
|
52083
|
+
tweenRect(innerBar, {
|
|
52084
|
+
x: cx - HOVER_INNER / 2, y: cy - HOVER_INNER / 2,
|
|
52085
|
+
w: HOVER_INNER, h: HOVER_INNER, rx: HOVER_INNER_RX
|
|
52086
|
+
}, PORT_ANIM_MS);
|
|
52087
|
+
}
|
|
52088
|
+
}
|
|
52215
52089
|
batchLabelChanges(function() {
|
|
52216
52090
|
hideLabelsFor(nodeId);
|
|
52217
52091
|
peers.forEach(showLabel);
|
|
@@ -52228,6 +52102,18 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
52228
52102
|
});
|
|
52229
52103
|
portEl.addEventListener('mouseleave', function() {
|
|
52230
52104
|
hoveredPort = null;
|
|
52105
|
+
if (portEl.tagName === 'rect') {
|
|
52106
|
+
tweenRect(portEl, {
|
|
52107
|
+
x: origX, y: origY,
|
|
52108
|
+
w: OUTER_W, h: OUTER_H, rx: OUTER_RX
|
|
52109
|
+
}, PORT_ANIM_MS);
|
|
52110
|
+
if (hasInner) {
|
|
52111
|
+
tweenRect(innerBar, {
|
|
52112
|
+
x: innerOrig.x, y: innerOrig.y,
|
|
52113
|
+
w: innerOrig.w, h: innerOrig.h, rx: innerOrig.rx
|
|
52114
|
+
}, PORT_ANIM_MS);
|
|
52115
|
+
}
|
|
52116
|
+
}
|
|
52231
52117
|
// Defer so if entering another port, its mouseenter sets hoveredPort first
|
|
52232
52118
|
var myPeers = peers, myNodeId = nodeId;
|
|
52233
52119
|
Promise.resolve().then(function() {
|
|
@@ -52272,7 +52158,7 @@ circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor);
|
|
|
52272
52158
|
if (!selectedPortId) return;
|
|
52273
52159
|
selectedPortId = null;
|
|
52274
52160
|
document.body.classList.remove('port-active');
|
|
52275
|
-
content.querySelectorAll('
|
|
52161
|
+
content.querySelectorAll('.port-selected').forEach(function(c) {
|
|
52276
52162
|
c.classList.remove('port-selected');
|
|
52277
52163
|
});
|
|
52278
52164
|
content.querySelectorAll('[data-source].dimmed, [data-source].highlighted').forEach(function(p) {
|
|
@@ -52697,7 +52583,7 @@ async function diagramCommand(input, options = {}) {
|
|
|
52697
52583
|
if (ASCII_FORMATS.has(format)) {
|
|
52698
52584
|
result = fileToASCII(filePath, { ...diagramOptions, format });
|
|
52699
52585
|
} else if (format === "html") {
|
|
52700
|
-
result = fileToHTML(filePath, diagramOptions);
|
|
52586
|
+
result = fileToHTML(filePath, { ...diagramOptions, format });
|
|
52701
52587
|
} else {
|
|
52702
52588
|
result = fileToSVG(filePath, diagramOptions);
|
|
52703
52589
|
}
|
|
@@ -89256,7 +89142,7 @@ function parseIntStrict(value) {
|
|
|
89256
89142
|
// src/cli/index.ts
|
|
89257
89143
|
init_logger();
|
|
89258
89144
|
init_error_utils();
|
|
89259
|
-
var version2 = true ? "0.33.
|
|
89145
|
+
var version2 = true ? "0.33.2" : "0.0.0-dev";
|
|
89260
89146
|
var program2 = new Command();
|
|
89261
89147
|
program2.name("fw").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
|
|
89262
89148
|
logger.banner(version2);
|