sketchmark 1.3.7 → 1.4.0
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 +21 -8
- package/dist/ast/types.d.ts +4 -0
- package/dist/ast/types.d.ts.map +1 -1
- package/dist/index.cjs +292 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +292 -42
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/renderer/canvas/index.d.ts.map +1 -1
- package/dist/renderer/shared.d.ts +16 -0
- package/dist/renderer/shared.d.ts.map +1 -1
- package/dist/renderer/svg/index.d.ts.map +1 -1
- package/dist/scene/index.d.ts +4 -2
- package/dist/scene/index.d.ts.map +1 -1
- package/dist/sketchmark.iife.js +292 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -436,17 +436,30 @@ a <--> b label="Sync"
|
|
|
436
436
|
a -- b # line, no arrow
|
|
437
437
|
a --- b # dashed line, no arrow
|
|
438
438
|
|
|
439
|
-
# With style overrides
|
|
440
|
-
a --> b label="HTTPS" stroke="#cc0000" stroke-width=2 color="#aa0000" font-size=10
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
439
|
+
# With style overrides
|
|
440
|
+
a --> b label="HTTPS" stroke="#cc0000" stroke-width=2 color="#aa0000" font-size=10
|
|
441
|
+
|
|
442
|
+
# Orthogonal / polyline routing
|
|
443
|
+
a --> b route=orthogonal
|
|
444
|
+
a --> b via=[160,40,160,180]
|
|
445
|
+
a --> b via="160,40 160,180" label="manual route"
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
`route=orthogonal` creates a right-angle elbow route between the edge endpoints.
|
|
449
|
+
`via` supplies manual waypoint coordinates as x,y pairs; it can use bracket
|
|
450
|
+
syntax or a quoted string. Waypoint coordinates are canvas-space coordinates
|
|
451
|
+
after layout, so `layout=absolute margin=0` is the easiest mode for precise
|
|
452
|
+
manual routing.
|
|
453
|
+
|
|
454
|
+
### Edge Style Properties
|
|
455
|
+
|
|
445
456
|
| Property | Description |
|
|
446
457
|
|----------|-------------|
|
|
447
458
|
| `label` | Text label floating on the edge |
|
|
448
459
|
| `label-dx` | Horizontal edge-label nudge to avoid crowded midpoints or crossings |
|
|
449
460
|
| `label-dy` | Vertical edge-label nudge to avoid crowded midpoints or crossings |
|
|
461
|
+
| `route` | `straight`, `orthogonal`, or `polyline`; `orthogonal` auto-generates elbow points |
|
|
462
|
+
| `via` | Manual polyline waypoints as x,y pairs, e.g. `via=[120,40,120,160]` |
|
|
450
463
|
| `stroke` | Line color |
|
|
451
464
|
| `stroke-width` | Line thickness |
|
|
452
465
|
| `color` | Label text color |
|
|
@@ -1069,8 +1082,8 @@ Nodes can also opt into authored absolute `x`/`y` positioning when their parent
|
|
|
1069
1082
|
| Edge labels | ✅ | |
|
|
1070
1083
|
| Edge color/stroke override | ✅ | |
|
|
1071
1084
|
| Self-loops | ❌ | |
|
|
1072
|
-
| Curved/bezier edges | ❌ | Straight
|
|
1073
|
-
| Waypoints / routing control |
|
|
1085
|
+
| Curved/bezier edges | ❌ | Straight and polyline segments only |
|
|
1086
|
+
| Waypoints / routing control | ✅ | Use `via=[x1,y1,x2,y2]` or `route=orthogonal` |
|
|
1074
1087
|
| Multiple edges between same nodes | ✅ | Stack visually |
|
|
1075
1088
|
| Edge from/to groups | ✅ | Uses group center |
|
|
1076
1089
|
|
package/dist/ast/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export type NodeShape = 'box' | 'circle' | 'diamond' | 'hexagon' | 'triangle' | 'cylinder' | 'parallelogram' | 'text' | 'image' | 'icon' | 'note' | 'line' | 'path';
|
|
2
2
|
export type EdgeConnector = '->' | '<-' | '<->' | '-->' | '<-->' | '---' | '--';
|
|
3
|
+
export type EdgeRoute = 'straight' | 'orthogonal' | 'polyline';
|
|
4
|
+
export type EdgePoint = [number, number];
|
|
3
5
|
export type EdgeAnchor = 'top' | 'right' | 'bottom' | 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
4
6
|
export type LayoutType = 'row' | 'column' | 'grid' | 'absolute';
|
|
5
7
|
export type AlignItems = 'start' | 'center' | 'end';
|
|
@@ -89,6 +91,8 @@ export interface ASTEdge {
|
|
|
89
91
|
labelDy?: number;
|
|
90
92
|
fromAnchor?: EdgeAnchor;
|
|
91
93
|
toAnchor?: EdgeAnchor;
|
|
94
|
+
route?: EdgeRoute;
|
|
95
|
+
via?: EdgePoint[];
|
|
92
96
|
dashed?: boolean;
|
|
93
97
|
bidirectional?: boolean;
|
|
94
98
|
theme?: string;
|
package/dist/ast/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ast/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ast/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -359,6 +359,39 @@ function isValueToken(t) {
|
|
|
359
359
|
function isPropKeyToken(t) {
|
|
360
360
|
return !!t && (t.type === "IDENT" || t.type === "KEYWORD");
|
|
361
361
|
}
|
|
362
|
+
const NUMBER_RE = /[-+]?(?:\d*\.\d+|\d+)(?:[eE][-+]?\d+)?/g;
|
|
363
|
+
function parseEdgeWaypoints(value, token) {
|
|
364
|
+
if (!value)
|
|
365
|
+
return undefined;
|
|
366
|
+
const numbers = (value.match(NUMBER_RE) ?? []).map((part) => Number(part));
|
|
367
|
+
if (!numbers.length)
|
|
368
|
+
return undefined;
|
|
369
|
+
if (numbers.length % 2 !== 0) {
|
|
370
|
+
throw new ParseError(`Edge via must contain x,y coordinate pairs`, token.line, token.col);
|
|
371
|
+
}
|
|
372
|
+
const points = [];
|
|
373
|
+
for (let index = 0; index < numbers.length; index += 2) {
|
|
374
|
+
const x = numbers[index];
|
|
375
|
+
const y = numbers[index + 1];
|
|
376
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
|
377
|
+
throw new ParseError(`Edge via contains a non-numeric coordinate`, token.line, token.col);
|
|
378
|
+
}
|
|
379
|
+
points.push([x, y]);
|
|
380
|
+
}
|
|
381
|
+
return points.length ? points : undefined;
|
|
382
|
+
}
|
|
383
|
+
function normalizeEdgeRoute(value, token) {
|
|
384
|
+
if (!value)
|
|
385
|
+
return undefined;
|
|
386
|
+
const normalized = value.toLowerCase();
|
|
387
|
+
if (normalized === "straight" || normalized === "polyline" || normalized === "orthogonal") {
|
|
388
|
+
return normalized;
|
|
389
|
+
}
|
|
390
|
+
if (normalized === "ortho" || normalized === "elbow") {
|
|
391
|
+
return "orthogonal";
|
|
392
|
+
}
|
|
393
|
+
throw new ParseError(`Unsupported edge route "${value}"; use straight, orthogonal, or polyline`, token.line, token.col);
|
|
394
|
+
}
|
|
362
395
|
function parse(src, options = {}) {
|
|
363
396
|
resetUid();
|
|
364
397
|
const preparedSource = applyPluginPreprocessors(src, options.plugins);
|
|
@@ -717,28 +750,63 @@ function parse(src, options = {}) {
|
|
|
717
750
|
height: props.height !== undefined ? parseFloat(props.height) : undefined,
|
|
718
751
|
};
|
|
719
752
|
}
|
|
720
|
-
function
|
|
721
|
-
const toTok = rest.shift();
|
|
722
|
-
if (!toTok)
|
|
723
|
-
throw new ParseError("Expected edge target", 0, 0);
|
|
753
|
+
function parseEdgeProps(toks) {
|
|
724
754
|
const props = {};
|
|
725
755
|
let j = 0;
|
|
726
|
-
while (j <
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
j += 3;
|
|
756
|
+
while (j < toks.length) {
|
|
757
|
+
const key = toks[j];
|
|
758
|
+
const eq = toks[j + 1];
|
|
759
|
+
if (!isPropKeyToken(key) || eq?.type !== "EQUALS") {
|
|
760
|
+
j++;
|
|
761
|
+
continue;
|
|
733
762
|
}
|
|
734
|
-
|
|
763
|
+
const value = toks[j + 2];
|
|
764
|
+
if (!value) {
|
|
735
765
|
j++;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
if (value.type === "LBRACKET") {
|
|
769
|
+
const parts = [];
|
|
770
|
+
let depth = 1;
|
|
771
|
+
j += 3;
|
|
772
|
+
while (j < toks.length && depth > 0) {
|
|
773
|
+
const tok = toks[j];
|
|
774
|
+
if (tok.type === "LBRACKET") {
|
|
775
|
+
depth++;
|
|
776
|
+
}
|
|
777
|
+
else if (tok.type === "RBRACKET") {
|
|
778
|
+
depth--;
|
|
779
|
+
if (depth === 0) {
|
|
780
|
+
j++;
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (depth > 0)
|
|
785
|
+
parts.push(tok.value);
|
|
786
|
+
j++;
|
|
787
|
+
}
|
|
788
|
+
if (depth > 0) {
|
|
789
|
+
throw new ParseError(`Unterminated edge property list; expected ']'`, key.line, key.col);
|
|
790
|
+
}
|
|
791
|
+
props[key.value] = parts.join(" ");
|
|
792
|
+
continue;
|
|
736
793
|
}
|
|
794
|
+
props[key.value] = value.value;
|
|
795
|
+
j += 3;
|
|
737
796
|
}
|
|
797
|
+
return props;
|
|
798
|
+
}
|
|
799
|
+
function parseEdge(fromId, connector, rest) {
|
|
800
|
+
const toTok = rest.shift();
|
|
801
|
+
if (!toTok)
|
|
802
|
+
throw new ParseError("Expected edge target", 0, 0);
|
|
803
|
+
const props = parseEdgeProps(rest);
|
|
738
804
|
const dashed = connector.includes("--") ||
|
|
739
805
|
connector.includes(".-") ||
|
|
740
806
|
connector.includes("-.");
|
|
741
807
|
const bidirectional = connector.includes("<") && connector.includes(">");
|
|
808
|
+
const via = parseEdgeWaypoints(props.via, toTok);
|
|
809
|
+
const route = normalizeEdgeRoute(props.route, toTok) ?? (via?.length ? "polyline" : undefined);
|
|
742
810
|
return {
|
|
743
811
|
kind: "edge",
|
|
744
812
|
id: uid("edge"),
|
|
@@ -750,6 +818,8 @@ function parse(src, options = {}) {
|
|
|
750
818
|
labelDy: props["label-dy"] !== undefined ? parseFloat(props["label-dy"]) : undefined,
|
|
751
819
|
fromAnchor: props["anchor-from"],
|
|
752
820
|
toAnchor: props["anchor-to"],
|
|
821
|
+
route,
|
|
822
|
+
via,
|
|
753
823
|
dashed,
|
|
754
824
|
bidirectional,
|
|
755
825
|
style: propsToStyle(props),
|
|
@@ -3683,6 +3753,8 @@ function buildSceneGraph(ast) {
|
|
|
3683
3753
|
labelDy: e.labelDy,
|
|
3684
3754
|
fromAnchor: e.fromAnchor,
|
|
3685
3755
|
toAnchor: e.toAnchor,
|
|
3756
|
+
route: e.route,
|
|
3757
|
+
via: e.via,
|
|
3686
3758
|
dashed: e.dashed ?? false,
|
|
3687
3759
|
bidirectional: e.bidirectional ?? false,
|
|
3688
3760
|
style: e.style ?? {},
|
|
@@ -4284,6 +4356,151 @@ function getConnPoint(src, dstCX, dstCY, anchor) {
|
|
|
4284
4356
|
return anchoredConnPoint(src, anchor, dstCX, dstCY);
|
|
4285
4357
|
}
|
|
4286
4358
|
// ── Group depth (for paint order) ────────────────────────────────────────
|
|
4359
|
+
function segmentLength(a, b) {
|
|
4360
|
+
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
4361
|
+
}
|
|
4362
|
+
function compactPolylinePoints(points) {
|
|
4363
|
+
const compacted = [];
|
|
4364
|
+
for (const point of points) {
|
|
4365
|
+
const previous = compacted[compacted.length - 1];
|
|
4366
|
+
if (!previous || segmentLength(previous, point) > 0.01) {
|
|
4367
|
+
compacted.push(point);
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
return compacted;
|
|
4371
|
+
}
|
|
4372
|
+
function polylinePathData(points) {
|
|
4373
|
+
return points
|
|
4374
|
+
.map(([x, y], index) => `${index === 0 ? "M" : "L"} ${x} ${y}`)
|
|
4375
|
+
.join(" ");
|
|
4376
|
+
}
|
|
4377
|
+
function polylineEndpointDirection(points, end) {
|
|
4378
|
+
const step = end === "start" ? 1 : -1;
|
|
4379
|
+
let index = end === "start" ? 0 : points.length - 1;
|
|
4380
|
+
while (index + step >= 0 && index + step < points.length) {
|
|
4381
|
+
const from = points[index];
|
|
4382
|
+
const to = points[index + step];
|
|
4383
|
+
const dx = to[0] - from[0];
|
|
4384
|
+
const dy = to[1] - from[1];
|
|
4385
|
+
const len = Math.hypot(dx, dy);
|
|
4386
|
+
if (len > 0.01) {
|
|
4387
|
+
return end === "start" ? [dx / len, dy / len] : [-dx / len, -dy / len];
|
|
4388
|
+
}
|
|
4389
|
+
index += step;
|
|
4390
|
+
}
|
|
4391
|
+
return [1, 0];
|
|
4392
|
+
}
|
|
4393
|
+
function insetPolylineEndpoints(points, arrowAt, inset) {
|
|
4394
|
+
const next = points.map((point) => [point[0], point[1]]);
|
|
4395
|
+
if (next.length < 2)
|
|
4396
|
+
return next;
|
|
4397
|
+
if (arrowAt === "start" || arrowAt === "both") {
|
|
4398
|
+
const [dx, dy] = polylineEndpointDirection(next, "start");
|
|
4399
|
+
next[0] = [next[0][0] + dx * inset, next[0][1] + dy * inset];
|
|
4400
|
+
}
|
|
4401
|
+
if (arrowAt === "end" || arrowAt === "both") {
|
|
4402
|
+
const [dx, dy] = polylineEndpointDirection(next, "end");
|
|
4403
|
+
const last = next.length - 1;
|
|
4404
|
+
next[last] = [next[last][0] - dx * inset, next[last][1] - dy * inset];
|
|
4405
|
+
}
|
|
4406
|
+
return compactPolylinePoints(next);
|
|
4407
|
+
}
|
|
4408
|
+
function polylineLabelPosition(points, offset, dx = 0, dy = 0) {
|
|
4409
|
+
if (points.length < 2) {
|
|
4410
|
+
const [x, y] = points[0] ?? [0, 0];
|
|
4411
|
+
return { x: x + dx, y: y + dy };
|
|
4412
|
+
}
|
|
4413
|
+
const lengths = points.slice(1).map((point, index) => segmentLength(points[index], point));
|
|
4414
|
+
const total = lengths.reduce((sum, value) => sum + value, 0);
|
|
4415
|
+
if (total <= 0.01) {
|
|
4416
|
+
const [x, y] = points[0];
|
|
4417
|
+
return { x: x + dx, y: y + dy };
|
|
4418
|
+
}
|
|
4419
|
+
let travelled = 0;
|
|
4420
|
+
const target = total / 2;
|
|
4421
|
+
for (let index = 0; index < lengths.length; index += 1) {
|
|
4422
|
+
const length = lengths[index];
|
|
4423
|
+
if (travelled + length >= target) {
|
|
4424
|
+
const from = points[index];
|
|
4425
|
+
const to = points[index + 1];
|
|
4426
|
+
const t = length > 0 ? (target - travelled) / length : 0;
|
|
4427
|
+
const ux = (to[0] - from[0]) / length;
|
|
4428
|
+
const uy = (to[1] - from[1]) / length;
|
|
4429
|
+
return {
|
|
4430
|
+
x: from[0] + (to[0] - from[0]) * t - uy * offset + dx,
|
|
4431
|
+
y: from[1] + (to[1] - from[1]) * t + ux * offset + dy,
|
|
4432
|
+
};
|
|
4433
|
+
}
|
|
4434
|
+
travelled += length;
|
|
4435
|
+
}
|
|
4436
|
+
const [x, y] = points[points.length - 1];
|
|
4437
|
+
return { x: x + dx, y: y + dy };
|
|
4438
|
+
}
|
|
4439
|
+
function rectBoundaryPoint(entity, point, direction) {
|
|
4440
|
+
const [px, py] = point;
|
|
4441
|
+
const [dx, dy] = direction;
|
|
4442
|
+
const candidates = [];
|
|
4443
|
+
const minX = entity.x;
|
|
4444
|
+
const maxX = entity.x + entity.w;
|
|
4445
|
+
const minY = entity.y;
|
|
4446
|
+
const maxY = entity.y + entity.h;
|
|
4447
|
+
const epsilon = 0.01;
|
|
4448
|
+
if (Math.abs(dx) > epsilon) {
|
|
4449
|
+
candidates.push((minX - px) / dx, (maxX - px) / dx);
|
|
4450
|
+
}
|
|
4451
|
+
if (Math.abs(dy) > epsilon) {
|
|
4452
|
+
candidates.push((minY - py) / dy, (maxY - py) / dy);
|
|
4453
|
+
}
|
|
4454
|
+
const valid = candidates
|
|
4455
|
+
.filter((t) => t >= -epsilon)
|
|
4456
|
+
.map((t) => ({
|
|
4457
|
+
t: Math.max(0, t),
|
|
4458
|
+
x: px + dx * t,
|
|
4459
|
+
y: py + dy * t,
|
|
4460
|
+
}))
|
|
4461
|
+
.filter(({ x, y }) => x >= minX - epsilon &&
|
|
4462
|
+
x <= maxX + epsilon &&
|
|
4463
|
+
y >= minY - epsilon &&
|
|
4464
|
+
y <= maxY + epsilon)
|
|
4465
|
+
.sort((a, b) => a.t - b.t);
|
|
4466
|
+
const hit = valid[0];
|
|
4467
|
+
return hit ? [hit.x, hit.y] : point;
|
|
4468
|
+
}
|
|
4469
|
+
function ellipseBoundaryPoint(entity, point, direction) {
|
|
4470
|
+
const [px, py] = point;
|
|
4471
|
+
const [dx, dy] = direction;
|
|
4472
|
+
const cx = entity.x + entity.w / 2;
|
|
4473
|
+
const cy = entity.y + entity.h / 2;
|
|
4474
|
+
const rx = Math.max(1, entity.w * 0.44);
|
|
4475
|
+
const ry = Math.max(1, entity.h * 0.44);
|
|
4476
|
+
const x0 = px - cx;
|
|
4477
|
+
const y0 = py - cy;
|
|
4478
|
+
const a = (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry);
|
|
4479
|
+
const b = 2 * ((x0 * dx) / (rx * rx) + (y0 * dy) / (ry * ry));
|
|
4480
|
+
const c = (x0 * x0) / (rx * rx) + (y0 * y0) / (ry * ry) - 1;
|
|
4481
|
+
const disc = b * b - 4 * a * c;
|
|
4482
|
+
if (a <= 0 || disc < 0)
|
|
4483
|
+
return point;
|
|
4484
|
+
const sqrt = Math.sqrt(disc);
|
|
4485
|
+
const hits = [(-b - sqrt) / (2 * a), (-b + sqrt) / (2 * a)]
|
|
4486
|
+
.filter((t) => t >= -0.01)
|
|
4487
|
+
.sort((left, right) => left - right);
|
|
4488
|
+
const t = Math.max(0, hits[0] ?? 0);
|
|
4489
|
+
return [px + dx * t, py + dy * t];
|
|
4490
|
+
}
|
|
4491
|
+
function polylineArrowTipPoint(entity, points, end) {
|
|
4492
|
+
const point = end === "start" ? points[0] : points[points.length - 1];
|
|
4493
|
+
if (!point)
|
|
4494
|
+
return [0, 0];
|
|
4495
|
+
const [dx, dy] = polylineEndpointDirection(points, end);
|
|
4496
|
+
const outward = end === "start" ? [dx, dy] : [-dx, -dy];
|
|
4497
|
+
if (Math.hypot(outward[0], outward[1]) <= 0.01)
|
|
4498
|
+
return point;
|
|
4499
|
+
if (entity.shape === "circle") {
|
|
4500
|
+
return ellipseBoundaryPoint(entity, point, outward);
|
|
4501
|
+
}
|
|
4502
|
+
return rectBoundaryPoint(entity, point, outward);
|
|
4503
|
+
}
|
|
4287
4504
|
function groupDepth(g, gm) {
|
|
4288
4505
|
let d = 0;
|
|
4289
4506
|
let cur = g;
|
|
@@ -5244,6 +5461,31 @@ function rectConnPoint(rx, ry, rw, rh, ox, oy) {
|
|
|
5244
5461
|
const t = Math.min(tx, ty);
|
|
5245
5462
|
return [cx + t * dx, cy + t * dy];
|
|
5246
5463
|
}
|
|
5464
|
+
function distance$1(a, b) {
|
|
5465
|
+
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
5466
|
+
}
|
|
5467
|
+
function compactEdgePoints(points) {
|
|
5468
|
+
const compacted = [];
|
|
5469
|
+
for (const point of points) {
|
|
5470
|
+
const previous = compacted[compacted.length - 1];
|
|
5471
|
+
if (!previous || distance$1(previous, point) > 0.01) {
|
|
5472
|
+
compacted.push(point);
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
return compacted;
|
|
5476
|
+
}
|
|
5477
|
+
function orthogonalEdgePoints(start, end) {
|
|
5478
|
+
if (Math.abs(start[0] - end[0]) < 0.01 || Math.abs(start[1] - end[1]) < 0.01) {
|
|
5479
|
+
return [start, end];
|
|
5480
|
+
}
|
|
5481
|
+
const midX = (start[0] + end[0]) / 2;
|
|
5482
|
+
return compactEdgePoints([
|
|
5483
|
+
start,
|
|
5484
|
+
[midX, start[1]],
|
|
5485
|
+
[midX, end[1]],
|
|
5486
|
+
end,
|
|
5487
|
+
]);
|
|
5488
|
+
}
|
|
5247
5489
|
function routeEdges(sg) {
|
|
5248
5490
|
const nm = nodeMap(sg);
|
|
5249
5491
|
const tm = tableMap(sg);
|
|
@@ -5273,10 +5515,17 @@ function routeEdges(sg) {
|
|
|
5273
5515
|
}
|
|
5274
5516
|
const dstCX = dst.x + dst.w / 2, dstCY = dst.y + dst.h / 2;
|
|
5275
5517
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
5276
|
-
e.
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5518
|
+
const start = anchoredConnPoint(src, e.fromAnchor, dstCX, dstCY);
|
|
5519
|
+
const end = anchoredConnPoint(dst, e.toAnchor, srcCX, srcCY);
|
|
5520
|
+
if (e.via?.length) {
|
|
5521
|
+
e.points = compactEdgePoints([start, ...e.via, end]);
|
|
5522
|
+
}
|
|
5523
|
+
else if (e.route === "orthogonal") {
|
|
5524
|
+
e.points = orthogonalEdgePoints(start, end);
|
|
5525
|
+
}
|
|
5526
|
+
else {
|
|
5527
|
+
e.points = [start, end];
|
|
5528
|
+
}
|
|
5280
5529
|
}
|
|
5281
5530
|
}
|
|
5282
5531
|
function computeBounds(sg, margin) {
|
|
@@ -5286,6 +5535,7 @@ function computeBounds(sg, margin) {
|
|
|
5286
5535
|
...sg.tables.map((t) => t.x + t.w),
|
|
5287
5536
|
...sg.charts.map((c) => c.x + c.w),
|
|
5288
5537
|
...sg.markdowns.map((m) => m.x + m.w),
|
|
5538
|
+
...sg.edges.flatMap((e) => (e.points ?? []).map(([x]) => x)),
|
|
5289
5539
|
];
|
|
5290
5540
|
const allY = [
|
|
5291
5541
|
...sg.nodes.map((n) => n.y + n.h),
|
|
@@ -5293,6 +5543,7 @@ function computeBounds(sg, margin) {
|
|
|
5293
5543
|
...sg.tables.map((t) => t.y + t.h),
|
|
5294
5544
|
...sg.charts.map((c) => c.y + c.h),
|
|
5295
5545
|
...sg.markdowns.map((m) => m.y + m.h),
|
|
5546
|
+
...sg.edges.flatMap((e) => (e.points ?? []).map(([, y]) => y)),
|
|
5296
5547
|
];
|
|
5297
5548
|
const autoWidth = (allX.length ? Math.max(...allX) : 400) + margin;
|
|
5298
5549
|
const autoHeight = (allY.length ? Math.max(...allY) : 300) + margin;
|
|
@@ -8466,20 +8717,16 @@ function renderToSVG(sg, container, options = {}) {
|
|
|
8466
8717
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
8467
8718
|
const [x1, y1] = getConnPoint(src, dstCX, dstCY, e.fromAnchor);
|
|
8468
8719
|
const [x2, y2] = getConnPoint(dst, srcCX, srcCY, e.toAnchor);
|
|
8720
|
+
const points = compactPolylinePoints(e.points?.length && e.points.length >= 2 ? e.points : [[x1, y1], [x2, y2]]);
|
|
8469
8721
|
const eg = mkGroup(`edge-${e.from}-${e.to}`, "eg");
|
|
8470
8722
|
setParentGroupData(eg, resolveEdgeParentGroupId(e.from, e.to, nm, tm, gmMap, cm, parentGroups));
|
|
8471
8723
|
if (e.style?.opacity != null)
|
|
8472
8724
|
eg.setAttribute("opacity", String(e.style.opacity));
|
|
8473
|
-
const len = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) || 1;
|
|
8474
|
-
const nx = (x2 - x1) / len, ny = (y2 - y1) / len;
|
|
8475
8725
|
const ecol = String(e.style?.stroke ?? palette.edgeStroke);
|
|
8476
8726
|
const { arrowAt, dashed } = connMeta(e.connector);
|
|
8477
8727
|
const HEAD = EDGE.headInset;
|
|
8478
|
-
const
|
|
8479
|
-
const
|
|
8480
|
-
const sx2 = arrowAt === "end" || arrowAt === "both" ? x2 - nx * HEAD : x2;
|
|
8481
|
-
const sy2 = arrowAt === "end" || arrowAt === "both" ? y2 - ny * HEAD : y2;
|
|
8482
|
-
const shaft = rc.line(sx1, sy1, sx2, sy2, {
|
|
8728
|
+
const shaftPoints = insetPolylineEndpoints(points, arrowAt, HEAD);
|
|
8729
|
+
const shaft = rc.path(polylinePathData(shaftPoints), {
|
|
8483
8730
|
...BASE_ROUGH,
|
|
8484
8731
|
roughness: 0.9,
|
|
8485
8732
|
seed: hashStr$3(e.from + e.to),
|
|
@@ -8490,18 +8737,21 @@ function renderToSVG(sg, container, options = {}) {
|
|
|
8490
8737
|
shaft.setAttribute("data-edge-role", "shaft");
|
|
8491
8738
|
eg.appendChild(shaft);
|
|
8492
8739
|
if (arrowAt === "end" || arrowAt === "both") {
|
|
8493
|
-
const
|
|
8740
|
+
const [endDx, endDy] = polylineEndpointDirection(points, "end");
|
|
8741
|
+
const [endX, endY] = polylineArrowTipPoint(dst, points, "end");
|
|
8742
|
+
const endHead = arrowHead(rc, endX, endY, Math.atan2(endDy, endDx), ecol, hashStr$3(e.to));
|
|
8494
8743
|
endHead.setAttribute("data-edge-role", "head");
|
|
8495
8744
|
eg.appendChild(endHead);
|
|
8496
8745
|
}
|
|
8497
8746
|
if (arrowAt === "start" || arrowAt === "both") {
|
|
8498
|
-
const
|
|
8747
|
+
const [startDx, startDy] = polylineEndpointDirection(points, "start");
|
|
8748
|
+
const [startX, startY] = polylineArrowTipPoint(src, points, "start");
|
|
8749
|
+
const startHead = arrowHead(rc, startX, startY, Math.atan2(-startDy, -startDx), ecol, hashStr$3(e.from + "back"));
|
|
8499
8750
|
startHead.setAttribute("data-edge-role", "head");
|
|
8500
8751
|
eg.appendChild(startHead);
|
|
8501
8752
|
}
|
|
8502
8753
|
if (e.label) {
|
|
8503
|
-
const
|
|
8504
|
-
const my = (y1 + y2) / 2 + nx * EDGE.labelOffset + (e.labelDy ?? 0);
|
|
8754
|
+
const { x: mx, y: my } = polylineLabelPosition(points, EDGE.labelOffset, e.labelDx ?? 0, e.labelDy ?? 0);
|
|
8505
8755
|
const tw = Math.max(e.label.length * 7 + 12, 36);
|
|
8506
8756
|
const bg = se("rect");
|
|
8507
8757
|
bg.setAttribute("x", String(mx - tw / 2));
|
|
@@ -9213,31 +9463,31 @@ function renderToCanvas(sg, canvas, options = {}) {
|
|
|
9213
9463
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
9214
9464
|
const [x1, y1] = getConnPoint(src, dstCX, dstCY, e.fromAnchor);
|
|
9215
9465
|
const [x2, y2] = getConnPoint(dst, srcCX, srcCY, e.toAnchor);
|
|
9466
|
+
const points = compactPolylinePoints(e.points?.length && e.points.length >= 2 ? e.points : [[x1, y1], [x2, y2]]);
|
|
9216
9467
|
if (e.style?.opacity != null)
|
|
9217
9468
|
ctx.globalAlpha = Number(e.style.opacity);
|
|
9218
9469
|
const ecol = String(e.style?.stroke ?? palette.edgeStroke);
|
|
9219
9470
|
const { arrowAt, dashed } = connMeta(e.connector);
|
|
9220
|
-
const len = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) || 1;
|
|
9221
|
-
const nx = (x2 - x1) / len, ny = (y2 - y1) / len;
|
|
9222
9471
|
const HEAD = EDGE.headInset;
|
|
9223
|
-
const
|
|
9224
|
-
|
|
9225
|
-
const sx2 = arrowAt === 'end' || arrowAt === 'both' ? x2 - nx * HEAD : x2;
|
|
9226
|
-
const sy2 = arrowAt === 'end' || arrowAt === 'both' ? y2 - ny * HEAD : y2;
|
|
9227
|
-
rc.line(sx1, sy1, sx2, sy2, {
|
|
9472
|
+
const shaftPoints = insetPolylineEndpoints(points, arrowAt, HEAD);
|
|
9473
|
+
rc.path(polylinePathData(shaftPoints), {
|
|
9228
9474
|
...R, roughness: 0.9, seed: hashStr$3(e.from + e.to),
|
|
9229
9475
|
stroke: ecol,
|
|
9230
9476
|
strokeWidth: Number(e.style?.strokeWidth ?? 1.6),
|
|
9231
9477
|
...(dashed ? { strokeLineDash: EDGE.dashPattern } : {}),
|
|
9232
9478
|
});
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9479
|
+
if (arrowAt === 'end' || arrowAt === 'both') {
|
|
9480
|
+
const [endDx, endDy] = polylineEndpointDirection(points, 'end');
|
|
9481
|
+
const [endX, endY] = polylineArrowTipPoint(dst, points, 'end');
|
|
9482
|
+
drawArrowHead(rc, endX, endY, Math.atan2(endDy, endDx), ecol, hashStr$3(e.to));
|
|
9483
|
+
}
|
|
9484
|
+
if (arrowAt === 'start' || arrowAt === 'both') {
|
|
9485
|
+
const [startDx, startDy] = polylineEndpointDirection(points, 'start');
|
|
9486
|
+
const [startX, startY] = polylineArrowTipPoint(src, points, 'start');
|
|
9487
|
+
drawArrowHead(rc, startX, startY, Math.atan2(-startDy, -startDx), ecol, hashStr$3(e.from + 'back'));
|
|
9488
|
+
}
|
|
9238
9489
|
if (e.label) {
|
|
9239
|
-
const
|
|
9240
|
-
const my = (y1 + y2) / 2 + nx * EDGE.labelOffset + (e.labelDy ?? 0);
|
|
9490
|
+
const { x: mx, y: my } = polylineLabelPosition(points, EDGE.labelOffset, e.labelDx ?? 0, e.labelDy ?? 0);
|
|
9241
9491
|
// ── Edge label: font, font-size, letter-spacing ──
|
|
9242
9492
|
// always center-anchored (single line)
|
|
9243
9493
|
const eFontSize = Number(e.style?.fontSize ?? EDGE.labelFontSize);
|
|
@@ -9934,7 +10184,7 @@ function animateShapeDraw(el, strokeDur = ANIMATION.nodeStrokeDur, stag = ANIMAT
|
|
|
9934
10184
|
}));
|
|
9935
10185
|
}
|
|
9936
10186
|
// ── Edge draw helpers ─────────────────────────────────────
|
|
9937
|
-
const EDGE_SHAFT_SELECTOR = '[data-edge-role="shaft"] path';
|
|
10187
|
+
const EDGE_SHAFT_SELECTOR = '[data-edge-role="shaft"] path, path[data-edge-role="shaft"]';
|
|
9938
10188
|
const EDGE_DECOR_SELECTOR = '[data-edge-role="head"], [data-edge-role="label"], [data-edge-role="label-bg"]';
|
|
9939
10189
|
function edgeShaftPaths(el) {
|
|
9940
10190
|
return Array.from(el.querySelectorAll(EDGE_SHAFT_SELECTOR));
|