@crazyhappyone/auto-graph 0.1.1 → 0.1.3
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 +6 -1
- package/README.zh-CN.md +6 -1
- package/dist/cli/index.cjs +293 -21
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +293 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +293 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +293 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,7 +70,12 @@ if (parsed.value === undefined) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const normalized = normalizeDiagramDsl(parsed.value);
|
|
73
|
-
const coordinated = solveDiagram(normalized.diagram
|
|
73
|
+
const coordinated = solveDiagram(normalized.diagram, {
|
|
74
|
+
routeKind: "obstacle-avoiding",
|
|
75
|
+
maxRoutingAttempts: 8,
|
|
76
|
+
labelPlacement: "beside",
|
|
77
|
+
labelOffset: 16,
|
|
78
|
+
});
|
|
74
79
|
|
|
75
80
|
const svg = exportSvg(coordinated, { title: "Architecture" });
|
|
76
81
|
const excalidraw = exportExcalidraw(coordinated);
|
package/README.zh-CN.md
CHANGED
|
@@ -70,7 +70,12 @@ if (parsed.value === undefined) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const normalized = normalizeDiagramDsl(parsed.value);
|
|
73
|
-
const coordinated = solveDiagram(normalized.diagram
|
|
73
|
+
const coordinated = solveDiagram(normalized.diagram, {
|
|
74
|
+
routeKind: "obstacle-avoiding",
|
|
75
|
+
maxRoutingAttempts: 8,
|
|
76
|
+
labelPlacement: "beside",
|
|
77
|
+
labelOffset: 16,
|
|
78
|
+
});
|
|
74
79
|
|
|
75
80
|
const svg = exportSvg(coordinated, { title: "Architecture" });
|
|
76
81
|
const excalidraw = exportExcalidraw(coordinated);
|
package/dist/cli/index.cjs
CHANGED
|
@@ -3259,6 +3259,7 @@ function routeEdge(input) {
|
|
|
3259
3259
|
const diagnostics = [];
|
|
3260
3260
|
const softObstacles = input.obstacles ?? [];
|
|
3261
3261
|
const hardObstacles = input.hardObstacles ?? [];
|
|
3262
|
+
const maxAttempts = input.maxRoutingAttempts ?? 5;
|
|
3262
3263
|
const defaultAnchors = defaultAnchorsForGeometry(
|
|
3263
3264
|
input.source.box,
|
|
3264
3265
|
input.target.box,
|
|
@@ -3354,6 +3355,51 @@ function routeEdge(input) {
|
|
|
3354
3355
|
)
|
|
3355
3356
|
);
|
|
3356
3357
|
if (hardClearCandidate !== void 0) {
|
|
3358
|
+
let bestPoints2 = hardClearCandidate.points;
|
|
3359
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3360
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3361
|
+
for (const candidate of candidateRoutes) {
|
|
3362
|
+
if (routeCrossesBoxes(candidate.points, hardObstacles) || routeIntersectsEndpointInteriors(
|
|
3363
|
+
candidate.points,
|
|
3364
|
+
candidate.endpointObstacles
|
|
3365
|
+
)) {
|
|
3366
|
+
continue;
|
|
3367
|
+
}
|
|
3368
|
+
const rerouted2 = greedyRerouteAroundObstacles(
|
|
3369
|
+
candidate.points,
|
|
3370
|
+
allObstacles,
|
|
3371
|
+
maxAttempts
|
|
3372
|
+
);
|
|
3373
|
+
if (!routeCrossesBoxes(rerouted2, allObstacles) && !routeIntersectsEndpointInteriors(
|
|
3374
|
+
rerouted2,
|
|
3375
|
+
candidate.endpointObstacles
|
|
3376
|
+
)) {
|
|
3377
|
+
return {
|
|
3378
|
+
points: finalizeRoute(
|
|
3379
|
+
rerouted2,
|
|
3380
|
+
softObstacles,
|
|
3381
|
+
hardObstacles,
|
|
3382
|
+
diagnostics
|
|
3383
|
+
),
|
|
3384
|
+
diagnostics
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3389
|
+
bestPoints2,
|
|
3390
|
+
allObstacles,
|
|
3391
|
+
Math.min(maxAttempts, 3)
|
|
3392
|
+
);
|
|
3393
|
+
const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
|
|
3394
|
+
rerouted,
|
|
3395
|
+
hardClearCandidate.endpointObstacles
|
|
3396
|
+
);
|
|
3397
|
+
if (reroutedAvoidsEndpointInteriors) {
|
|
3398
|
+
if (routeCrossesBoxes(rerouted, hardObstacles) && !routeCrossesBoxes(bestPoints2, hardObstacles)) ; else {
|
|
3399
|
+
bestPoints2 = rerouted;
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3357
3403
|
diagnostics.push({
|
|
3358
3404
|
severity: "warning",
|
|
3359
3405
|
code: "routing.obstacle.unavoidable",
|
|
@@ -3361,7 +3407,7 @@ function routeEdge(input) {
|
|
|
3361
3407
|
});
|
|
3362
3408
|
return {
|
|
3363
3409
|
points: finalizeRoute(
|
|
3364
|
-
|
|
3410
|
+
bestPoints2,
|
|
3365
3411
|
softObstacles,
|
|
3366
3412
|
hardObstacles,
|
|
3367
3413
|
diagnostics
|
|
@@ -3370,6 +3416,33 @@ function routeEdge(input) {
|
|
|
3370
3416
|
};
|
|
3371
3417
|
}
|
|
3372
3418
|
if (hardObstacles.length > 0) {
|
|
3419
|
+
let bestPoints2 = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
|
|
3420
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3421
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3422
|
+
for (const candidate of candidateRoutes) {
|
|
3423
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3424
|
+
candidate.points,
|
|
3425
|
+
allObstacles,
|
|
3426
|
+
maxAttempts
|
|
3427
|
+
);
|
|
3428
|
+
if (!routeCrossesBoxes(rerouted, allObstacles)) {
|
|
3429
|
+
return {
|
|
3430
|
+
points: finalizeRoute(
|
|
3431
|
+
rerouted,
|
|
3432
|
+
softObstacles,
|
|
3433
|
+
hardObstacles,
|
|
3434
|
+
diagnostics
|
|
3435
|
+
),
|
|
3436
|
+
diagnostics
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
bestPoints2 = greedyRerouteAroundObstacles(
|
|
3441
|
+
candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
|
|
3442
|
+
allObstacles,
|
|
3443
|
+
maxAttempts
|
|
3444
|
+
);
|
|
3445
|
+
}
|
|
3373
3446
|
diagnostics.push({
|
|
3374
3447
|
severity: "error",
|
|
3375
3448
|
code: "routing.evidence.crossing_forbidden",
|
|
@@ -3377,7 +3450,7 @@ function routeEdge(input) {
|
|
|
3377
3450
|
});
|
|
3378
3451
|
return {
|
|
3379
3452
|
points: finalizeRoute(
|
|
3380
|
-
|
|
3453
|
+
bestPoints2,
|
|
3381
3454
|
softObstacles,
|
|
3382
3455
|
hardObstacles,
|
|
3383
3456
|
diagnostics
|
|
@@ -3385,6 +3458,33 @@ function routeEdge(input) {
|
|
|
3385
3458
|
diagnostics
|
|
3386
3459
|
};
|
|
3387
3460
|
}
|
|
3461
|
+
let bestPoints = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
|
|
3462
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3463
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3464
|
+
for (const candidate of candidateRoutes) {
|
|
3465
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3466
|
+
candidate.points,
|
|
3467
|
+
allObstacles,
|
|
3468
|
+
maxAttempts
|
|
3469
|
+
);
|
|
3470
|
+
if (!routeCrossesBoxes(rerouted, allObstacles)) {
|
|
3471
|
+
return {
|
|
3472
|
+
points: finalizeRoute(
|
|
3473
|
+
rerouted,
|
|
3474
|
+
softObstacles,
|
|
3475
|
+
hardObstacles,
|
|
3476
|
+
diagnostics
|
|
3477
|
+
),
|
|
3478
|
+
diagnostics
|
|
3479
|
+
};
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
bestPoints = greedyRerouteAroundObstacles(
|
|
3483
|
+
candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
|
|
3484
|
+
allObstacles,
|
|
3485
|
+
maxAttempts
|
|
3486
|
+
);
|
|
3487
|
+
}
|
|
3388
3488
|
diagnostics.push({
|
|
3389
3489
|
severity: "warning",
|
|
3390
3490
|
code: "routing.obstacle.unavoidable",
|
|
@@ -3392,7 +3492,7 @@ function routeEdge(input) {
|
|
|
3392
3492
|
});
|
|
3393
3493
|
return {
|
|
3394
3494
|
points: finalizeRoute(
|
|
3395
|
-
|
|
3495
|
+
bestPoints,
|
|
3396
3496
|
softObstacles,
|
|
3397
3497
|
hardObstacles,
|
|
3398
3498
|
diagnostics
|
|
@@ -3550,6 +3650,70 @@ function insetBox(box, margin) {
|
|
|
3550
3650
|
height: box.height - margin * 2
|
|
3551
3651
|
};
|
|
3552
3652
|
}
|
|
3653
|
+
function greedyRerouteAroundObstacles(points, obstacles, maxIterations) {
|
|
3654
|
+
let current = [...points];
|
|
3655
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
3656
|
+
const improved = pushRouteAwayFromObstacles(current, obstacles);
|
|
3657
|
+
if (improved === null) {
|
|
3658
|
+
break;
|
|
3659
|
+
}
|
|
3660
|
+
current = improved;
|
|
3661
|
+
if (!routeCrossesBoxes(current, obstacles)) {
|
|
3662
|
+
break;
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
return current;
|
|
3666
|
+
}
|
|
3667
|
+
function pushRouteAwayFromObstacles(points, obstacles) {
|
|
3668
|
+
const result = [];
|
|
3669
|
+
let improved = false;
|
|
3670
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
3671
|
+
const a = points[i];
|
|
3672
|
+
const b = points[i + 1];
|
|
3673
|
+
if (a === void 0 || b === void 0) {
|
|
3674
|
+
result.push(a ?? b ?? { x: 0, y: 0 });
|
|
3675
|
+
continue;
|
|
3676
|
+
}
|
|
3677
|
+
result.push(a);
|
|
3678
|
+
const intersectors = obstacles.filter(
|
|
3679
|
+
(obs) => segmentIntersectsBox(a, b, obs)
|
|
3680
|
+
);
|
|
3681
|
+
if (intersectors.length === 0) {
|
|
3682
|
+
continue;
|
|
3683
|
+
}
|
|
3684
|
+
const mx = (a.x + b.x) / 2;
|
|
3685
|
+
const my = (a.y + b.y) / 2;
|
|
3686
|
+
const isHorizontal = a.y === b.y;
|
|
3687
|
+
const margin = 12;
|
|
3688
|
+
let bestWaypoint = null;
|
|
3689
|
+
let bestDist = Infinity;
|
|
3690
|
+
for (const obs of intersectors) {
|
|
3691
|
+
const candidates = isHorizontal ? [
|
|
3692
|
+
{ x: mx, y: obs.y - margin },
|
|
3693
|
+
{ x: mx, y: obs.y + obs.height + margin }
|
|
3694
|
+
] : [
|
|
3695
|
+
{ x: obs.x - margin, y: my },
|
|
3696
|
+
{ x: obs.x + obs.width + margin, y: my }
|
|
3697
|
+
];
|
|
3698
|
+
for (const wp of candidates) {
|
|
3699
|
+
const dist = Math.hypot(wp.x - mx, wp.y - my);
|
|
3700
|
+
if (dist < bestDist) {
|
|
3701
|
+
bestDist = dist;
|
|
3702
|
+
bestWaypoint = wp;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
if (bestWaypoint !== null) {
|
|
3707
|
+
result.push(bestWaypoint);
|
|
3708
|
+
improved = true;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
const last = points[points.length - 1];
|
|
3712
|
+
if (last !== void 0) {
|
|
3713
|
+
result.push(last);
|
|
3714
|
+
}
|
|
3715
|
+
return improved ? result : null;
|
|
3716
|
+
}
|
|
3553
3717
|
function fallbackRoute(input, defaultAnchors) {
|
|
3554
3718
|
return [
|
|
3555
3719
|
getEdgePort(
|
|
@@ -4136,7 +4300,9 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4136
4300
|
styledEdges,
|
|
4137
4301
|
nodeGeometryById,
|
|
4138
4302
|
coordinatedNodes,
|
|
4139
|
-
[...nodeGeometryById.values()].map(
|
|
4303
|
+
[...nodeGeometryById.values()].map(
|
|
4304
|
+
(geometry) => options.routingGutter === void 0 ? geometry.obstacleBox : expandBox(geometry.obstacleBox, options.routingGutter)
|
|
4305
|
+
),
|
|
4140
4306
|
[...softObstacles, ...titleBarObstacles],
|
|
4141
4307
|
routingTextObstacles,
|
|
4142
4308
|
hardObstacles,
|
|
@@ -4151,7 +4317,9 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4151
4317
|
...baseTextAnnotations.map((annotation) => annotation.box),
|
|
4152
4318
|
...frameTextAnnotation.map((annotation) => annotation.box)
|
|
4153
4319
|
],
|
|
4154
|
-
options.textMeasurer
|
|
4320
|
+
options.textMeasurer,
|
|
4321
|
+
options.labelPlacement,
|
|
4322
|
+
options.labelOffset
|
|
4155
4323
|
);
|
|
4156
4324
|
const textAnnotations = [
|
|
4157
4325
|
...baseTextAnnotations,
|
|
@@ -6089,7 +6257,8 @@ function coordinateBaseTextAnnotations(input) {
|
|
|
6089
6257
|
}
|
|
6090
6258
|
return annotations;
|
|
6091
6259
|
}
|
|
6092
|
-
function coordinateEdgeTextAnnotations(edges, obstacleBoxes, textMeasurer) {
|
|
6260
|
+
function coordinateEdgeTextAnnotations(edges, obstacleBoxes, textMeasurer, labelPlacement, labelOffset3) {
|
|
6261
|
+
const labelBaseOffset = labelPlacement === "beside" ? labelOffset3 ?? 16 : 10;
|
|
6093
6262
|
const measurer = textMeasurer ?? createDefaultTextMeasurer();
|
|
6094
6263
|
const annotations = [];
|
|
6095
6264
|
const placedLabelBoxes = [];
|
|
@@ -6116,7 +6285,8 @@ function coordinateEdgeTextAnnotations(edges, obstacleBoxes, textMeasurer) {
|
|
|
6116
6285
|
layout2,
|
|
6117
6286
|
edges,
|
|
6118
6287
|
obstacleBoxes,
|
|
6119
|
-
placedLabelBoxes
|
|
6288
|
+
placedLabelBoxes,
|
|
6289
|
+
labelBaseOffset
|
|
6120
6290
|
);
|
|
6121
6291
|
placedLabelBoxes.push({
|
|
6122
6292
|
x: center.x - layout2.box.width / 2,
|
|
@@ -6400,8 +6570,8 @@ function fallbackLabelLayout(text) {
|
|
|
6400
6570
|
diagnostics: []
|
|
6401
6571
|
};
|
|
6402
6572
|
}
|
|
6403
|
-
function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes) {
|
|
6404
|
-
const placement = labelPlacementOnPolyline2(edge.points);
|
|
6573
|
+
function edgeLabelAnchor(edge, layout2, edges, obstacleBoxes, placedLabelBoxes, baseOffset = 10) {
|
|
6574
|
+
const placement = labelPlacementOnPolyline2(edge.points, baseOffset);
|
|
6405
6575
|
if (placement === void 0) {
|
|
6406
6576
|
return { x: 0, y: 0 };
|
|
6407
6577
|
}
|
|
@@ -6456,9 +6626,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
6456
6626
|
{ x: placement.x, y: placement.y + offset }
|
|
6457
6627
|
);
|
|
6458
6628
|
}
|
|
6459
|
-
|
|
6460
|
-
}
|
|
6461
|
-
if (segment.start.x === segment.end.x) {
|
|
6629
|
+
} else if (segment.start.x === segment.end.x) {
|
|
6462
6630
|
const needed = layout2.box.width / 2 + EDGE_LABEL_CLEARANCE;
|
|
6463
6631
|
const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
|
|
6464
6632
|
for (let step = 1; step <= maxSteps; step += 1) {
|
|
@@ -6468,14 +6636,90 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
6468
6636
|
{ x: placement.x - offset, y: placement.y }
|
|
6469
6637
|
);
|
|
6470
6638
|
}
|
|
6471
|
-
|
|
6639
|
+
} else {
|
|
6640
|
+
const dx = segment.end.x - segment.start.x;
|
|
6641
|
+
const dy = segment.end.y - segment.start.y;
|
|
6642
|
+
const segLen = Math.hypot(dx, dy);
|
|
6643
|
+
if (segLen > 0) {
|
|
6644
|
+
const nx = -dy / segLen;
|
|
6645
|
+
const ny = dx / segLen;
|
|
6646
|
+
const needed = (Math.abs(nx) * layout2.box.width + Math.abs(ny) * layout2.box.height) / 2 + EDGE_LABEL_CLEARANCE;
|
|
6647
|
+
const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
|
|
6648
|
+
for (let step = 1; step <= maxSteps; step += 1) {
|
|
6649
|
+
const offset = EDGE_LABEL_CLEARANCE * step;
|
|
6650
|
+
candidates.push(
|
|
6651
|
+
{ x: placement.x + nx * offset, y: placement.y + ny * offset },
|
|
6652
|
+
{ x: placement.x - nx * offset, y: placement.y - ny * offset }
|
|
6653
|
+
);
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6657
|
+
const totalLen = points.reduce((sum, p, idx) => {
|
|
6658
|
+
if (idx === 0) return 0;
|
|
6659
|
+
const prev = points[idx - 1];
|
|
6660
|
+
return sum + Math.hypot((p?.x ?? 0) - (prev?.x ?? 0), (p?.y ?? 0) - (prev?.y ?? 0));
|
|
6661
|
+
}, 0);
|
|
6662
|
+
if (totalLen > 200) {
|
|
6663
|
+
for (const ratio of [0.25, 0.75]) {
|
|
6664
|
+
const qp = labelPlacementAtRatio(points, ratio, totalLen);
|
|
6665
|
+
if (qp !== void 0) {
|
|
6666
|
+
candidates.push(qp);
|
|
6667
|
+
const qTargetDist = totalLen * ratio;
|
|
6668
|
+
let qTravelled = 0;
|
|
6669
|
+
let seg;
|
|
6670
|
+
for (let si = 1; si < points.length; si++) {
|
|
6671
|
+
const sp = points[si - 1];
|
|
6672
|
+
const sc = points[si];
|
|
6673
|
+
if (sp === void 0 || sc === void 0) continue;
|
|
6674
|
+
const sl = Math.hypot(sc.x - sp.x, sc.y - sp.y);
|
|
6675
|
+
if (sl <= 0) continue;
|
|
6676
|
+
if (qTravelled + sl >= qTargetDist) {
|
|
6677
|
+
seg = { start: sp, end: sc, length: sl };
|
|
6678
|
+
break;
|
|
6679
|
+
}
|
|
6680
|
+
qTravelled += sl;
|
|
6681
|
+
}
|
|
6682
|
+
if (seg !== void 0) {
|
|
6683
|
+
const segLen = Math.hypot(
|
|
6684
|
+
seg.end.x - seg.start.x,
|
|
6685
|
+
seg.end.y - seg.start.y
|
|
6686
|
+
);
|
|
6687
|
+
const qpNeeded = seg.start.y === seg.end.y ? layout2.box.height / 2 + EDGE_LABEL_CLEARANCE : seg.start.x === seg.end.x ? layout2.box.width / 2 + EDGE_LABEL_CLEARANCE : (Math.abs(seg.start.y - seg.end.y) * layout2.box.width + Math.abs(seg.end.x - seg.start.x) * layout2.box.height) / (2 * segLen) + EDGE_LABEL_CLEARANCE;
|
|
6688
|
+
const qpMaxSteps = Math.max(
|
|
6689
|
+
12,
|
|
6690
|
+
Math.ceil(qpNeeded / EDGE_LABEL_CLEARANCE)
|
|
6691
|
+
);
|
|
6692
|
+
for (let step = 1; step <= qpMaxSteps; step += 1) {
|
|
6693
|
+
const offset = EDGE_LABEL_CLEARANCE * step;
|
|
6694
|
+
if (seg.start.y === seg.end.y) {
|
|
6695
|
+
candidates.push(
|
|
6696
|
+
{ x: qp.x, y: qp.y - offset },
|
|
6697
|
+
{ x: qp.x, y: qp.y + offset }
|
|
6698
|
+
);
|
|
6699
|
+
} else if (seg.start.x === seg.end.x) {
|
|
6700
|
+
candidates.push(
|
|
6701
|
+
{ x: qp.x - offset, y: qp.y },
|
|
6702
|
+
{ x: qp.x + offset, y: qp.y }
|
|
6703
|
+
);
|
|
6704
|
+
} else {
|
|
6705
|
+
const nx = -(seg.end.y - seg.start.y) / segLen;
|
|
6706
|
+
const ny = (seg.end.x - seg.start.x) / segLen;
|
|
6707
|
+
candidates.push(
|
|
6708
|
+
{ x: qp.x + nx * offset, y: qp.y + ny * offset },
|
|
6709
|
+
{ x: qp.x - nx * offset, y: qp.y - ny * offset }
|
|
6710
|
+
);
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
}
|
|
6472
6716
|
}
|
|
6473
6717
|
return candidates;
|
|
6474
6718
|
}
|
|
6475
|
-
function labelPlacementOnPolyline2(points) {
|
|
6476
|
-
return labelSegmentOnPolyline(points)?.placement;
|
|
6719
|
+
function labelPlacementOnPolyline2(points, baseOffset = 10) {
|
|
6720
|
+
return labelSegmentOnPolyline(points, baseOffset)?.placement;
|
|
6477
6721
|
}
|
|
6478
|
-
function labelSegmentOnPolyline(points) {
|
|
6722
|
+
function labelSegmentOnPolyline(points, baseOffset = 10) {
|
|
6479
6723
|
const segments = nonZeroSegments2(points);
|
|
6480
6724
|
const totalLength = segments.reduce(
|
|
6481
6725
|
(sum, segment) => sum + segment.length,
|
|
@@ -6490,7 +6734,7 @@ function labelSegmentOnPolyline(points) {
|
|
|
6490
6734
|
const ratio = remaining / segment.length;
|
|
6491
6735
|
const x = segment.start.x + (segment.end.x - segment.start.x) * ratio;
|
|
6492
6736
|
const y = segment.start.y + (segment.end.y - segment.start.y) * ratio;
|
|
6493
|
-
const offset2 = labelOffset2(segment);
|
|
6737
|
+
const offset2 = labelOffset2(segment, baseOffset);
|
|
6494
6738
|
return {
|
|
6495
6739
|
start: segment.start,
|
|
6496
6740
|
end: segment.end,
|
|
@@ -6525,8 +6769,36 @@ function nonZeroSegments2(points) {
|
|
|
6525
6769
|
}
|
|
6526
6770
|
return segments;
|
|
6527
6771
|
}
|
|
6528
|
-
function
|
|
6529
|
-
|
|
6772
|
+
function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
6773
|
+
if (points.length < 2 || ratio < 0 || ratio > 1) {
|
|
6774
|
+
return void 0;
|
|
6775
|
+
}
|
|
6776
|
+
const targetDist = totalLength * ratio;
|
|
6777
|
+
let travelled = 0;
|
|
6778
|
+
for (let idx = 1; idx < points.length; idx++) {
|
|
6779
|
+
const prev = points[idx - 1];
|
|
6780
|
+
const curr = points[idx];
|
|
6781
|
+
if (prev === void 0 || curr === void 0) {
|
|
6782
|
+
continue;
|
|
6783
|
+
}
|
|
6784
|
+
const segLen = Math.hypot(curr.x - prev.x, curr.y - prev.y);
|
|
6785
|
+
if (segLen <= 0) {
|
|
6786
|
+
continue;
|
|
6787
|
+
}
|
|
6788
|
+
if (travelled + segLen >= targetDist) {
|
|
6789
|
+
const t = (targetDist - travelled) / segLen;
|
|
6790
|
+
const offset = labelOffset2({ start: prev, end: curr, length: segLen });
|
|
6791
|
+
return {
|
|
6792
|
+
x: prev.x + (curr.x - prev.x) * t + offset.x,
|
|
6793
|
+
y: prev.y + (curr.y - prev.y) * t + offset.y
|
|
6794
|
+
};
|
|
6795
|
+
}
|
|
6796
|
+
travelled += segLen;
|
|
6797
|
+
}
|
|
6798
|
+
return void 0;
|
|
6799
|
+
}
|
|
6800
|
+
function labelOffset2(segment, baseOffset = 10) {
|
|
6801
|
+
const offset = baseOffset;
|
|
6530
6802
|
const dx = segment.end.x - segment.start.x;
|
|
6531
6803
|
const dy = segment.end.y - segment.start.y;
|
|
6532
6804
|
return {
|
|
@@ -6638,7 +6910,7 @@ function isValidEdgeId(value) {
|
|
|
6638
6910
|
return value.length > 0 && EDGE_ID_PATTERN.test(value);
|
|
6639
6911
|
}
|
|
6640
6912
|
var directionSchema = zod.z.enum(["TB", "LR", "BT", "RL"]);
|
|
6641
|
-
var routeKindSchema = zod.z.enum(["orthogonal", "straight"]);
|
|
6913
|
+
var routeKindSchema = zod.z.enum(["orthogonal", "straight", "obstacle-avoiding"]);
|
|
6642
6914
|
var outputFormatSchema = zod.z.enum(["svg", "excalidraw"]);
|
|
6643
6915
|
var edgeStrokeStyleSchema = zod.z.enum(["solid", "dashed"]);
|
|
6644
6916
|
var edgeArrowheadSchema = zod.z.enum(["triangle", "hollowTriangle"]);
|
|
@@ -7237,7 +7509,7 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
7237
7509
|
return { diagnostics };
|
|
7238
7510
|
}
|
|
7239
7511
|
const solved = solveDiagram(normalized.diagram, {
|
|
7240
|
-
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal",
|
|
7512
|
+
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : normalized.diagram.metadata?.routeKind === "obstacle-avoiding" ? "obstacle-avoiding" : "orthogonal",
|
|
7241
7513
|
...solvePortShiftingOption(normalized.diagram.metadata?.portShifting),
|
|
7242
7514
|
...options.textMeasurer === void 0 ? {} : { textMeasurer: options.textMeasurer }
|
|
7243
7515
|
});
|