@pixerate/editor 0.55.0 → 0.57.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/dist/agent/index.cjs +18 -17
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.js +3 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/animation-editor/index.cjs +25 -7
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +21 -5
- package/dist/animation-editor/index.d.ts +21 -5
- package/dist/animation-editor/index.js +25 -7
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/canvas/index.cjs +2105 -172
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +319 -23
- package/dist/canvas/index.d.ts +319 -23
- package/dist/canvas/index.js +2081 -148
- package/dist/canvas/index.js.map +1 -1
- package/dist/chart/index.cjs +32 -30
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.d.cts +4 -2
- package/dist/chart/index.d.ts +4 -2
- package/dist/chart/index.js +20 -18
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-C3JHII3M.cjs → chunk-3I6V7PI4.cjs} +45 -45
- package/dist/{chunk-C3JHII3M.cjs.map → chunk-3I6V7PI4.cjs.map} +1 -1
- package/dist/{chunk-P43HUQRX.cjs → chunk-AHCENCU4.cjs} +12 -10
- package/dist/chunk-AHCENCU4.cjs.map +1 -0
- package/dist/chunk-II77MLHN.cjs +11106 -0
- package/dist/chunk-II77MLHN.cjs.map +1 -0
- package/dist/{chunk-OIKYP7XC.js → chunk-LMUDHBWR.js} +2 -2
- package/dist/{chunk-VODBAO32.js → chunk-OEFCLWZ3.js} +4 -1425
- package/dist/chunk-OEFCLWZ3.js.map +1 -0
- package/dist/{chunk-NK3WL5TJ.cjs → chunk-P2CTDJNF.cjs} +27 -1448
- package/dist/chunk-P2CTDJNF.cjs.map +1 -0
- package/dist/chunk-TKPPIVW7.cjs +1443 -0
- package/dist/chunk-TKPPIVW7.cjs.map +1 -0
- package/dist/chunk-WJSCGBJ2.js +11106 -0
- package/dist/chunk-WJSCGBJ2.js.map +1 -0
- package/dist/{chunk-RIXTW3C4.js → chunk-WLVZ235X.js} +5 -3
- package/dist/{chunk-RIXTW3C4.js.map → chunk-WLVZ235X.js.map} +1 -1
- package/dist/chunk-ZOH6X3VR.js +1443 -0
- package/dist/chunk-ZOH6X3VR.js.map +1 -0
- package/dist/{controller-DscWQbjO.d.ts → controller-D2rj5umx.d.ts} +2 -362
- package/dist/{controller-CX0QfSv0.d.cts → controller-R2biKk_E.d.cts} +2 -362
- package/dist/diagram/index.cjs +1457 -47
- package/dist/diagram/index.cjs.map +1 -1
- package/dist/diagram/index.d.cts +1734 -15
- package/dist/diagram/index.d.ts +1734 -15
- package/dist/diagram/index.js +1436 -26
- package/dist/diagram/index.js.map +1 -1
- package/dist/extensions/index.cjs +5 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +4 -3
- package/dist/extensions/index.d.ts +4 -3
- package/dist/extensions/index.js +4 -3
- package/dist/{index-DIWB6xMf.d.cts → index-BcHyG0Wq.d.cts} +2 -1
- package/dist/{index-CALDD35B.d.ts → index-CTCc3m3C.d.ts} +2 -1
- package/dist/index.cjs +10 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/types-BRp-6zkY.d.cts +362 -0
- package/dist/types-BRp-6zkY.d.ts +362 -0
- package/dist/{types-BULrFyuQ.d.cts → types-DYkjhzdz.d.cts} +1 -1
- package/dist/{types-BULrFyuQ.d.ts → types-DYkjhzdz.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-H5K77C7Y.cjs +0 -3848
- package/dist/chunk-H5K77C7Y.cjs.map +0 -1
- package/dist/chunk-NK3WL5TJ.cjs.map +0 -1
- package/dist/chunk-P43HUQRX.cjs.map +0 -1
- package/dist/chunk-VODBAO32.js.map +0 -1
- package/dist/chunk-WWJNC7SX.js +0 -3848
- package/dist/chunk-WWJNC7SX.js.map +0 -1
- /package/dist/{chunk-OIKYP7XC.js.map → chunk-LMUDHBWR.js.map} +0 -0
package/dist/canvas/index.js
CHANGED
|
@@ -15,8 +15,39 @@ import {
|
|
|
15
15
|
pathfinder
|
|
16
16
|
} from "../chunk-VWZB6BCY.js";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
ARCH_METRICS,
|
|
19
|
+
GANTT_METRICS,
|
|
20
|
+
GIT_METRICS,
|
|
21
|
+
JOURNEY_METRICS,
|
|
22
|
+
MINDMAP_METRICS,
|
|
23
|
+
PIE_METRICS,
|
|
24
|
+
QUADRANT_METRICS,
|
|
25
|
+
RADAR_CHART_BOX,
|
|
26
|
+
SEQUENCE_METRICS,
|
|
27
|
+
TIMELINE_METRICS,
|
|
28
|
+
XY_CHART_BOX,
|
|
29
|
+
architectureArrow,
|
|
30
|
+
architectureEdgeRoute,
|
|
31
|
+
c4ArrowHead,
|
|
32
|
+
c4BoundaryText,
|
|
33
|
+
c4ElementGeometry,
|
|
34
|
+
c4RelGeometry,
|
|
35
|
+
estimateTextWidth,
|
|
36
|
+
ganttGeometry,
|
|
37
|
+
getFamilyLayout,
|
|
38
|
+
gitGraphGeometry,
|
|
39
|
+
isSide,
|
|
40
|
+
journeyGeometry,
|
|
41
|
+
mindmapGeometry,
|
|
42
|
+
parseMermaid,
|
|
43
|
+
pieGeometry,
|
|
44
|
+
quadrantGeometry,
|
|
45
|
+
sequenceGeometry,
|
|
46
|
+
serviceLabelLines,
|
|
47
|
+
shiftEndpoint,
|
|
48
|
+
textWidth,
|
|
49
|
+
timelineGeometry
|
|
50
|
+
} from "../chunk-WJSCGBJ2.js";
|
|
20
51
|
import {
|
|
21
52
|
DEFAULT_NODE_HEIGHT,
|
|
22
53
|
DEFAULT_NODE_WIDTH,
|
|
@@ -36,6 +67,13 @@ import {
|
|
|
36
67
|
DEFAULT_ARRANGE_SHORTCUTS,
|
|
37
68
|
matchArrangeShortcut
|
|
38
69
|
} from "../chunk-7DWMJCAT.js";
|
|
70
|
+
import {
|
|
71
|
+
layoutChart
|
|
72
|
+
} from "../chunk-OEFCLWZ3.js";
|
|
73
|
+
import {
|
|
74
|
+
createChartSpec
|
|
75
|
+
} from "../chunk-633QC34G.js";
|
|
76
|
+
import "../chunk-EKYHKQPG.js";
|
|
39
77
|
import {
|
|
40
78
|
CANVAS_GRADIENT_PRESETS,
|
|
41
79
|
PIXERATE_BRAND_GRADIENT,
|
|
@@ -1321,12 +1359,12 @@ function computeSnapGuides(moving, targets, options = {}) {
|
|
|
1321
1359
|
if (useCentres) {
|
|
1322
1360
|
lines.push({ value: start + size / 2, kind: "centre", axis: horizontal ? index.centreX : index.centreY });
|
|
1323
1361
|
}
|
|
1324
|
-
for (const
|
|
1325
|
-
const aligned = matches(
|
|
1362
|
+
for (const line4 of lines) {
|
|
1363
|
+
const aligned = matches(line4.axis, line4.value, eps);
|
|
1326
1364
|
if (aligned.length === 0) continue;
|
|
1327
1365
|
const span = boundsOf([snapped, ...aligned]);
|
|
1328
1366
|
guides.push(
|
|
1329
|
-
horizontal ? { orientation: "vertical", kind:
|
|
1367
|
+
horizontal ? { orientation: "vertical", kind: line4.kind, x1: line4.value, y1: span.y, x2: line4.value, y2: span.y + span.height } : { orientation: "horizontal", kind: line4.kind, x1: span.x, y1: line4.value, x2: span.x + span.width, y2: line4.value }
|
|
1330
1368
|
);
|
|
1331
1369
|
}
|
|
1332
1370
|
};
|
|
@@ -1547,13 +1585,13 @@ function parseCanvasScenes(input) {
|
|
|
1547
1585
|
}
|
|
1548
1586
|
const list = Array.isArray(value) ? value : typeof value === "object" && value !== null && Array.isArray(value.scenes) ? value.scenes : [];
|
|
1549
1587
|
const seen = /* @__PURE__ */ new Set();
|
|
1550
|
-
const
|
|
1588
|
+
const scenes2 = [];
|
|
1551
1589
|
for (const entry of list) {
|
|
1552
1590
|
if (!isValidCanvasScene(entry) || seen.has(entry.id)) continue;
|
|
1553
1591
|
seen.add(entry.id);
|
|
1554
|
-
|
|
1592
|
+
scenes2.push(cloneScene(entry));
|
|
1555
1593
|
}
|
|
1556
|
-
return
|
|
1594
|
+
return scenes2;
|
|
1557
1595
|
}
|
|
1558
1596
|
var CanvasScenesStore = class {
|
|
1559
1597
|
scenes;
|
|
@@ -1578,9 +1616,9 @@ var CanvasScenesStore = class {
|
|
|
1578
1616
|
currentIndex
|
|
1579
1617
|
};
|
|
1580
1618
|
}
|
|
1581
|
-
commit(
|
|
1582
|
-
this.scenes =
|
|
1583
|
-
if (this.currentId && !
|
|
1619
|
+
commit(scenes2 = this.scenes) {
|
|
1620
|
+
this.scenes = scenes2;
|
|
1621
|
+
if (this.currentId && !scenes2.some((s) => s.id === this.currentId)) this.currentId = null;
|
|
1584
1622
|
this.cached = this.snapshot();
|
|
1585
1623
|
this.onChange?.(this.cached);
|
|
1586
1624
|
for (const listener of this.listeners) listener(this.cached);
|
|
@@ -1615,11 +1653,11 @@ var CanvasScenesStore = class {
|
|
|
1615
1653
|
nodeIds: input.nodeIds
|
|
1616
1654
|
});
|
|
1617
1655
|
if (!isValidCanvasScene(scene)) throw new Error("[CanvasScenesStore] Invalid scene viewport.");
|
|
1618
|
-
const
|
|
1619
|
-
const at = index === void 0 ?
|
|
1620
|
-
|
|
1656
|
+
const scenes2 = [...this.scenes];
|
|
1657
|
+
const at = index === void 0 ? scenes2.length : Math.max(0, Math.min(scenes2.length, index));
|
|
1658
|
+
scenes2.splice(at, 0, scene);
|
|
1621
1659
|
this.currentId = scene.id;
|
|
1622
|
-
this.commit(
|
|
1660
|
+
this.commit(scenes2);
|
|
1623
1661
|
return scene;
|
|
1624
1662
|
}
|
|
1625
1663
|
/** Patches a scene's name, viewport or node ids. Returns the updated scene. */
|
|
@@ -1635,9 +1673,9 @@ var CanvasScenesStore = class {
|
|
|
1635
1673
|
id
|
|
1636
1674
|
});
|
|
1637
1675
|
if (!isValidCanvasScene(next)) throw new Error("[CanvasScenesStore] Invalid scene viewport.");
|
|
1638
|
-
const
|
|
1639
|
-
|
|
1640
|
-
this.commit(
|
|
1676
|
+
const scenes2 = [...this.scenes];
|
|
1677
|
+
scenes2[index] = next;
|
|
1678
|
+
this.commit(scenes2);
|
|
1641
1679
|
return next;
|
|
1642
1680
|
}
|
|
1643
1681
|
rename(id, name) {
|
|
@@ -1649,10 +1687,10 @@ var CanvasScenesStore = class {
|
|
|
1649
1687
|
if (from === -1) return;
|
|
1650
1688
|
const to = Math.max(0, Math.min(this.scenes.length - 1, Math.trunc(toIndex2)));
|
|
1651
1689
|
if (from === to) return;
|
|
1652
|
-
const
|
|
1653
|
-
const [scene] =
|
|
1654
|
-
|
|
1655
|
-
this.commit(
|
|
1690
|
+
const scenes2 = [...this.scenes];
|
|
1691
|
+
const [scene] = scenes2.splice(from, 1);
|
|
1692
|
+
scenes2.splice(to, 0, scene);
|
|
1693
|
+
this.commit(scenes2);
|
|
1656
1694
|
}
|
|
1657
1695
|
/** Reorders scenes to match `ids`; unknown ids are ignored and missing scenes keep their relative order at the end. */
|
|
1658
1696
|
reorder(ids) {
|
|
@@ -1867,8 +1905,8 @@ function combineShapeNodes(nodes, ids, operation, options = {}) {
|
|
|
1867
1905
|
} else {
|
|
1868
1906
|
report = { engine: "polygon" };
|
|
1869
1907
|
const operands = ordered.map((node) => shapeNodeToPolygon(node, lookup, options));
|
|
1870
|
-
const write = (
|
|
1871
|
-
polygonToSvgPath(
|
|
1908
|
+
const write = (polygon2) => toBezierPath(
|
|
1909
|
+
polygonToSvgPath(polygon2, {
|
|
1872
1910
|
precision: 9,
|
|
1873
1911
|
simplify: options.simplify,
|
|
1874
1912
|
curves: options.curves ?? "fit",
|
|
@@ -2621,10 +2659,10 @@ function layoutFrameInner(s, frame) {
|
|
|
2621
2659
|
} else {
|
|
2622
2660
|
lines.push(items.map((_, i) => i));
|
|
2623
2661
|
}
|
|
2624
|
-
for (const
|
|
2625
|
-
const fixed =
|
|
2626
|
-
const gaps = gap * Math.max(
|
|
2627
|
-
const fills =
|
|
2662
|
+
for (const line4 of lines) {
|
|
2663
|
+
const fixed = line4.filter((i) => !items[i].fillMain).reduce((sum, i) => sum + items[i].main, 0);
|
|
2664
|
+
const gaps = gap * Math.max(line4.length - 1, 0);
|
|
2665
|
+
const fills = line4.filter((i) => items[i].fillMain);
|
|
2628
2666
|
if (fills.length > 0) distribute(items, fills, innerMainFixed - fixed - (autoGap ? 0 : gaps));
|
|
2629
2667
|
}
|
|
2630
2668
|
for (const it of items) {
|
|
@@ -2637,11 +2675,11 @@ function layoutFrameInner(s, frame) {
|
|
|
2637
2675
|
for (const it of items) if (!it.fillCross) it.baseline = itemBaseline(s, it.id, 0);
|
|
2638
2676
|
}
|
|
2639
2677
|
const extents = [];
|
|
2640
|
-
for (const
|
|
2641
|
-
const gaps = gap * Math.max(
|
|
2642
|
-
const lineBase =
|
|
2643
|
-
for (const i of
|
|
2644
|
-
const inLine =
|
|
2678
|
+
for (const line4 of lines) {
|
|
2679
|
+
const gaps = gap * Math.max(line4.length - 1, 0);
|
|
2680
|
+
const lineBase = line4.reduce((m, i) => Math.max(m, items[i].baseline ?? 0), 0);
|
|
2681
|
+
for (const i of line4) items[i].baseOff = items[i].baseline !== void 0 ? lineBase - items[i].baseline : 0;
|
|
2682
|
+
const inLine = line4.map((i) => items[i]);
|
|
2645
2683
|
const mainUsed = inLine.reduce((sum, it) => sum + it.main, 0) + gaps;
|
|
2646
2684
|
const allFill = inLine.every((it) => it.fillCross);
|
|
2647
2685
|
const cross = inLine.filter((it) => allFill || !it.fillCross).reduce((m, it) => Math.max(m, it.baseOff + it.cross), 0);
|
|
@@ -2688,13 +2726,13 @@ function layoutFrameInner(s, frame) {
|
|
|
2688
2726
|
}
|
|
2689
2727
|
}
|
|
2690
2728
|
}
|
|
2691
|
-
lines.forEach((
|
|
2729
|
+
lines.forEach((line4, li) => {
|
|
2692
2730
|
const [used, ownCross] = extents[li];
|
|
2693
2731
|
const lineCross = single ? innerCross : ownCross;
|
|
2694
|
-
const total = used - gap * Math.max(
|
|
2695
|
-
let [pos, step] = mainOffsets(alignMain, innerMain, total,
|
|
2732
|
+
const total = used - gap * Math.max(line4.length - 1, 0);
|
|
2733
|
+
let [pos, step] = mainOffsets(alignMain, innerMain, total, line4.length, gap);
|
|
2696
2734
|
pos += horizontal ? pl : pt;
|
|
2697
|
-
for (const i of
|
|
2735
|
+
for (const i of line4) {
|
|
2698
2736
|
const it = items[i];
|
|
2699
2737
|
const crossSize = it.fillCross ? clampLayoutSize(lineCross, it.minCross, it.maxCross) : it.cross;
|
|
2700
2738
|
let off = 0;
|
|
@@ -3672,37 +3710,37 @@ function inside(out, inner, outer) {
|
|
|
3672
3710
|
}
|
|
3673
3711
|
function measureBetween(a, b) {
|
|
3674
3712
|
const out = [];
|
|
3675
|
-
const
|
|
3713
|
+
const A2 = toBox(a);
|
|
3676
3714
|
const B = toBox(b);
|
|
3677
|
-
if (!finiteBox(
|
|
3678
|
-
if (contains(B,
|
|
3679
|
-
inside(out,
|
|
3715
|
+
if (!finiteBox(A2) || !finiteBox(B)) return out;
|
|
3716
|
+
if (contains(B, A2)) {
|
|
3717
|
+
inside(out, A2, B);
|
|
3680
3718
|
return out;
|
|
3681
3719
|
}
|
|
3682
|
-
if (contains(
|
|
3683
|
-
inside(out, B,
|
|
3720
|
+
if (contains(A2, B)) {
|
|
3721
|
+
inside(out, B, A2);
|
|
3684
3722
|
return out;
|
|
3685
3723
|
}
|
|
3686
|
-
const ox = overlapMid(
|
|
3687
|
-
const oy = overlapMid(
|
|
3688
|
-
const overlapping =
|
|
3724
|
+
const ox = overlapMid(A2.x0, A2.x1, B.x0, B.x1);
|
|
3725
|
+
const oy = overlapMid(A2.y0, A2.y1, B.y0, B.y1);
|
|
3726
|
+
const overlapping = A2.x0 < B.x1 && B.x0 < A2.x1 && A2.y0 < B.y1 && B.y0 < A2.y1;
|
|
3689
3727
|
if (overlapping && ox !== null && oy !== null) {
|
|
3690
|
-
measured(out,
|
|
3691
|
-
measured(out,
|
|
3692
|
-
measured(out, ox,
|
|
3693
|
-
measured(out, ox,
|
|
3728
|
+
measured(out, A2.x0, oy, B.x0, oy);
|
|
3729
|
+
measured(out, A2.x1, oy, B.x1, oy);
|
|
3730
|
+
measured(out, ox, A2.y0, ox, B.y0);
|
|
3731
|
+
measured(out, ox, A2.y1, ox, B.y1);
|
|
3694
3732
|
return out;
|
|
3695
3733
|
}
|
|
3696
|
-
const cx = (
|
|
3697
|
-
const cy = (
|
|
3698
|
-
const gapX = B.x0 >=
|
|
3734
|
+
const cx = (A2.x0 + A2.x1) / 2;
|
|
3735
|
+
const cy = (A2.y0 + A2.y1) / 2;
|
|
3736
|
+
const gapX = B.x0 >= A2.x1 ? [A2.x1, B.x0] : B.x1 <= A2.x0 ? [A2.x0, B.x1] : null;
|
|
3699
3737
|
if (gapX) {
|
|
3700
3738
|
const [from, to] = gapX;
|
|
3701
3739
|
const y = oy ?? cy;
|
|
3702
3740
|
measured(out, from, y, to, y);
|
|
3703
3741
|
if (oy === null) extension(out, to, y, to, y < B.y0 ? B.y0 : B.y1);
|
|
3704
3742
|
}
|
|
3705
|
-
const gapY = B.y0 >=
|
|
3743
|
+
const gapY = B.y0 >= A2.y1 ? [A2.y1, B.y0] : B.y1 <= A2.y0 ? [A2.y0, B.y1] : null;
|
|
3706
3744
|
if (gapY) {
|
|
3707
3745
|
const [from, to] = gapY;
|
|
3708
3746
|
const x = ox ?? cx;
|
|
@@ -3713,12 +3751,12 @@ function measureBetween(a, b) {
|
|
|
3713
3751
|
}
|
|
3714
3752
|
function measureToLine(a, orientation, at) {
|
|
3715
3753
|
const out = [];
|
|
3716
|
-
const
|
|
3717
|
-
if (!finiteBox(
|
|
3754
|
+
const A2 = toBox(a);
|
|
3755
|
+
if (!finiteBox(A2) || !Number.isFinite(at)) return out;
|
|
3718
3756
|
const vertical = orientation === "vertical";
|
|
3719
|
-
const cx = (
|
|
3720
|
-
const cy = (
|
|
3721
|
-
const [lo, hi] = vertical ? [
|
|
3757
|
+
const cx = (A2.x0 + A2.x1) / 2;
|
|
3758
|
+
const cy = (A2.y0 + A2.y1) / 2;
|
|
3759
|
+
const [lo, hi] = vertical ? [A2.x0, A2.x1] : [A2.y0, A2.y1];
|
|
3722
3760
|
const seg = (from, to) => vertical ? measured(out, from, cy, to, cy) : measured(out, cx, from, cx, to);
|
|
3723
3761
|
if (at >= hi) seg(hi, at);
|
|
3724
3762
|
else if (at <= lo) seg(at, lo);
|
|
@@ -4078,17 +4116,17 @@ function readNodeStyleProperty(style, prop) {
|
|
|
4078
4116
|
function writeNodeStyleProperty(style, prop, value, unitless = false) {
|
|
4079
4117
|
if (typeof style === "string") {
|
|
4080
4118
|
const name = kebab(prop);
|
|
4081
|
-
const
|
|
4119
|
+
const text2 = value === void 0 ? void 0 : typeof value === "number" && !unitless ? `${value}px` : String(value);
|
|
4082
4120
|
const decls = [];
|
|
4083
|
-
let placed =
|
|
4121
|
+
let placed = text2 === void 0;
|
|
4084
4122
|
for (const [key, current] of parseDeclarations(style)) {
|
|
4085
4123
|
if (key.toLowerCase() !== name) decls.push([key, current]);
|
|
4086
4124
|
else if (!placed) {
|
|
4087
|
-
decls.push([name,
|
|
4125
|
+
decls.push([name, text2]);
|
|
4088
4126
|
placed = true;
|
|
4089
4127
|
}
|
|
4090
4128
|
}
|
|
4091
|
-
if (!placed) decls.push([name,
|
|
4129
|
+
if (!placed) decls.push([name, text2]);
|
|
4092
4130
|
return decls.map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
4093
4131
|
}
|
|
4094
4132
|
const next = { ...style ?? {} };
|
|
@@ -5331,7 +5369,7 @@ function timing(options, duration) {
|
|
|
5331
5369
|
direction: loop === "ping-pong" ? rate < 0 ? "alternate-reverse" : "alternate" : rate < 0 ? "reverse" : "normal"
|
|
5332
5370
|
};
|
|
5333
5371
|
}
|
|
5334
|
-
var cssIdent = (
|
|
5372
|
+
var cssIdent = (text2) => text2.replace(/[^A-Za-z0-9_-]/g, "-").replace(/^(\d)/, "_$1");
|
|
5335
5373
|
function exportCssAnimation(nodes, nodeId, options = {}) {
|
|
5336
5374
|
const duration = options.duration ?? getAnimationDuration(nodes.filter((n3) => n3.id === nodeId));
|
|
5337
5375
|
const props = getCssPropertyAnimations(nodes, nodeId, { ...options, duration });
|
|
@@ -7293,8 +7331,8 @@ function swapCanvasInstance(nodes, ids, componentId, options = {}) {
|
|
|
7293
7331
|
if (options.keepTextOverridesOnly) {
|
|
7294
7332
|
for (const d of g.subtree(id)) {
|
|
7295
7333
|
const layer = updates.get(d) ?? g.get(d);
|
|
7296
|
-
const
|
|
7297
|
-
const keep = getNodeOverrides(layer).filter((gr) =>
|
|
7334
|
+
const text2 = typeof layer.type === "string" && (options.textTypes ?? ["text"]).includes(layer.type);
|
|
7335
|
+
const keep = getNodeOverrides(layer).filter((gr) => text2 || d === id && gr === "size");
|
|
7298
7336
|
updates.set(d, setOverrides(layer, keep));
|
|
7299
7337
|
}
|
|
7300
7338
|
}
|
|
@@ -8454,9 +8492,9 @@ function estimateDiagramNodeSize(node) {
|
|
|
8454
8492
|
}
|
|
8455
8493
|
var IMAGE_LABEL_HEIGHT = 24;
|
|
8456
8494
|
function diagramImageSize(node) {
|
|
8457
|
-
const
|
|
8458
|
-
const w =
|
|
8459
|
-
const h =
|
|
8495
|
+
const num4 = (v) => typeof v === "number" && v > 0 ? v : void 0;
|
|
8496
|
+
const w = num4(node.data?.w);
|
|
8497
|
+
const h = num4(node.data?.h);
|
|
8460
8498
|
return { width: w ?? h ?? 96, height: h ?? w ?? 96 };
|
|
8461
8499
|
}
|
|
8462
8500
|
function extraLines(node) {
|
|
@@ -8475,6 +8513,8 @@ function rankdir(direction) {
|
|
|
8475
8513
|
}
|
|
8476
8514
|
function autoLayoutDiagram(graph, options = {}) {
|
|
8477
8515
|
const measure = options.measure ?? estimateDiagramNodeSize;
|
|
8516
|
+
const custom = getFamilyLayout(options.family);
|
|
8517
|
+
if (custom) return custom(graph, { v: 1 }, { ...options, measure });
|
|
8478
8518
|
const nodeSep = options.nodeSep ?? 48;
|
|
8479
8519
|
const rankSep = options.rankSep ?? 72;
|
|
8480
8520
|
const pad = options.groupPadding ?? 24;
|
|
@@ -8573,6 +8613,8 @@ function push(map, key, value) {
|
|
|
8573
8613
|
}
|
|
8574
8614
|
function ensureDiagramLayout(graph, meta, options) {
|
|
8575
8615
|
const measure = options?.measure ?? estimateDiagramNodeSize;
|
|
8616
|
+
const custom = getFamilyLayout(options?.family);
|
|
8617
|
+
if (custom) return custom(graph, meta, { ...options ?? {}, measure });
|
|
8576
8618
|
const stored = meta.layout ?? {};
|
|
8577
8619
|
const allIds = [...graph.nodes.map((n3) => n3.id), ...graph.groups.map((g) => g.id)];
|
|
8578
8620
|
const missing = allIds.filter((id) => !stored[id]);
|
|
@@ -8837,14 +8879,14 @@ var DiagramStream = class {
|
|
|
8837
8879
|
layout = null;
|
|
8838
8880
|
/** Reads the source so far. `complete` when nothing more will arrive. */
|
|
8839
8881
|
update(source, complete = false) {
|
|
8840
|
-
const
|
|
8841
|
-
const parsed = parseMermaid(
|
|
8882
|
+
const text2 = streamedDiagramText(source);
|
|
8883
|
+
const parsed = parseMermaid(text2);
|
|
8842
8884
|
const document2 = !complete ? { ...parsed, graph: connectedDiagramOnly(parsed.graph) } : parsed;
|
|
8843
8885
|
if (document2.tier !== "editable" || !document2.graph.nodes.length) return { document: document2, layout: this.layout && complete ? null : this.layout, relaid: false };
|
|
8844
8886
|
const key = fingerprint(document2.graph);
|
|
8845
8887
|
if (key === this.lastKey && this.layout) return { document: document2, layout: this.layout, relaid: false };
|
|
8846
8888
|
this.lastKey = key;
|
|
8847
|
-
this.layout = ensureDiagramLayout(document2.graph, document2.meta, this.options);
|
|
8889
|
+
this.layout = ensureDiagramLayout(document2.graph, document2.meta, { family: document2.family, ...this.options });
|
|
8848
8890
|
return { document: document2, layout: this.layout, relaid: true };
|
|
8849
8891
|
}
|
|
8850
8892
|
/** Forgets the previous layout (a new source). */
|
|
@@ -8863,6 +8905,1881 @@ function streamedDiagramText(source) {
|
|
|
8863
8905
|
}
|
|
8864
8906
|
var easeDiagramTween = (t) => 1 - Math.pow(1 - Math.max(0, Math.min(1, t)), 3);
|
|
8865
8907
|
|
|
8908
|
+
// src/canvas/mermaid/theme.ts
|
|
8909
|
+
var DIAGRAM_SVG_LIGHT_THEME = {
|
|
8910
|
+
background: "#ffffff",
|
|
8911
|
+
nodeFill: "#ffffff",
|
|
8912
|
+
nodeStroke: "#0f172a",
|
|
8913
|
+
text: "#0f172a",
|
|
8914
|
+
edge: "#64748b",
|
|
8915
|
+
edgeLabelBackground: "#ffffff",
|
|
8916
|
+
groupFill: "#f8fafc",
|
|
8917
|
+
groupStroke: "#cbd5e1",
|
|
8918
|
+
groupText: "#475569",
|
|
8919
|
+
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
8920
|
+
fontSize: 13
|
|
8921
|
+
};
|
|
8922
|
+
var DIAGRAM_SVG_DARK_THEME = {
|
|
8923
|
+
background: "#0f172a",
|
|
8924
|
+
nodeFill: "#1e293b",
|
|
8925
|
+
nodeStroke: "#e2e8f0",
|
|
8926
|
+
text: "#f1f5f9",
|
|
8927
|
+
edge: "#94a3b8",
|
|
8928
|
+
edgeLabelBackground: "#0f172a",
|
|
8929
|
+
groupFill: "#111c33",
|
|
8930
|
+
groupStroke: "#334155",
|
|
8931
|
+
groupText: "#94a3b8",
|
|
8932
|
+
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
8933
|
+
fontSize: 13
|
|
8934
|
+
};
|
|
8935
|
+
|
|
8936
|
+
// src/canvas/mermaid/scene-kit.ts
|
|
8937
|
+
var PALETTE_LIGHT = ["#4e79a7", "#f28e2b", "#59a14f", "#e15759", "#76b7b2", "#edc948", "#b07aa1", "#ff9da7", "#9c755f", "#bab0ac", "#8cd17d", "#86bcb6"];
|
|
8938
|
+
var PALETTE_DARK = ["#7aa6d6", "#ffad5c", "#7fcf73", "#ff8587", "#9fdcd6", "#ffe07a", "#d4a2c6", "#ffc2c9", "#c49a82", "#d9d0cc", "#b0eba3", "#acd8d3"];
|
|
8939
|
+
var DIAGRAM_SCENE_LIGHT_THEME = {
|
|
8940
|
+
...DIAGRAM_SVG_LIGHT_THEME,
|
|
8941
|
+
palette: PALETTE_LIGHT,
|
|
8942
|
+
paletteText: "#0f172a",
|
|
8943
|
+
grid: "#cbd5e1",
|
|
8944
|
+
mutedText: "#64748b",
|
|
8945
|
+
selection: "#2563eb"
|
|
8946
|
+
};
|
|
8947
|
+
var DIAGRAM_SCENE_DARK_THEME = {
|
|
8948
|
+
...DIAGRAM_SVG_DARK_THEME,
|
|
8949
|
+
palette: PALETTE_DARK,
|
|
8950
|
+
paletteText: "#0f172a",
|
|
8951
|
+
grid: "#334155",
|
|
8952
|
+
mutedText: "#94a3b8",
|
|
8953
|
+
selection: "#60a5fa"
|
|
8954
|
+
};
|
|
8955
|
+
var DIAGRAM_TITLE_TARGET = "::title";
|
|
8956
|
+
function sceneColor(theme, i) {
|
|
8957
|
+
return theme.palette[(i % theme.palette.length + theme.palette.length) % theme.palette.length];
|
|
8958
|
+
}
|
|
8959
|
+
function estimateTextWidth2(text2, size) {
|
|
8960
|
+
return text2.length * size * 0.58;
|
|
8961
|
+
}
|
|
8962
|
+
|
|
8963
|
+
// src/canvas/mermaid/families/pie.ts
|
|
8964
|
+
var M = PIE_METRICS;
|
|
8965
|
+
var pieScene = ({ graph, theme }) => {
|
|
8966
|
+
const geo = pieGeometry(graph);
|
|
8967
|
+
const marks = [];
|
|
8968
|
+
for (const slice of geo.slices) {
|
|
8969
|
+
if (!slice.drawn) continue;
|
|
8970
|
+
const r = geo.radius;
|
|
8971
|
+
marks.push({
|
|
8972
|
+
kind: "path",
|
|
8973
|
+
key: `wedge:${slice.id}`,
|
|
8974
|
+
role: "slice",
|
|
8975
|
+
target: slice.id,
|
|
8976
|
+
d: slice.path,
|
|
8977
|
+
fill: sceneColor(theme, slice.colorIndex),
|
|
8978
|
+
stroke: theme.background,
|
|
8979
|
+
strokeWidth: 2,
|
|
8980
|
+
box: { x: geo.cx - r, y: geo.cy - r, width: r * 2, height: r * 2 }
|
|
8981
|
+
});
|
|
8982
|
+
}
|
|
8983
|
+
marks.push({ kind: "circle", key: "outer", role: "outline", cx: geo.cx, cy: geo.cy, r: geo.outerRadius, fill: "none", stroke: theme.nodeStroke, strokeWidth: M.outerStrokeWidth });
|
|
8984
|
+
for (const slice of geo.slices) {
|
|
8985
|
+
if (!slice.drawn) continue;
|
|
8986
|
+
marks.push({ kind: "text", key: `percent:${slice.id}`, role: "slice-label", target: slice.id, x: slice.labelX, y: slice.labelY, text: slice.labelText, anchor: "middle", baseline: "bottom", size: 17, fill: theme.paletteText });
|
|
8987
|
+
}
|
|
8988
|
+
for (const entry of geo.legend) {
|
|
8989
|
+
marks.push(
|
|
8990
|
+
{ kind: "rect", key: `swatch:${entry.sliceId}`, role: "legend", target: entry.sliceId, x: entry.x, y: entry.y, width: M.legendRectSize, height: M.legendRectSize, fill: sceneColor(theme, entry.colorIndex), stroke: sceneColor(theme, entry.colorIndex) },
|
|
8991
|
+
{
|
|
8992
|
+
kind: "text",
|
|
8993
|
+
key: `legend:${entry.sliceId}`,
|
|
8994
|
+
role: "legend",
|
|
8995
|
+
target: entry.sliceId,
|
|
8996
|
+
x: entry.x + M.legendRectSize + M.legendSpacing,
|
|
8997
|
+
y: entry.y + M.legendRectSize / 2,
|
|
8998
|
+
text: entry.text,
|
|
8999
|
+
anchor: "start",
|
|
9000
|
+
baseline: "middle",
|
|
9001
|
+
size: M.legendFontSize,
|
|
9002
|
+
fill: theme.text
|
|
9003
|
+
}
|
|
9004
|
+
);
|
|
9005
|
+
}
|
|
9006
|
+
if (geo.title)
|
|
9007
|
+
marks.push({ kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: geo.title.x, y: geo.title.y, text: geo.title.text, anchor: "middle", baseline: "bottom", size: M.titleFontSize, fill: theme.text });
|
|
9008
|
+
return marks;
|
|
9009
|
+
};
|
|
9010
|
+
|
|
9011
|
+
// src/canvas/mermaid/families/charts.ts
|
|
9012
|
+
var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
9013
|
+
var numbers = (v) => Array.isArray(v) ? v.map(num2) : [];
|
|
9014
|
+
var text = (v) => typeof v === "string" ? v : "";
|
|
9015
|
+
function chartTheme(theme) {
|
|
9016
|
+
return {
|
|
9017
|
+
background: theme.background,
|
|
9018
|
+
surface: theme.background,
|
|
9019
|
+
text: theme.text,
|
|
9020
|
+
mutedText: theme.mutedText,
|
|
9021
|
+
grid: theme.grid,
|
|
9022
|
+
axis: theme.mutedText,
|
|
9023
|
+
selection: theme.selection,
|
|
9024
|
+
fontFamily: theme.fontFamily
|
|
9025
|
+
};
|
|
9026
|
+
}
|
|
9027
|
+
function xyChartSpec(graph, palette) {
|
|
9028
|
+
const data = graph.data ?? {};
|
|
9029
|
+
const longest = Math.max(0, ...graph.nodes.map((n3) => numbers(n3.data?.values).length));
|
|
9030
|
+
let categories = Array.isArray(data.categories) ? data.categories.map(String) : [];
|
|
9031
|
+
const xMin = num2(data.xMin);
|
|
9032
|
+
const xMax = num2(data.xMax);
|
|
9033
|
+
if (!categories.length && longest) {
|
|
9034
|
+
categories = Array.from(
|
|
9035
|
+
{ length: longest },
|
|
9036
|
+
(_, i) => xMin !== null && xMax !== null ? String(Math.round((xMin + (xMax - xMin) * i / Math.max(1, longest - 1)) * 100) / 100) : String(i + 1)
|
|
9037
|
+
);
|
|
9038
|
+
}
|
|
9039
|
+
const bars = graph.nodes.some((n3) => n3.shape === "bar");
|
|
9040
|
+
return createChartSpec({
|
|
9041
|
+
type: bars ? "bar" : "line",
|
|
9042
|
+
title: graph.title ?? "",
|
|
9043
|
+
categories,
|
|
9044
|
+
series: graph.nodes.map((n3) => ({ id: n3.id, name: n3.label, values: numbers(n3.data?.values), type: n3.shape === "line" ? "line" : "bar" })),
|
|
9045
|
+
orientation: data.horizontal ? "horizontal" : "vertical",
|
|
9046
|
+
xAxis: { show: true, title: text(data.xTitle), min: null, max: null, step: null, gridlines: false, format: {} },
|
|
9047
|
+
yAxis: { show: true, title: text(data.yTitle), min: num2(data.yMin), max: num2(data.yMax), step: null, gridlines: true, format: {} },
|
|
9048
|
+
legend: { show: graph.nodes.some((n3) => n3.data?.titled), position: "top" },
|
|
9049
|
+
...palette ? { palette: [...palette] } : {}
|
|
9050
|
+
});
|
|
9051
|
+
}
|
|
9052
|
+
function radarChartSpec(graph, palette) {
|
|
9053
|
+
const data = graph.data ?? {};
|
|
9054
|
+
return createChartSpec({
|
|
9055
|
+
type: "radar",
|
|
9056
|
+
title: graph.title ?? "",
|
|
9057
|
+
categories: Array.isArray(data.axes) ? data.axes.map(String) : [],
|
|
9058
|
+
series: graph.nodes.map((n3) => ({ id: n3.id, name: n3.label, values: numbers(n3.data?.values) })),
|
|
9059
|
+
yAxis: { show: true, title: "", min: num2(data.min), max: num2(data.max), step: null, gridlines: true, format: {} },
|
|
9060
|
+
legend: { show: data.showLegend !== false, position: "top" },
|
|
9061
|
+
...palette ? { palette: [...palette] } : {}
|
|
9062
|
+
});
|
|
9063
|
+
}
|
|
9064
|
+
function targetOf(target) {
|
|
9065
|
+
if (!target) return void 0;
|
|
9066
|
+
if (target.kind === "series" || target.kind === "point") return target.seriesId;
|
|
9067
|
+
if (target.kind === "title") return DIAGRAM_TITLE_TARGET;
|
|
9068
|
+
return void 0;
|
|
9069
|
+
}
|
|
9070
|
+
function toDiagramMarks(marks, x, y) {
|
|
9071
|
+
return marks.filter((m) => m.role !== "selection" && m.role !== "drag-readout").map((m) => {
|
|
9072
|
+
const base = { key: m.key, role: m.role, ...targetOf(m.target) ? { target: targetOf(m.target) } : {}, ...m.opacity !== void 0 ? { opacity: m.opacity } : {} };
|
|
9073
|
+
switch (m.kind) {
|
|
9074
|
+
case "rect":
|
|
9075
|
+
return { ...base, kind: "rect", x: m.x + x, y: m.y + y, width: m.width, height: m.height, fill: m.fill, stroke: m.stroke, strokeWidth: m.strokeWidth, radius: m.radius };
|
|
9076
|
+
case "circle":
|
|
9077
|
+
return { ...base, kind: "circle", cx: m.cx + x, cy: m.cy + y, r: m.r, fill: m.fill, stroke: m.stroke, strokeWidth: m.strokeWidth };
|
|
9078
|
+
case "line":
|
|
9079
|
+
return { ...base, kind: "line", x1: m.x1 + x, y1: m.y1 + y, x2: m.x2 + x, y2: m.y2 + y, stroke: m.stroke, strokeWidth: m.strokeWidth, dash: m.dash };
|
|
9080
|
+
case "text":
|
|
9081
|
+
return { ...base, kind: "text", x: m.x + x, y: m.y + y, text: m.text, anchor: m.anchor, baseline: m.baseline, size: m.size, weight: m.weight, fill: m.fill, rotate: m.rotate };
|
|
9082
|
+
case "path":
|
|
9083
|
+
return {
|
|
9084
|
+
...base,
|
|
9085
|
+
kind: "path",
|
|
9086
|
+
// Chart paths are absolute, so the whole path moves with a translate prefix.
|
|
9087
|
+
d: x || y ? translatePath(m.d, x, y) : m.d,
|
|
9088
|
+
fill: m.fill,
|
|
9089
|
+
stroke: m.stroke,
|
|
9090
|
+
strokeWidth: m.strokeWidth,
|
|
9091
|
+
dash: m.dash
|
|
9092
|
+
};
|
|
9093
|
+
}
|
|
9094
|
+
});
|
|
9095
|
+
}
|
|
9096
|
+
function translatePath(d, dx, dy) {
|
|
9097
|
+
let i = 0;
|
|
9098
|
+
return d.replace(/-?\d*\.?\d+(?:e-?\d+)?/gi, (v) => String(Math.round((Number(v) + (i++ % 2 === 0 ? dx : dy)) * 100) / 100));
|
|
9099
|
+
}
|
|
9100
|
+
var xyChartScene = ({ graph, theme }) => {
|
|
9101
|
+
const box = XY_CHART_BOX;
|
|
9102
|
+
const scene = layoutChart(xyChartSpec(graph, theme.palette), { width: box.width, height: box.height, theme: chartTheme(theme) });
|
|
9103
|
+
return toDiagramMarks(scene.marks, box.x, box.y);
|
|
9104
|
+
};
|
|
9105
|
+
var radarScene = ({ graph, theme }) => {
|
|
9106
|
+
const box = RADAR_CHART_BOX;
|
|
9107
|
+
const scene = layoutChart(radarChartSpec(graph, theme.palette), { width: box.width, height: box.height, theme: chartTheme(theme) });
|
|
9108
|
+
return toDiagramMarks(scene.marks, box.x, box.y);
|
|
9109
|
+
};
|
|
9110
|
+
|
|
9111
|
+
// src/canvas/mermaid/families/sequence.ts
|
|
9112
|
+
var M2 = SEQUENCE_METRICS;
|
|
9113
|
+
var LABEL_SIZE = 14;
|
|
9114
|
+
var LINE_HEIGHT = 1.25;
|
|
9115
|
+
var SMALL_SIZE = 13;
|
|
9116
|
+
var TITLE_SIZE = 18;
|
|
9117
|
+
var NOTE_COLOR = 5;
|
|
9118
|
+
function displayLines(label) {
|
|
9119
|
+
let text2 = label;
|
|
9120
|
+
if (text2.startsWith("`") && text2.endsWith("`")) text2 = text2.slice(1, -1);
|
|
9121
|
+
return text2.replace(/<br\s*\/?>/gi, "\n").replace(/#quot;/g, '"').replace(/#(\d+);/g, (_, n3) => String.fromCharCode(Number(n3))).split("\n");
|
|
9122
|
+
}
|
|
9123
|
+
function dashFor(pattern) {
|
|
9124
|
+
return pattern === "dotted" ? "6 4" : pattern === "invisible" ? "0 1" : void 0;
|
|
9125
|
+
}
|
|
9126
|
+
function markerFor(head) {
|
|
9127
|
+
if (head === "none" || head === "arrow_cross") return void 0;
|
|
9128
|
+
return head === "arrow_open" ? "arrow" : "arrowclosed";
|
|
9129
|
+
}
|
|
9130
|
+
function textLines(lines, base) {
|
|
9131
|
+
const lh = base.size * LINE_HEIGHT;
|
|
9132
|
+
const top = base.cy - (lines.length - 1) * lh / 2;
|
|
9133
|
+
return lines.map((text2, i) => ({
|
|
9134
|
+
kind: "text",
|
|
9135
|
+
key: lines.length === 1 ? base.key : `${base.key}:${i}`,
|
|
9136
|
+
role: base.role,
|
|
9137
|
+
...base.target ? { target: base.target } : {},
|
|
9138
|
+
x: base.x,
|
|
9139
|
+
y: top + i * lh,
|
|
9140
|
+
text: text2,
|
|
9141
|
+
anchor: base.anchor ?? "middle",
|
|
9142
|
+
baseline: "middle",
|
|
9143
|
+
size: base.size,
|
|
9144
|
+
fill: base.fill,
|
|
9145
|
+
...base.weight ? { weight: base.weight } : {}
|
|
9146
|
+
}));
|
|
9147
|
+
}
|
|
9148
|
+
function participantMarks(node, box, mirror, theme) {
|
|
9149
|
+
const prefix = mirror ? "mirror" : "participant";
|
|
9150
|
+
const role = mirror ? "participant-mirror" : "participant";
|
|
9151
|
+
const lines = displayLines(node.label || node.id);
|
|
9152
|
+
if (node.shape !== "actor") {
|
|
9153
|
+
return [
|
|
9154
|
+
{ kind: "rect", key: `${prefix}:${node.id}`, role, target: node.id, ...box, fill: theme.nodeFill, stroke: theme.nodeStroke, strokeWidth: 1, radius: 3 },
|
|
9155
|
+
...textLines(lines, { key: `${prefix}-label:${node.id}`, role: `${role}-label`, target: node.id, x: box.x + box.width / 2, cy: box.y + box.height / 2, size: LABEL_SIZE, fill: theme.text })
|
|
9156
|
+
];
|
|
9157
|
+
}
|
|
9158
|
+
const lh = LABEL_SIZE * LINE_HEIGHT;
|
|
9159
|
+
const labelHeight = lines.length * lh;
|
|
9160
|
+
const scale = Math.min(28 / 40, 34 / 46);
|
|
9161
|
+
const figTop = box.y + box.height - labelHeight - 2 - 34 + (34 - 46 * scale) / 2;
|
|
9162
|
+
const figLeft = box.x + box.width / 2 - 20 * scale;
|
|
9163
|
+
const fx = (v) => figLeft + v * scale;
|
|
9164
|
+
const fy = (v) => figTop + v * scale;
|
|
9165
|
+
const d = `M${fx(20)},${fy(15)} V${fy(31)} M${fx(6)},${fy(21)} H${fx(34)} M${fx(20)},${fy(31)} L${fx(9)},${fy(44)} M${fx(20)},${fy(31)} L${fx(31)},${fy(44)}`;
|
|
9166
|
+
return [
|
|
9167
|
+
{ kind: "circle", key: `${prefix}-head:${node.id}`, role: `${role}-figure`, target: node.id, cx: fx(20), cy: fy(8), r: 7 * scale, fill: theme.nodeFill, stroke: theme.nodeStroke, strokeWidth: 1.5 },
|
|
9168
|
+
{
|
|
9169
|
+
kind: "path",
|
|
9170
|
+
key: `${prefix}-body:${node.id}`,
|
|
9171
|
+
role: `${role}-figure`,
|
|
9172
|
+
target: node.id,
|
|
9173
|
+
d,
|
|
9174
|
+
fill: "none",
|
|
9175
|
+
stroke: theme.nodeStroke,
|
|
9176
|
+
strokeWidth: 1.5,
|
|
9177
|
+
box: { x: fx(6), y: fy(15), width: 28 * scale, height: 29 * scale }
|
|
9178
|
+
},
|
|
9179
|
+
...textLines(lines, {
|
|
9180
|
+
key: `${prefix}-label:${node.id}`,
|
|
9181
|
+
role: `${role}-label`,
|
|
9182
|
+
target: node.id,
|
|
9183
|
+
x: box.x + box.width / 2,
|
|
9184
|
+
cy: box.y + box.height - labelHeight / 2,
|
|
9185
|
+
size: LABEL_SIZE,
|
|
9186
|
+
fill: theme.text
|
|
9187
|
+
})
|
|
9188
|
+
];
|
|
9189
|
+
}
|
|
9190
|
+
function crossMark(key, target, x, y, dir, stroke) {
|
|
9191
|
+
const cx = x - dir * 2.8;
|
|
9192
|
+
const h = 2.8;
|
|
9193
|
+
return {
|
|
9194
|
+
kind: "path",
|
|
9195
|
+
key,
|
|
9196
|
+
role: "message-head",
|
|
9197
|
+
target,
|
|
9198
|
+
d: `M${cx - h},${y - h} L${cx + h},${y + h} M${cx + h},${y - h} L${cx - h},${y + h}`,
|
|
9199
|
+
stroke,
|
|
9200
|
+
strokeWidth: 1.5
|
|
9201
|
+
};
|
|
9202
|
+
}
|
|
9203
|
+
var sequenceScene = ({ graph, theme }) => {
|
|
9204
|
+
const geo = sequenceGeometry(graph);
|
|
9205
|
+
const marks = [];
|
|
9206
|
+
for (const group of graph.groups) {
|
|
9207
|
+
const box = geo.boxes.get(group.id);
|
|
9208
|
+
if (!box) continue;
|
|
9209
|
+
const color = typeof group.data?.color === "string" ? group.data.color : void 0;
|
|
9210
|
+
marks.push(
|
|
9211
|
+
{ kind: "rect", key: `box:${group.id}`, role: "box", target: group.id, ...box, fill: color ?? "none", stroke: theme.groupStroke, strokeWidth: 1 },
|
|
9212
|
+
...textLines(displayLines(group.label), {
|
|
9213
|
+
key: `box-label:${group.id}`,
|
|
9214
|
+
role: "box-label",
|
|
9215
|
+
target: group.id,
|
|
9216
|
+
x: box.x + box.width / 2,
|
|
9217
|
+
cy: box.y + 4 + LABEL_SIZE * LINE_HEIGHT / 2,
|
|
9218
|
+
size: LABEL_SIZE,
|
|
9219
|
+
weight: 600,
|
|
9220
|
+
fill: theme.groupText
|
|
9221
|
+
})
|
|
9222
|
+
);
|
|
9223
|
+
}
|
|
9224
|
+
if (graph.title) {
|
|
9225
|
+
const lefts = [...[...geo.columns.values()].map((c) => c.x), ...[...geo.boxes.values()].map((b) => b.x)];
|
|
9226
|
+
const rights = [...[...geo.columns.values()].map((c) => c.x + c.width), ...[...geo.boxes.values()].map((b) => b.x + b.width)];
|
|
9227
|
+
const tops = [0, ...[...geo.boxes.values()].map((b) => b.y)];
|
|
9228
|
+
const minX = lefts.length ? Math.min(...lefts) : 0;
|
|
9229
|
+
const maxX = rights.length ? Math.max(...rights) : 240;
|
|
9230
|
+
marks.push({ kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: (minX + maxX) / 2, y: Math.min(...tops) - 38, text: graph.title, anchor: "middle", baseline: "middle", size: TITLE_SIZE, weight: 600, fill: theme.text });
|
|
9231
|
+
}
|
|
9232
|
+
[...geo.fragments].map((f, i) => ({ f, i })).sort((a, b) => a.f.depth - b.f.depth || a.i - b.i).forEach(({ f, i }) => {
|
|
9233
|
+
marks.push({ kind: "rect", key: `fragment:${i}`, role: "fragment", x: f.x, y: f.y, width: f.width, height: f.height, fill: "none", stroke: theme.mutedText, strokeWidth: 1.5 });
|
|
9234
|
+
const tabW = estimateTextWidth2(f.keyword, SMALL_SIZE) + 22;
|
|
9235
|
+
const tabH = SMALL_SIZE * LINE_HEIGHT + 4;
|
|
9236
|
+
marks.push(
|
|
9237
|
+
{
|
|
9238
|
+
kind: "path",
|
|
9239
|
+
key: `fragment-tab:${i}`,
|
|
9240
|
+
role: "fragment-tab",
|
|
9241
|
+
d: `M${f.x},${f.y} H${f.x + tabW} V${f.y + tabH * 0.6} L${f.x + tabW - 8},${f.y + tabH} H${f.x} Z`,
|
|
9242
|
+
fill: theme.groupFill,
|
|
9243
|
+
stroke: theme.mutedText,
|
|
9244
|
+
strokeWidth: 1.5
|
|
9245
|
+
},
|
|
9246
|
+
{ kind: "text", key: `fragment-keyword:${i}`, role: "fragment-keyword", x: f.x + 8, y: f.y + tabH / 2, text: f.keyword, anchor: "start", baseline: "middle", size: SMALL_SIZE, weight: 600, fill: theme.groupText }
|
|
9247
|
+
);
|
|
9248
|
+
if (f.text)
|
|
9249
|
+
marks.push({ kind: "text", key: `fragment-text:${i}`, role: "fragment-text", x: f.x + f.width / 2, y: f.y + 3, text: `[${f.text}]`, anchor: "middle", baseline: "top", size: SMALL_SIZE, weight: 600, fill: theme.text });
|
|
9250
|
+
f.dividers.forEach((d, j) => {
|
|
9251
|
+
marks.push({ kind: "line", key: `fragment-divider:${i}:${j}`, role: "fragment-divider", x1: f.x, y1: d.y, x2: f.x + f.width, y2: d.y, stroke: theme.mutedText, strokeWidth: 1.5, dash: "6 4" });
|
|
9252
|
+
if (d.text)
|
|
9253
|
+
marks.push({ kind: "text", key: `fragment-divider-text:${i}:${j}`, role: "fragment-text", x: f.x + f.width / 2, y: d.y + 3, text: `[${d.text}]`, anchor: "middle", baseline: "top", size: SMALL_SIZE, weight: 600, fill: theme.text });
|
|
9254
|
+
});
|
|
9255
|
+
});
|
|
9256
|
+
for (const col of geo.columns.values())
|
|
9257
|
+
marks.push({ kind: "line", key: `lifeline:${col.id}`, role: "lifeline", target: col.id, x1: col.center, y1: geo.lifelineTop, x2: col.center, y2: geo.lifelineBottom, stroke: theme.grid, strokeWidth: 1 });
|
|
9258
|
+
geo.activations.forEach(
|
|
9259
|
+
(a, i) => marks.push({ kind: "rect", key: `activation:${i}`, role: "activation", x: a.x, y: a.top, width: M2.activationWidth, height: Math.max(8, a.bottom - a.top), fill: theme.groupFill, stroke: theme.edge, strokeWidth: 1 })
|
|
9260
|
+
);
|
|
9261
|
+
for (const node of graph.nodes) {
|
|
9262
|
+
const col = geo.columns.get(node.id);
|
|
9263
|
+
if (!col) continue;
|
|
9264
|
+
marks.push(...participantMarks(node, { x: col.x, y: 0, width: col.width, height: M2.actorHeight }, false, theme));
|
|
9265
|
+
marks.push(...participantMarks(node, { x: col.x, y: geo.lifelineBottom, width: col.width, height: M2.actorHeight }, true, theme));
|
|
9266
|
+
}
|
|
9267
|
+
const noteColor = sceneColor(theme, NOTE_COLOR);
|
|
9268
|
+
geo.notes.forEach((n3, i) => {
|
|
9269
|
+
const box = { x: n3.x, y: n3.y, width: n3.width, height: n3.height };
|
|
9270
|
+
marks.push(
|
|
9271
|
+
{ kind: "rect", key: `note-bg:${i}`, role: "note", ...box, fill: theme.background },
|
|
9272
|
+
{ kind: "rect", key: `note-fill:${i}`, role: "note", ...box, fill: noteColor, opacity: 0.3 },
|
|
9273
|
+
{ kind: "rect", key: `note:${i}`, role: "note", ...box, fill: "none", stroke: noteColor, strokeWidth: 1 },
|
|
9274
|
+
...textLines(displayLines(n3.text), { key: `note-text:${i}`, role: "note-text", x: n3.x + n3.width / 2, cy: n3.y + n3.height / 2, size: LABEL_SIZE, fill: theme.text })
|
|
9275
|
+
);
|
|
9276
|
+
});
|
|
9277
|
+
const edges = new Map(graph.edges.map((e) => [e.id, e]));
|
|
9278
|
+
const autonumber = !!graph.data?.autonumber;
|
|
9279
|
+
geo.messages.forEach((row, index) => {
|
|
9280
|
+
const edge = edges.get(row.edgeId);
|
|
9281
|
+
if (!edge) return;
|
|
9282
|
+
const x1 = geo.columns.get(edge.source)?.center ?? 0;
|
|
9283
|
+
const x2 = geo.columns.get(edge.target)?.center ?? 0;
|
|
9284
|
+
const y = row.y;
|
|
9285
|
+
const stroke = theme.edge;
|
|
9286
|
+
const strokeWidth = edge.pattern === "thick" ? 3.5 : 1.5;
|
|
9287
|
+
const dash = dashFor(edge.pattern);
|
|
9288
|
+
const markerEnd = markerFor(edge.arrowEnd);
|
|
9289
|
+
const markerStart = markerFor(edge.arrowStart);
|
|
9290
|
+
const heads = { ...markerEnd ? { markerEnd } : {}, ...markerStart ? { markerStart } : {} };
|
|
9291
|
+
let endX;
|
|
9292
|
+
let endDir;
|
|
9293
|
+
let startDir;
|
|
9294
|
+
let endY = y;
|
|
9295
|
+
let startY = y;
|
|
9296
|
+
if (row.self) {
|
|
9297
|
+
endX = x1 + 4;
|
|
9298
|
+
endDir = -1;
|
|
9299
|
+
startDir = -1;
|
|
9300
|
+
endY = y + 10;
|
|
9301
|
+
startY = y - 10;
|
|
9302
|
+
marks.push({
|
|
9303
|
+
kind: "path",
|
|
9304
|
+
key: `message:${edge.id}`,
|
|
9305
|
+
role: "message",
|
|
9306
|
+
target: edge.id,
|
|
9307
|
+
d: `M${x1},${y - 10} H${x1 + 44} V${y + 10} H${x1 + 4}`,
|
|
9308
|
+
fill: "none",
|
|
9309
|
+
stroke,
|
|
9310
|
+
strokeWidth,
|
|
9311
|
+
...dash ? { dash } : {},
|
|
9312
|
+
...heads,
|
|
9313
|
+
box: { x: x1, y: y - 10, width: 44, height: 20 }
|
|
9314
|
+
});
|
|
9315
|
+
} else {
|
|
9316
|
+
endX = x2 + (x2 > x1 ? -2 : 2);
|
|
9317
|
+
endDir = x2 >= x1 ? 1 : -1;
|
|
9318
|
+
startDir = -endDir;
|
|
9319
|
+
marks.push({ kind: "line", key: `message:${edge.id}`, role: "message", target: edge.id, x1, y1: y, x2: endX, y2: y, stroke, strokeWidth, ...dash ? { dash } : {}, ...heads });
|
|
9320
|
+
}
|
|
9321
|
+
if (edge.arrowEnd === "arrow_cross") marks.push(crossMark(`message-cross-end:${edge.id}`, edge.id, endX, endY, endDir, stroke));
|
|
9322
|
+
if (edge.arrowStart === "arrow_cross") marks.push(crossMark(`message-cross-start:${edge.id}`, edge.id, x1, startY, startDir, stroke));
|
|
9323
|
+
if (autonumber)
|
|
9324
|
+
marks.push(
|
|
9325
|
+
{ kind: "circle", key: `number-dot:${edge.id}`, role: "message-number", target: edge.id, cx: x1, cy: y, r: 10, fill: stroke },
|
|
9326
|
+
{ kind: "text", key: `number:${edge.id}`, role: "message-number", target: edge.id, x: x1, y, text: String(index + 1), anchor: "middle", baseline: "middle", size: 11, weight: 600, fill: theme.background }
|
|
9327
|
+
);
|
|
9328
|
+
const label = edge.label ? displayLines(edge.label).join(" ") : "";
|
|
9329
|
+
if (label)
|
|
9330
|
+
marks.push({
|
|
9331
|
+
kind: "text",
|
|
9332
|
+
key: `message-label:${edge.id}`,
|
|
9333
|
+
role: "message-label",
|
|
9334
|
+
target: edge.id,
|
|
9335
|
+
x: row.self ? x1 + 52 + 4 : (x1 + x2) / 2,
|
|
9336
|
+
y: row.self ? y - 18 : y - 13,
|
|
9337
|
+
text: label,
|
|
9338
|
+
anchor: row.self ? "start" : "middle",
|
|
9339
|
+
baseline: "middle",
|
|
9340
|
+
size: LABEL_SIZE,
|
|
9341
|
+
fill: theme.text
|
|
9342
|
+
});
|
|
9343
|
+
});
|
|
9344
|
+
return marks;
|
|
9345
|
+
};
|
|
9346
|
+
|
|
9347
|
+
// src/canvas/mermaid/families/journey.ts
|
|
9348
|
+
var M3 = JOURNEY_METRICS;
|
|
9349
|
+
var TITLE_SIZE2 = 32;
|
|
9350
|
+
function actorColor(theme, slot) {
|
|
9351
|
+
return sceneColor(theme, M3.sectionColours + slot);
|
|
9352
|
+
}
|
|
9353
|
+
function wrapLines(text2, size, max) {
|
|
9354
|
+
const lines = [];
|
|
9355
|
+
for (const para of text2.replace(/<br\s*\/?>/gi, "\n").split("\n")) {
|
|
9356
|
+
let line4 = "";
|
|
9357
|
+
for (const word of para.split(/\s+/).filter(Boolean)) {
|
|
9358
|
+
const next = line4 ? `${line4} ${word}` : word;
|
|
9359
|
+
if (line4 && estimateTextWidth2(next, size) > max) {
|
|
9360
|
+
lines.push(line4);
|
|
9361
|
+
line4 = word;
|
|
9362
|
+
} else line4 = next;
|
|
9363
|
+
}
|
|
9364
|
+
lines.push(line4);
|
|
9365
|
+
}
|
|
9366
|
+
return lines;
|
|
9367
|
+
}
|
|
9368
|
+
function boxLabel(key, role, target, text2, box, fill) {
|
|
9369
|
+
let size = M3.fontSize;
|
|
9370
|
+
let lines = wrapLines(text2, size, box.width - 10);
|
|
9371
|
+
if (lines.length > 2) {
|
|
9372
|
+
size = 13;
|
|
9373
|
+
lines = wrapLines(text2, size, box.width - 8);
|
|
9374
|
+
}
|
|
9375
|
+
const lineHeight = size * 1.15;
|
|
9376
|
+
const max = Math.max(1, Math.floor(box.height / lineHeight));
|
|
9377
|
+
if (lines.length > max) lines = [...lines.slice(0, max - 1), `${lines[max - 1]}\u2026`];
|
|
9378
|
+
const top = box.y + box.height / 2 - lines.length * lineHeight / 2 + lineHeight / 2;
|
|
9379
|
+
return lines.map((line4, i) => ({
|
|
9380
|
+
kind: "text",
|
|
9381
|
+
key: `${key}:${i}`,
|
|
9382
|
+
role,
|
|
9383
|
+
target,
|
|
9384
|
+
x: box.x + box.width / 2,
|
|
9385
|
+
y: top + i * lineHeight,
|
|
9386
|
+
text: line4,
|
|
9387
|
+
anchor: "middle",
|
|
9388
|
+
baseline: "middle",
|
|
9389
|
+
size,
|
|
9390
|
+
fill
|
|
9391
|
+
}));
|
|
9392
|
+
}
|
|
9393
|
+
var journeyScene = ({ graph, theme }) => {
|
|
9394
|
+
const geo = journeyGeometry(graph);
|
|
9395
|
+
const marks = [];
|
|
9396
|
+
const ink = theme.mutedText;
|
|
9397
|
+
if (graph.title)
|
|
9398
|
+
marks.push({
|
|
9399
|
+
kind: "text",
|
|
9400
|
+
key: "title",
|
|
9401
|
+
role: "title",
|
|
9402
|
+
target: DIAGRAM_TITLE_TARGET,
|
|
9403
|
+
x: geo.title.x,
|
|
9404
|
+
y: geo.title.baseline + 7,
|
|
9405
|
+
text: graph.title,
|
|
9406
|
+
anchor: "start",
|
|
9407
|
+
baseline: "bottom",
|
|
9408
|
+
size: TITLE_SIZE2,
|
|
9409
|
+
weight: 700,
|
|
9410
|
+
fill: theme.text
|
|
9411
|
+
});
|
|
9412
|
+
for (const t of geo.tasks.values())
|
|
9413
|
+
marks.push({ kind: "line", key: `task-line:${t.id}`, role: "task-line", x1: t.face.x, y1: t.y, x2: t.face.x, y2: M3.lineBottom, stroke: theme.grid, strokeWidth: 1, dash: "4 2" });
|
|
9414
|
+
marks.push({
|
|
9415
|
+
kind: "line",
|
|
9416
|
+
key: "axis",
|
|
9417
|
+
role: "axis",
|
|
9418
|
+
x1: geo.axis.x1,
|
|
9419
|
+
y1: geo.axis.y,
|
|
9420
|
+
x2: geo.axis.x2,
|
|
9421
|
+
y2: geo.axis.y,
|
|
9422
|
+
stroke: theme.edge,
|
|
9423
|
+
strokeWidth: M3.axisWidth,
|
|
9424
|
+
markerEnd: "arrowclosed"
|
|
9425
|
+
});
|
|
9426
|
+
for (const l of geo.legend)
|
|
9427
|
+
marks.push(
|
|
9428
|
+
{ kind: "circle", key: `legend-dot:${l.name}`, role: "legend", cx: l.x, cy: l.y, r: M3.actorRadius, fill: actorColor(theme, l.colour), stroke: theme.nodeStroke, strokeWidth: 1 },
|
|
9429
|
+
{ kind: "text", key: `legend:${l.name}`, role: "legend", x: l.labelX, y: l.y, text: l.name, anchor: "start", baseline: "middle", size: M3.fontSize, fill: theme.text }
|
|
9430
|
+
);
|
|
9431
|
+
for (const t of geo.tasks.values()) {
|
|
9432
|
+
const { x, y } = t.face;
|
|
9433
|
+
const r = M3.faceRadius;
|
|
9434
|
+
marks.push(
|
|
9435
|
+
{ kind: "circle", key: `face:${t.id}`, role: "face", target: t.id, cx: x, cy: y, r, fill: theme.nodeFill, stroke: ink, strokeWidth: 2 },
|
|
9436
|
+
{ kind: "circle", key: `eye-l:${t.id}`, role: "face-eye", cx: x - r / 3, cy: y - r / 3, r: 1.5, fill: ink, stroke: ink, strokeWidth: 2 },
|
|
9437
|
+
{ kind: "circle", key: `eye-r:${t.id}`, role: "face-eye", cx: x + r / 3, cy: y - r / 3, r: 1.5, fill: ink, stroke: ink, strokeWidth: 2 }
|
|
9438
|
+
);
|
|
9439
|
+
if (t.score > 3)
|
|
9440
|
+
marks.push({ kind: "path", key: `mouth:${t.id}`, role: "face-mouth", d: `M${x + 7},${y + 2} A7,7 0 0 1 ${x - 7},${y + 2}`, fill: "none", stroke: ink, strokeWidth: 1, box: { x: x - 7, y: y + 2, width: 14, height: 7 } });
|
|
9441
|
+
else if (t.score < 3)
|
|
9442
|
+
marks.push({ kind: "path", key: `mouth:${t.id}`, role: "face-mouth", d: `M${x - 7},${y + 7} A7,7 0 0 1 ${x + 7},${y + 7}`, fill: "none", stroke: ink, strokeWidth: 1, box: { x: x - 7, y, width: 14, height: 7 } });
|
|
9443
|
+
else marks.push({ kind: "line", key: `mouth:${t.id}`, role: "face-mouth", x1: x - 5, y1: y + 7, x2: x + 5, y2: y + 7, stroke: ink, strokeWidth: 1 });
|
|
9444
|
+
}
|
|
9445
|
+
for (const group of graph.groups) {
|
|
9446
|
+
const s = geo.sections.get(group.id);
|
|
9447
|
+
if (!s) continue;
|
|
9448
|
+
marks.push({
|
|
9449
|
+
kind: "rect",
|
|
9450
|
+
key: `section:${s.id}`,
|
|
9451
|
+
role: "section",
|
|
9452
|
+
target: s.id,
|
|
9453
|
+
x: s.x,
|
|
9454
|
+
y: s.y,
|
|
9455
|
+
width: s.width,
|
|
9456
|
+
height: s.height,
|
|
9457
|
+
fill: sceneColor(theme, s.colour),
|
|
9458
|
+
stroke: theme.nodeStroke,
|
|
9459
|
+
strokeWidth: 1,
|
|
9460
|
+
radius: 3,
|
|
9461
|
+
// Mermaid draws no bar for an empty section; it is parked after the tasks, faded.
|
|
9462
|
+
...s.empty ? { dash: "4 3", opacity: 0.6 } : {}
|
|
9463
|
+
});
|
|
9464
|
+
marks.push(...boxLabel(`section-label:${s.id}`, "section-label", s.id, group.label, s, theme.paletteText).map((m) => s.empty ? { ...m, opacity: 0.6 } : m));
|
|
9465
|
+
}
|
|
9466
|
+
for (const node of graph.nodes) {
|
|
9467
|
+
const t = geo.tasks.get(node.id);
|
|
9468
|
+
if (!t) continue;
|
|
9469
|
+
marks.push({
|
|
9470
|
+
kind: "rect",
|
|
9471
|
+
key: `task:${t.id}`,
|
|
9472
|
+
role: "task",
|
|
9473
|
+
target: t.id,
|
|
9474
|
+
x: t.x,
|
|
9475
|
+
y: t.y,
|
|
9476
|
+
width: t.width,
|
|
9477
|
+
height: t.height,
|
|
9478
|
+
fill: sceneColor(theme, t.colour),
|
|
9479
|
+
stroke: theme.nodeStroke,
|
|
9480
|
+
strokeWidth: 1,
|
|
9481
|
+
radius: 3
|
|
9482
|
+
});
|
|
9483
|
+
marks.push(...boxLabel(`task-label:${t.id}`, "task-label", t.id, node.label ?? node.id, t, theme.paletteText));
|
|
9484
|
+
for (const a of t.actors)
|
|
9485
|
+
marks.push({ kind: "circle", key: `actor:${t.id}:${a.name}`, role: "actor", target: t.id, cx: a.x, cy: a.y, r: M3.actorRadius, fill: actorColor(theme, a.colour), stroke: theme.nodeStroke, strokeWidth: 1 });
|
|
9486
|
+
}
|
|
9487
|
+
return marks;
|
|
9488
|
+
};
|
|
9489
|
+
|
|
9490
|
+
// src/canvas/mermaid/families/quadrant.ts
|
|
9491
|
+
var M4 = QUADRANT_METRICS;
|
|
9492
|
+
var QUADRANT_TINT = 0.18;
|
|
9493
|
+
var quadrantScene = ({ graph, theme }) => {
|
|
9494
|
+
const geo = quadrantGeometry(graph);
|
|
9495
|
+
const marks = [];
|
|
9496
|
+
const groups = new Map(graph.groups.map((g) => [g.id, g]));
|
|
9497
|
+
for (const q of geo.quadrants) {
|
|
9498
|
+
const group = groups.get(q.id);
|
|
9499
|
+
marks.push({ kind: "rect", key: `quadrant-fill:${q.id}`, role: "quadrant-fill", x: q.x, y: q.y, width: q.width, height: q.height, fill: sceneColor(theme, q.n - 1), opacity: QUADRANT_TINT });
|
|
9500
|
+
marks.push({ kind: "rect", key: `quadrant:${q.id}`, role: "quadrant", ...group ? { target: q.id } : {}, x: q.x, y: q.y, width: q.width, height: q.height, fill: "transparent" });
|
|
9501
|
+
}
|
|
9502
|
+
for (const q of geo.quadrants) {
|
|
9503
|
+
const group = groups.get(q.id);
|
|
9504
|
+
if (!group || group.data?.placeholder || !group.label) continue;
|
|
9505
|
+
marks.push({
|
|
9506
|
+
kind: "text",
|
|
9507
|
+
key: `quadrant-label:${q.id}`,
|
|
9508
|
+
role: "quadrant-label",
|
|
9509
|
+
target: q.id,
|
|
9510
|
+
x: q.labelX,
|
|
9511
|
+
y: q.labelY,
|
|
9512
|
+
text: group.label,
|
|
9513
|
+
anchor: "middle",
|
|
9514
|
+
baseline: q.labelBaseline,
|
|
9515
|
+
size: M4.quadrantLabelFontSize,
|
|
9516
|
+
fill: theme.text
|
|
9517
|
+
});
|
|
9518
|
+
}
|
|
9519
|
+
geo.borders.forEach(
|
|
9520
|
+
(b, i) => marks.push({
|
|
9521
|
+
kind: "line",
|
|
9522
|
+
key: `border:${i}`,
|
|
9523
|
+
role: b.external ? "border" : "divider",
|
|
9524
|
+
x1: b.x1,
|
|
9525
|
+
y1: b.y1,
|
|
9526
|
+
x2: b.x2,
|
|
9527
|
+
y2: b.y2,
|
|
9528
|
+
stroke: theme.nodeStroke,
|
|
9529
|
+
strokeWidth: b.external ? M4.externalBorderWidth : M4.internalBorderWidth
|
|
9530
|
+
})
|
|
9531
|
+
);
|
|
9532
|
+
for (const l of geo.axisLabels)
|
|
9533
|
+
marks.push({
|
|
9534
|
+
kind: "text",
|
|
9535
|
+
key: `axis:${l.key}`,
|
|
9536
|
+
role: "axis-label",
|
|
9537
|
+
x: l.x,
|
|
9538
|
+
y: l.y,
|
|
9539
|
+
text: l.text,
|
|
9540
|
+
anchor: l.anchor,
|
|
9541
|
+
baseline: "top",
|
|
9542
|
+
size: l.rotation ? M4.yAxisLabelFontSize : M4.xAxisLabelFontSize,
|
|
9543
|
+
fill: theme.text,
|
|
9544
|
+
...l.rotation ? { rotate: l.rotation } : {}
|
|
9545
|
+
});
|
|
9546
|
+
if (geo.title)
|
|
9547
|
+
marks.push({ kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: geo.title.x, y: geo.title.y, text: geo.title.text, anchor: "middle", baseline: "top", size: M4.titleFontSize, fill: theme.text });
|
|
9548
|
+
for (const p of geo.points) {
|
|
9549
|
+
const fill = p.color ?? sceneColor(theme, 0);
|
|
9550
|
+
const strokeWidth = p.strokeWidth ? parseFloat(p.strokeWidth) : 0;
|
|
9551
|
+
marks.push({
|
|
9552
|
+
kind: "circle",
|
|
9553
|
+
key: `point:${p.id}`,
|
|
9554
|
+
role: "point",
|
|
9555
|
+
target: p.id,
|
|
9556
|
+
cx: p.cx,
|
|
9557
|
+
cy: p.cy,
|
|
9558
|
+
r: p.radius,
|
|
9559
|
+
fill,
|
|
9560
|
+
...Number.isFinite(strokeWidth) && strokeWidth > 0 ? { stroke: p.strokeColor ?? fill, strokeWidth } : {}
|
|
9561
|
+
});
|
|
9562
|
+
marks.push({
|
|
9563
|
+
kind: "text",
|
|
9564
|
+
key: `point-label:${p.id}`,
|
|
9565
|
+
role: "point-label",
|
|
9566
|
+
target: p.id,
|
|
9567
|
+
x: p.cx,
|
|
9568
|
+
y: p.cy + M4.pointTextPadding,
|
|
9569
|
+
text: p.label.replace(/<br\s*\/?>/gi, " "),
|
|
9570
|
+
anchor: "middle",
|
|
9571
|
+
baseline: "top",
|
|
9572
|
+
size: M4.pointLabelFontSize,
|
|
9573
|
+
fill: theme.text
|
|
9574
|
+
});
|
|
9575
|
+
}
|
|
9576
|
+
return marks;
|
|
9577
|
+
};
|
|
9578
|
+
|
|
9579
|
+
// src/canvas/mermaid/families/gitgraph.ts
|
|
9580
|
+
var M5 = GIT_METRICS;
|
|
9581
|
+
function rot([dx, dy], deg) {
|
|
9582
|
+
const a = deg * Math.PI / 180;
|
|
9583
|
+
const c = Math.cos(a);
|
|
9584
|
+
const s = Math.sin(a);
|
|
9585
|
+
return [dx * c - dy * s, dx * s + dy * c];
|
|
9586
|
+
}
|
|
9587
|
+
var polygon = (points) => `M${points.map(([x, y]) => `${round2(x)},${round2(y)}`).join(" L")} Z`;
|
|
9588
|
+
var round2 = (v) => Math.round(v * 100) / 100;
|
|
9589
|
+
function boxOf(points) {
|
|
9590
|
+
const xs = points.map((p) => p[0]);
|
|
9591
|
+
const ys = points.map((p) => p[1]);
|
|
9592
|
+
const x = Math.min(...xs);
|
|
9593
|
+
const y = Math.min(...ys);
|
|
9594
|
+
return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
|
|
9595
|
+
}
|
|
9596
|
+
function arrowBox(d) {
|
|
9597
|
+
const points = [];
|
|
9598
|
+
for (const [, cmd, args] of d.matchAll(/([MLA])([^MLA]*)/g)) {
|
|
9599
|
+
const nums = (args.match(/-?\d+(?:\.\d+)?(?:e-?\d+)?/gi) ?? []).map(Number);
|
|
9600
|
+
if (cmd === "A") {
|
|
9601
|
+
for (let i = 0; i + 6 < nums.length; i += 7) points.push([nums[i + 5], nums[i + 6]]);
|
|
9602
|
+
} else for (let i = 0; i + 1 < nums.length; i += 2) points.push([nums[i], nums[i + 1]]);
|
|
9603
|
+
}
|
|
9604
|
+
return points.length ? boxOf(points) : { x: 0, y: 0, width: 0, height: 0 };
|
|
9605
|
+
}
|
|
9606
|
+
function commitSymbol(c, theme) {
|
|
9607
|
+
const color = sceneColor(theme, c.color);
|
|
9608
|
+
const base = { target: c.id };
|
|
9609
|
+
switch (c.symbol) {
|
|
9610
|
+
case "HIGHLIGHT":
|
|
9611
|
+
return [
|
|
9612
|
+
{ kind: "rect", key: `commit:${c.id}`, role: "commit", ...base, x: c.x - 10, y: c.y - 10, width: 20, height: 20, fill: theme.text, stroke: theme.text },
|
|
9613
|
+
{ kind: "rect", key: `commit-inner:${c.id}`, role: "commit-inner", ...base, x: c.x - 6, y: c.y - 6, width: 12, height: 12, fill: color, stroke: color }
|
|
9614
|
+
];
|
|
9615
|
+
case "CHERRY_PICK":
|
|
9616
|
+
return [
|
|
9617
|
+
{ kind: "circle", key: `commit:${c.id}`, role: "commit", ...base, cx: c.x, cy: c.y, r: M5.commitRadius, fill: theme.text },
|
|
9618
|
+
{ kind: "circle", key: `cherry-l:${c.id}`, role: "cherry", ...base, cx: c.x - 3, cy: c.y + 2, r: 2.75, fill: theme.background },
|
|
9619
|
+
{ kind: "circle", key: `cherry-r:${c.id}`, role: "cherry", ...base, cx: c.x + 3, cy: c.y + 2, r: 2.75, fill: theme.background },
|
|
9620
|
+
{
|
|
9621
|
+
kind: "path",
|
|
9622
|
+
key: `cherry-stem:${c.id}`,
|
|
9623
|
+
role: "cherry-stem",
|
|
9624
|
+
...base,
|
|
9625
|
+
d: `M${c.x + 3},${c.y + 1} L${c.x},${c.y - 5} M${c.x - 3},${c.y + 1} L${c.x},${c.y - 5}`,
|
|
9626
|
+
fill: "none",
|
|
9627
|
+
stroke: theme.background
|
|
9628
|
+
}
|
|
9629
|
+
];
|
|
9630
|
+
default: {
|
|
9631
|
+
const marks = [{ kind: "circle", key: `commit:${c.id}`, role: "commit", ...base, cx: c.x, cy: c.y, r: M5.commitRadius, fill: color, stroke: color }];
|
|
9632
|
+
if (c.symbol === "MERGE")
|
|
9633
|
+
marks.push({ kind: "circle", key: `commit-inner:${c.id}`, role: "commit-inner", ...base, cx: c.x, cy: c.y, r: 6, fill: theme.background, stroke: theme.background });
|
|
9634
|
+
if (c.symbol === "REVERSE")
|
|
9635
|
+
marks.push({
|
|
9636
|
+
kind: "path",
|
|
9637
|
+
key: `commit-reverse:${c.id}`,
|
|
9638
|
+
role: "commit-reverse",
|
|
9639
|
+
...base,
|
|
9640
|
+
d: `M${c.x - 5},${c.y - 5} L${c.x + 5},${c.y + 5} M${c.x - 5},${c.y + 5} L${c.x + 5},${c.y - 5}`,
|
|
9641
|
+
fill: "none",
|
|
9642
|
+
stroke: theme.background,
|
|
9643
|
+
strokeWidth: 3
|
|
9644
|
+
});
|
|
9645
|
+
return marks;
|
|
9646
|
+
}
|
|
9647
|
+
}
|
|
9648
|
+
}
|
|
9649
|
+
function commitLabel(c, text2, direction, theme) {
|
|
9650
|
+
const w = estimateTextWidth(text2, M5.labelFontSize);
|
|
9651
|
+
const anchor = direction === "LR" ? [1 - 0.026 * w, 18.1 - 0.0136 * w] : [-14.9, 9.2];
|
|
9652
|
+
const ax = c.x + anchor[0];
|
|
9653
|
+
const ay = c.y + anchor[1];
|
|
9654
|
+
const corners = [[-w - 4, -7], [0, -7], [0, 7], [-w - 4, 7]].map((p) => {
|
|
9655
|
+
const [dx, dy] = rot(p, -45);
|
|
9656
|
+
return [ax + dx, ay + dy];
|
|
9657
|
+
});
|
|
9658
|
+
const [tx, ty] = rot([-2, 0], -45);
|
|
9659
|
+
return [
|
|
9660
|
+
{ kind: "path", key: `label-bg:${c.id}`, role: "commit-label-bg", target: c.id, d: polygon(corners), fill: theme.edgeLabelBackground, opacity: 0.5 },
|
|
9661
|
+
{ kind: "text", key: `label:${c.id}`, role: "commit-label", target: c.id, x: ax + tx, y: ay + ty, text: text2, anchor: "end", baseline: "middle", size: M5.labelFontSize, fill: theme.text, rotate: -45 }
|
|
9662
|
+
];
|
|
9663
|
+
}
|
|
9664
|
+
function commitTag(c, text2, index, direction, theme) {
|
|
9665
|
+
const w = estimateTextWidth(text2, M5.labelFontSize);
|
|
9666
|
+
const h2 = M5.labelTextHeight / 2;
|
|
9667
|
+
const key = `${c.id}:${index}`;
|
|
9668
|
+
let points;
|
|
9669
|
+
let hole;
|
|
9670
|
+
let label;
|
|
9671
|
+
let rotate;
|
|
9672
|
+
if (direction === "LR") {
|
|
9673
|
+
const ly = -19.2 - index * 20;
|
|
9674
|
+
const local = [
|
|
9675
|
+
[-w / 2 - 12, ly + 2],
|
|
9676
|
+
[-w / 2 - 12, ly - 2],
|
|
9677
|
+
[-w / 2 - 4, ly - h2 - 2],
|
|
9678
|
+
[w / 2 + 4, ly - h2 - 2],
|
|
9679
|
+
[w / 2 + 4, ly + h2 + 2],
|
|
9680
|
+
[-w / 2 - 4, ly + h2 + 2]
|
|
9681
|
+
];
|
|
9682
|
+
points = local.map(([x, y]) => [c.x + x, c.y + y]);
|
|
9683
|
+
hole = [c.x - w / 2 - 8, c.y + ly];
|
|
9684
|
+
label = [c.x, c.y + ly];
|
|
9685
|
+
} else {
|
|
9686
|
+
const ox = c.x + 12;
|
|
9687
|
+
const oy = c.y + 2 + index * 20;
|
|
9688
|
+
const place2 = (p) => {
|
|
9689
|
+
const [dx, dy] = rot(p, 45);
|
|
9690
|
+
return [ox + dx, oy + dy];
|
|
9691
|
+
};
|
|
9692
|
+
points = [[0, 2], [0, -2], [10, -h2 - 2], [14 + w, -h2 - 2], [14 + w, h2 + 2], [10, h2 + 2]].map(place2);
|
|
9693
|
+
hole = place2([2, 0]);
|
|
9694
|
+
label = place2([12 + w / 2, 0]);
|
|
9695
|
+
rotate = 45;
|
|
9696
|
+
}
|
|
9697
|
+
return [
|
|
9698
|
+
{ kind: "path", key: `tag:${key}`, role: "tag", target: c.id, d: polygon(points), fill: theme.groupFill, stroke: theme.groupStroke },
|
|
9699
|
+
{ kind: "circle", key: `tag-hole:${key}`, role: "tag-hole", target: c.id, cx: hole[0], cy: hole[1], r: 1.5, fill: theme.text },
|
|
9700
|
+
{
|
|
9701
|
+
kind: "text",
|
|
9702
|
+
key: `tag-label:${key}`,
|
|
9703
|
+
role: "tag-label",
|
|
9704
|
+
target: c.id,
|
|
9705
|
+
x: label[0],
|
|
9706
|
+
y: label[1],
|
|
9707
|
+
text: text2,
|
|
9708
|
+
anchor: "middle",
|
|
9709
|
+
baseline: "middle",
|
|
9710
|
+
size: M5.labelFontSize,
|
|
9711
|
+
fill: theme.text,
|
|
9712
|
+
...rotate !== void 0 ? { rotate } : {}
|
|
9713
|
+
}
|
|
9714
|
+
];
|
|
9715
|
+
}
|
|
9716
|
+
var gitGraphScene = ({ graph, theme }) => {
|
|
9717
|
+
const geo = gitGraphGeometry(graph);
|
|
9718
|
+
const marks = [];
|
|
9719
|
+
for (const lane of geo.lanes) {
|
|
9720
|
+
const { x1, y1, x2, y2 } = lane.line;
|
|
9721
|
+
marks.push({ kind: "line", key: `lane:${lane.branch}`, role: "lane", x1, y1, x2, y2, stroke: theme.grid, strokeWidth: 1, dash: "2 2" });
|
|
9722
|
+
}
|
|
9723
|
+
for (const edge of graph.edges) {
|
|
9724
|
+
const arrow = geo.arrows.get(edge.id);
|
|
9725
|
+
if (!arrow) continue;
|
|
9726
|
+
marks.push({
|
|
9727
|
+
kind: "path",
|
|
9728
|
+
key: `arrow:${edge.id}`,
|
|
9729
|
+
role: "parent-link",
|
|
9730
|
+
target: edge.id,
|
|
9731
|
+
d: arrow.path,
|
|
9732
|
+
fill: "none",
|
|
9733
|
+
stroke: sceneColor(theme, arrow.color),
|
|
9734
|
+
strokeWidth: 8,
|
|
9735
|
+
box: arrowBox(arrow.path)
|
|
9736
|
+
});
|
|
9737
|
+
}
|
|
9738
|
+
const groups = new Map(graph.groups.map((g) => [g.id, g]));
|
|
9739
|
+
for (const lane of geo.lanes) {
|
|
9740
|
+
const group = groups.get(lane.branch);
|
|
9741
|
+
if (!group) continue;
|
|
9742
|
+
const { x, y, width, height } = lane.label;
|
|
9743
|
+
const color = sceneColor(theme, lane.color);
|
|
9744
|
+
marks.push(
|
|
9745
|
+
{ kind: "rect", key: `branch:${lane.branch}`, role: "branch", target: lane.branch, x, y, width, height, fill: color, radius: 4 },
|
|
9746
|
+
{
|
|
9747
|
+
kind: "text",
|
|
9748
|
+
key: `branch-label:${lane.branch}`,
|
|
9749
|
+
role: "branch-label",
|
|
9750
|
+
target: lane.branch,
|
|
9751
|
+
x: x + width / 2,
|
|
9752
|
+
y: y + height / 2,
|
|
9753
|
+
text: group.label || group.id,
|
|
9754
|
+
anchor: "middle",
|
|
9755
|
+
baseline: "middle",
|
|
9756
|
+
size: M5.branchFontSize,
|
|
9757
|
+
fill: theme.paletteText
|
|
9758
|
+
}
|
|
9759
|
+
);
|
|
9760
|
+
}
|
|
9761
|
+
for (const node of graph.nodes) {
|
|
9762
|
+
const c = geo.commits.get(node.id);
|
|
9763
|
+
if (!c) continue;
|
|
9764
|
+
marks.push(...commitSymbol(c, theme));
|
|
9765
|
+
if (c.label !== void 0) marks.push(...commitLabel(c, c.label, geo.direction, theme));
|
|
9766
|
+
c.tags.forEach((t, i) => marks.push(...commitTag(c, t, i, geo.direction, theme)));
|
|
9767
|
+
}
|
|
9768
|
+
return marks;
|
|
9769
|
+
};
|
|
9770
|
+
|
|
9771
|
+
// src/canvas/mermaid/families/mindmap.ts
|
|
9772
|
+
var M6 = MINDMAP_METRICS;
|
|
9773
|
+
var round3 = (v) => Math.round(v * 100) / 100;
|
|
9774
|
+
function displayLabel(label) {
|
|
9775
|
+
let text2 = label;
|
|
9776
|
+
if (text2.startsWith("`") && text2.endsWith("`")) text2 = text2.slice(1, -1);
|
|
9777
|
+
return text2.replace(/<br\s*\/?>/gi, "\n").replace(/#quot;/g, '"').replace(/#(\d+);/g, (_, n3) => String.fromCharCode(Number(n3)));
|
|
9778
|
+
}
|
|
9779
|
+
function arcOutline(x, y, arcs) {
|
|
9780
|
+
let px2 = x;
|
|
9781
|
+
let py = y;
|
|
9782
|
+
const xs = [x];
|
|
9783
|
+
const ys = [y];
|
|
9784
|
+
const parts = [`M${round3(x)},${round3(y)}`];
|
|
9785
|
+
for (const a of arcs) {
|
|
9786
|
+
parts.push(`a${round3(a.rx)},${round3(a.ry)} ${a.rotation} ${a.large},${a.sweep} ${round3(a.dx)},${round3(a.dy)}`);
|
|
9787
|
+
for (const [sx, sy] of sampleArc(px2, py, a)) {
|
|
9788
|
+
xs.push(sx);
|
|
9789
|
+
ys.push(sy);
|
|
9790
|
+
}
|
|
9791
|
+
px2 += a.dx;
|
|
9792
|
+
py += a.dy;
|
|
9793
|
+
}
|
|
9794
|
+
parts.push(`H${round3(x)} V${round3(y)} Z`);
|
|
9795
|
+
const bx = Math.min(...xs);
|
|
9796
|
+
const by = Math.min(...ys);
|
|
9797
|
+
return { d: parts.join(" "), box: { x: bx, y: by, width: Math.max(...xs) - bx, height: Math.max(...ys) - by } };
|
|
9798
|
+
}
|
|
9799
|
+
function sampleArc(x1, y1, a) {
|
|
9800
|
+
const x2 = x1 + a.dx;
|
|
9801
|
+
const y2 = y1 + a.dy;
|
|
9802
|
+
let rx = Math.abs(a.rx);
|
|
9803
|
+
let ry = Math.abs(a.ry);
|
|
9804
|
+
if (!rx || !ry || a.dx === 0 && a.dy === 0) return [[x2, y2]];
|
|
9805
|
+
const phi = a.rotation * Math.PI / 180;
|
|
9806
|
+
const cos = Math.cos(phi);
|
|
9807
|
+
const sin = Math.sin(phi);
|
|
9808
|
+
const hx = (x1 - x2) / 2;
|
|
9809
|
+
const hy = (y1 - y2) / 2;
|
|
9810
|
+
const x1p = cos * hx + sin * hy;
|
|
9811
|
+
const y1p = -sin * hx + cos * hy;
|
|
9812
|
+
const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
|
|
9813
|
+
if (lambda > 1) {
|
|
9814
|
+
rx *= Math.sqrt(lambda);
|
|
9815
|
+
ry *= Math.sqrt(lambda);
|
|
9816
|
+
}
|
|
9817
|
+
const num4 = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
|
|
9818
|
+
const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
|
|
9819
|
+
const k = (a.large === a.sweep ? -1 : 1) * Math.sqrt(Math.max(0, num4 / den));
|
|
9820
|
+
const cxp = k * rx * y1p / ry;
|
|
9821
|
+
const cyp = -k * ry * x1p / rx;
|
|
9822
|
+
const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;
|
|
9823
|
+
const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
|
|
9824
|
+
const angle = (ux, uy, vx, vy) => Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);
|
|
9825
|
+
const t1 = angle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
|
|
9826
|
+
let dt = angle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
|
|
9827
|
+
if (!a.sweep && dt > 0) dt -= 2 * Math.PI;
|
|
9828
|
+
if (a.sweep && dt < 0) dt += 2 * Math.PI;
|
|
9829
|
+
const out = [];
|
|
9830
|
+
const steps = 24;
|
|
9831
|
+
for (let i = 1; i <= steps; i++) {
|
|
9832
|
+
const t = t1 + dt * i / steps;
|
|
9833
|
+
out.push([cx + rx * Math.cos(t) * cos - ry * Math.sin(t) * sin, cy + rx * Math.cos(t) * sin + ry * Math.sin(t) * cos]);
|
|
9834
|
+
}
|
|
9835
|
+
return out;
|
|
9836
|
+
}
|
|
9837
|
+
var arc = (rx, ry, rotation, sweep, dx, dy) => ({ rx, ry, rotation, large: 0, sweep, dx, dy });
|
|
9838
|
+
function topicShape(t, x0, y0, fill, underline) {
|
|
9839
|
+
const { width: w, height: h } = t;
|
|
9840
|
+
const base = { target: t.id, role: "topic" };
|
|
9841
|
+
const key = `topic:${t.id}`;
|
|
9842
|
+
switch (t.form) {
|
|
9843
|
+
case "circle":
|
|
9844
|
+
return [{ kind: "circle", key, ...base, cx: x0 + w / 2, cy: y0 + h / 2, r: w / 2, fill }];
|
|
9845
|
+
case "square":
|
|
9846
|
+
return [{ kind: "rect", key, ...base, x: x0, y: y0, width: w, height: h, fill }];
|
|
9847
|
+
case "rounded":
|
|
9848
|
+
return [{ kind: "rect", key, ...base, x: x0, y: y0, width: w, height: h, fill, radius: 5 }];
|
|
9849
|
+
case "hexagon": {
|
|
9850
|
+
const m = h / 4;
|
|
9851
|
+
const pts = [
|
|
9852
|
+
[m, h],
|
|
9853
|
+
[w - m, h],
|
|
9854
|
+
[w, h / 2],
|
|
9855
|
+
[w - m, 0],
|
|
9856
|
+
[m, 0],
|
|
9857
|
+
[0, h / 2]
|
|
9858
|
+
];
|
|
9859
|
+
return [{ kind: "path", key, ...base, d: `M${pts.map(([x, y]) => `${round3(x0 + x)},${round3(y0 + y)}`).join(" L")} Z`, fill }];
|
|
9860
|
+
}
|
|
9861
|
+
case "cloud": {
|
|
9862
|
+
const r1 = 0.15 * w;
|
|
9863
|
+
const r22 = 0.25 * w;
|
|
9864
|
+
const r3 = 0.35 * w;
|
|
9865
|
+
const r4 = 0.2 * w;
|
|
9866
|
+
const { d, box } = arcOutline(x0, y0, [
|
|
9867
|
+
arc(r1, r1, 0, 1, w * 0.25, -w * 0.1),
|
|
9868
|
+
arc(r3, r3, 1, 1, w * 0.4, -w * 0.1),
|
|
9869
|
+
arc(r22, r22, 1, 1, w * 0.35, w * 0.2),
|
|
9870
|
+
arc(r1, r1, 1, 1, w * 0.15, h * 0.35),
|
|
9871
|
+
arc(r4, r4, 1, 1, -w * 0.15, h * 0.65),
|
|
9872
|
+
arc(r22, r1, 1, 1, -w * 0.25, w * 0.15),
|
|
9873
|
+
arc(r3, r3, 1, 1, -w * 0.5, 0),
|
|
9874
|
+
arc(r1, r1, 1, 1, -w * 0.25, -w * 0.15),
|
|
9875
|
+
arc(r1, r1, 1, 1, -w * 0.1, -h * 0.35),
|
|
9876
|
+
arc(r4, r4, 1, 1, w * 0.1, -h * 0.65)
|
|
9877
|
+
]);
|
|
9878
|
+
return [{ kind: "path", key, ...base, d, fill, box }];
|
|
9879
|
+
}
|
|
9880
|
+
case "bang": {
|
|
9881
|
+
const r = 0.15 * w;
|
|
9882
|
+
const { d, box } = arcOutline(x0, y0, [
|
|
9883
|
+
arc(r, r, 1, 0, w * 0.25, -h * 0.1),
|
|
9884
|
+
arc(r, r, 1, 0, w * 0.25, 0),
|
|
9885
|
+
arc(r, r, 1, 0, w * 0.25, 0),
|
|
9886
|
+
arc(r, r, 1, 0, w * 0.25, h * 0.1),
|
|
9887
|
+
arc(r, r, 1, 0, w * 0.15, h * 0.33),
|
|
9888
|
+
arc(r * 0.8, r * 0.8, 1, 0, 0, h * 0.34),
|
|
9889
|
+
arc(r, r, 1, 0, -w * 0.15, h * 0.33),
|
|
9890
|
+
arc(r, r, 1, 0, -w * 0.25, h * 0.15),
|
|
9891
|
+
arc(r, r, 1, 0, -w * 0.25, 0),
|
|
9892
|
+
arc(r, r, 1, 0, -w * 0.25, 0),
|
|
9893
|
+
arc(r, r, 1, 0, -w * 0.25, -h * 0.15),
|
|
9894
|
+
arc(r, r, 1, 0, -w * 0.1, -h * 0.33),
|
|
9895
|
+
arc(r * 0.8, r * 0.8, 1, 0, 0, -h * 0.34),
|
|
9896
|
+
arc(r, r, 1, 0, w * 0.1, -h * 0.33)
|
|
9897
|
+
]);
|
|
9898
|
+
return [{ kind: "path", key, ...base, d, fill, box }];
|
|
9899
|
+
}
|
|
9900
|
+
default:
|
|
9901
|
+
return [
|
|
9902
|
+
{ kind: "rect", key, ...base, x: x0, y: y0, width: w, height: h, fill, radius: 5 },
|
|
9903
|
+
{ kind: "line", key: `underline:${t.id}`, role: "topic-underline", target: t.id, x1: x0, y1: y0 + h, x2: x0 + w, y2: y0 + h, stroke: underline, strokeWidth: 3 }
|
|
9904
|
+
];
|
|
9905
|
+
}
|
|
9906
|
+
}
|
|
9907
|
+
function topicColors(t, theme) {
|
|
9908
|
+
const underline = sceneColor(theme, t.section + Math.floor(theme.palette.length / 2));
|
|
9909
|
+
if (t.section < 0) return { fill: theme.nodeStroke, label: theme.background, underline };
|
|
9910
|
+
return { fill: sceneColor(theme, t.section), label: theme.paletteText, underline };
|
|
9911
|
+
}
|
|
9912
|
+
function iconGlyph(icon) {
|
|
9913
|
+
const name = icon.trim().split(/\s+/).pop() ?? "";
|
|
9914
|
+
const word = name.replace(/^(fa[a-z]?|mdi|bi|icon)-/, "");
|
|
9915
|
+
return (word[0] ?? "?").toUpperCase();
|
|
9916
|
+
}
|
|
9917
|
+
var mindmapScene = ({ graph, theme }) => {
|
|
9918
|
+
const geo = mindmapGeometry(graph);
|
|
9919
|
+
const marks = [];
|
|
9920
|
+
for (const e of geo.edges) {
|
|
9921
|
+
const a = geo.topics.get(e.source);
|
|
9922
|
+
const b = geo.topics.get(e.target);
|
|
9923
|
+
if (!a || !b) continue;
|
|
9924
|
+
marks.push({ kind: "line", key: `branch:${e.edgeId}`, role: "branch", x1: a.x, y1: a.y, x2: b.x, y2: b.y, stroke: sceneColor(theme, e.section), strokeWidth: e.width });
|
|
9925
|
+
}
|
|
9926
|
+
for (const node of graph.nodes) {
|
|
9927
|
+
const t = geo.topics.get(node.id);
|
|
9928
|
+
if (!t) continue;
|
|
9929
|
+
const x0 = t.x - t.width / 2;
|
|
9930
|
+
const y0 = t.y - t.height / 2;
|
|
9931
|
+
const colors = topicColors(t, theme);
|
|
9932
|
+
marks.push(...topicShape(t, x0, y0, colors.fill, colors.underline));
|
|
9933
|
+
const top = t.y - t.lines.length * M6.lineHeight / 2;
|
|
9934
|
+
t.lines.forEach((line4, i) => {
|
|
9935
|
+
const text2 = displayLabel(line4);
|
|
9936
|
+
if (!text2) return;
|
|
9937
|
+
marks.push({
|
|
9938
|
+
kind: "text",
|
|
9939
|
+
key: `label:${t.id}:${i}`,
|
|
9940
|
+
role: "topic-label",
|
|
9941
|
+
target: t.id,
|
|
9942
|
+
x: t.x,
|
|
9943
|
+
y: top + (i + 0.5) * M6.lineHeight,
|
|
9944
|
+
text: text2,
|
|
9945
|
+
anchor: "middle",
|
|
9946
|
+
baseline: "middle",
|
|
9947
|
+
size: M6.fontSize,
|
|
9948
|
+
fill: colors.label
|
|
9949
|
+
});
|
|
9950
|
+
});
|
|
9951
|
+
const icon = typeof node.data?.icon === "string" ? node.data.icon : void 0;
|
|
9952
|
+
if (icon) {
|
|
9953
|
+
marks.push(
|
|
9954
|
+
{ kind: "circle", key: `icon:${t.id}`, role: "icon", target: t.id, cx: x0, cy: y0, r: 11, fill: colors.fill, stroke: theme.background, strokeWidth: 2 },
|
|
9955
|
+
{ kind: "text", key: `icon-glyph:${t.id}`, role: "icon", target: t.id, x: x0, y: y0, text: iconGlyph(icon), anchor: "middle", baseline: "middle", size: 12, fill: colors.label }
|
|
9956
|
+
);
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
return marks;
|
|
9960
|
+
};
|
|
9961
|
+
|
|
9962
|
+
// src/canvas/mermaid/families/c4.ts
|
|
9963
|
+
var C4_COLORS = {
|
|
9964
|
+
person: { bg: "#08427b", border: "#073b6f" },
|
|
9965
|
+
system: { bg: "#1168bd", border: "#3c7fc0" },
|
|
9966
|
+
container: { bg: "#438dd5", border: "#3c7fc0" },
|
|
9967
|
+
component: { bg: "#85bbf0", border: "#78a8d8" },
|
|
9968
|
+
external_person: { bg: "#686868", border: "#8a8a8a" },
|
|
9969
|
+
external_system: { bg: "#999999", border: "#8a8a8a" },
|
|
9970
|
+
external_container: { bg: "#b3b3b3", border: "#a6a6a6" },
|
|
9971
|
+
external_component: { bg: "#cccccc", border: "#bfbfbf" }
|
|
9972
|
+
};
|
|
9973
|
+
var C4_ELEMENT_FG = "#ffffff";
|
|
9974
|
+
var NAME_SIZE = 14;
|
|
9975
|
+
var TYPE_SIZE = 10.5;
|
|
9976
|
+
var DESCR_SIZE = 11.48;
|
|
9977
|
+
var LINE_HEIGHT2 = 1.15;
|
|
9978
|
+
var SECTION_GAP = 3;
|
|
9979
|
+
var REL_FONT = 12;
|
|
9980
|
+
var REL_LINE = 14;
|
|
9981
|
+
var REL_GAP = 3;
|
|
9982
|
+
function colorsOf(type) {
|
|
9983
|
+
return C4_COLORS[`${type.external ? "external_" : ""}${type.base}`] ?? C4_COLORS.container;
|
|
9984
|
+
}
|
|
9985
|
+
var styleOf = (data) => data?.c4Style ?? {};
|
|
9986
|
+
function titleMark(graph, layout2, theme) {
|
|
9987
|
+
if (!graph.title) return null;
|
|
9988
|
+
const groupIds = new Set(graph.groups.map((g) => g.id));
|
|
9989
|
+
const roots = [...graph.nodes, ...graph.groups].filter((n3) => !(n3.parentId && groupIds.has(n3.parentId)) && layout2.positions[n3.id] && layout2.sizes[n3.id]);
|
|
9990
|
+
const minX = roots.length ? Math.min(...roots.map((n3) => layout2.positions[n3.id][0])) : 0;
|
|
9991
|
+
const maxX = roots.length ? Math.max(...roots.map((n3) => layout2.positions[n3.id][0] + layout2.sizes[n3.id].width)) : 240;
|
|
9992
|
+
const minY = roots.length ? Math.min(...roots.map((n3) => layout2.positions[n3.id][1])) : 0;
|
|
9993
|
+
return { kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: (minX + maxX) / 2, y: minY - 56 + 18, text: graph.title, anchor: "middle", baseline: "middle", size: 18, weight: 600, fill: theme.text };
|
|
9994
|
+
}
|
|
9995
|
+
var c4Scene = ({ graph, layout: layout2, theme }) => {
|
|
9996
|
+
const marks = [];
|
|
9997
|
+
const box = (id) => {
|
|
9998
|
+
const p = layout2.positions[id];
|
|
9999
|
+
const s = layout2.sizes[id];
|
|
10000
|
+
return p && s ? { x: p[0], y: p[1], width: s.width, height: s.height } : null;
|
|
10001
|
+
};
|
|
10002
|
+
const groupIds = new Set(graph.groups.map((g) => g.id));
|
|
10003
|
+
const depth2 = (id) => {
|
|
10004
|
+
let d = 0;
|
|
10005
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10006
|
+
let p = graph.groups.find((g) => g.id === id)?.parentId;
|
|
10007
|
+
while (p && groupIds.has(p) && !seen.has(p)) {
|
|
10008
|
+
seen.add(p);
|
|
10009
|
+
d++;
|
|
10010
|
+
p = graph.groups.find((g) => g.id === p)?.parentId;
|
|
10011
|
+
}
|
|
10012
|
+
return d;
|
|
10013
|
+
};
|
|
10014
|
+
for (const group of [...graph.groups].sort((a, b) => depth2(a.id) - depth2(b.id))) {
|
|
10015
|
+
const b = box(group.id);
|
|
10016
|
+
if (!b) continue;
|
|
10017
|
+
const text2 = c4BoundaryText(group);
|
|
10018
|
+
const cx = b.x + b.width / 2;
|
|
10019
|
+
marks.push({ kind: "rect", key: `boundary:${group.id}`, role: "boundary", target: group.id, ...b, radius: 2.5, fill: "none", stroke: theme.groupStroke, strokeWidth: 1, dash: text2.solid ? void 0 : "7 7" });
|
|
10020
|
+
marks.push({ kind: "text", key: `boundary-label:${group.id}`, role: "boundary-label", target: group.id, x: cx, y: b.y + text2.labelY, text: text2.label, anchor: "middle", baseline: "middle", size: 16, weight: 700, fill: theme.groupText });
|
|
10021
|
+
marks.push({ kind: "text", key: `boundary-type:${group.id}`, role: "boundary-type", target: group.id, x: cx, y: b.y + text2.typeY, text: text2.type, anchor: "middle", baseline: "middle", size: 14, fill: theme.groupText });
|
|
10022
|
+
if (text2.descr && text2.descrY !== void 0)
|
|
10023
|
+
marks.push({ kind: "text", key: `boundary-descr:${group.id}`, role: "boundary-descr", target: group.id, x: cx, y: b.y + text2.descrY, text: text2.descr, anchor: "middle", baseline: "middle", size: 12, fill: theme.groupText });
|
|
10024
|
+
}
|
|
10025
|
+
const labels = [];
|
|
10026
|
+
const dynamic = graph.data?.c4Type === "C4Dynamic";
|
|
10027
|
+
graph.edges.forEach((edge, index) => {
|
|
10028
|
+
const from = box(edge.source);
|
|
10029
|
+
const to = box(edge.target);
|
|
10030
|
+
if (!from || !to) return;
|
|
10031
|
+
const geo = c4RelGeometry(from, to, index);
|
|
10032
|
+
const { start, end, control } = geo;
|
|
10033
|
+
const style = styleOf(edge.data);
|
|
10034
|
+
const line4 = style.lineColor || theme.edge;
|
|
10035
|
+
marks.push({
|
|
10036
|
+
kind: "path",
|
|
10037
|
+
key: `relation:${edge.id}`,
|
|
10038
|
+
role: "relation",
|
|
10039
|
+
target: edge.id,
|
|
10040
|
+
d: control ? `M${start.x},${start.y} Q${control.x},${control.y} ${end.x},${end.y}` : `M${start.x},${start.y} L${end.x},${end.y}`,
|
|
10041
|
+
fill: "none",
|
|
10042
|
+
stroke: line4,
|
|
10043
|
+
strokeWidth: 1
|
|
10044
|
+
});
|
|
10045
|
+
const head = (key, points) => marks.push({ kind: "path", key, role: "arrow", target: edge.id, d: `M${points.split(" ").join(" L")} Z`, fill: line4 });
|
|
10046
|
+
if (edge.arrowEnd !== "none") head(`arrow-end:${edge.id}`, c4ArrowHead(end, control ?? start));
|
|
10047
|
+
if (edge.arrowStart !== "none") head(`arrow-start:${edge.id}`, c4ArrowHead(start, control ?? end));
|
|
10048
|
+
const offsetX = parseInt(style.offsetX ?? "0", 10) || 0;
|
|
10049
|
+
const offsetY = parseInt(style.offsetY ?? "0", 10) || 0;
|
|
10050
|
+
const left = geo.label.x + offsetX;
|
|
10051
|
+
const top = geo.label.y + offsetY - 7;
|
|
10052
|
+
const textFill = style.textColor || theme.text;
|
|
10053
|
+
const label = `${dynamic ? `${index + 1}: ` : ""}${edge.label ?? ""}`;
|
|
10054
|
+
const tech = typeof edge.data?.tech === "string" && edge.data.tech ? `[${edge.data.tech}]` : "";
|
|
10055
|
+
const gridWidth = Math.max(label ? estimateTextWidth2(label, REL_FONT) : 0, tech ? estimateTextWidth2(tech, REL_FONT) : 0);
|
|
10056
|
+
if (label)
|
|
10057
|
+
labels.push({ kind: "text", key: `relation-label:${edge.id}`, role: "relation-label", target: edge.id, x: left, y: top + REL_LINE / 2, text: label, anchor: "start", baseline: "middle", size: REL_FONT, fill: textFill });
|
|
10058
|
+
if (tech)
|
|
10059
|
+
labels.push({
|
|
10060
|
+
kind: "text",
|
|
10061
|
+
key: `relation-tech:${edge.id}`,
|
|
10062
|
+
role: "relation-tech",
|
|
10063
|
+
target: edge.id,
|
|
10064
|
+
x: left + gridWidth / 2,
|
|
10065
|
+
y: top + (label ? REL_LINE + REL_GAP : 0) + REL_LINE / 2,
|
|
10066
|
+
text: tech,
|
|
10067
|
+
anchor: "middle",
|
|
10068
|
+
baseline: "middle",
|
|
10069
|
+
size: REL_FONT,
|
|
10070
|
+
italic: true,
|
|
10071
|
+
fill: style.textColor || theme.mutedText
|
|
10072
|
+
});
|
|
10073
|
+
});
|
|
10074
|
+
for (const node of graph.nodes) {
|
|
10075
|
+
const b = box(node.id);
|
|
10076
|
+
if (!b) continue;
|
|
10077
|
+
const geo = c4ElementGeometry(node);
|
|
10078
|
+
const style = styleOf(node.data);
|
|
10079
|
+
const colors = colorsOf(geo.type);
|
|
10080
|
+
const fill = style.bgColor || colors.bg;
|
|
10081
|
+
const stroke = style.borderColor || colors.border;
|
|
10082
|
+
const fg = style.fontColor || C4_ELEMENT_FG;
|
|
10083
|
+
const { x, y } = b;
|
|
10084
|
+
const w = geo.width;
|
|
10085
|
+
const h = geo.height;
|
|
10086
|
+
const common = { target: node.id, fill, stroke, strokeWidth: 2 };
|
|
10087
|
+
if (geo.person) {
|
|
10088
|
+
const { headRadius: r, bodyTop, bodyRadius } = geo.person;
|
|
10089
|
+
marks.push(
|
|
10090
|
+
{ kind: "rect", key: `element:${node.id}`, role: "element", ...common, x, y: y + bodyTop, width: w, height: h - bodyTop, radius: bodyRadius },
|
|
10091
|
+
{ kind: "circle", key: `element-head:${node.id}`, role: "element", ...common, cx: x + w / 2, cy: y + r, r }
|
|
10092
|
+
);
|
|
10093
|
+
} else if (geo.shape === "cylinder" && geo.cylinder) {
|
|
10094
|
+
const { rx, ry } = geo.cylinder;
|
|
10095
|
+
const body = h - 2 * ry;
|
|
10096
|
+
marks.push({
|
|
10097
|
+
kind: "path",
|
|
10098
|
+
key: `element:${node.id}`,
|
|
10099
|
+
role: "element",
|
|
10100
|
+
...common,
|
|
10101
|
+
d: `M${x},${y + ry} a${rx},${ry} 0,0,0 ${w},0 a${rx},${ry} 0,0,0 ${-w},0 l0,${body} a${rx},${ry} 0,0,0 ${w},0 l0,${-body}`,
|
|
10102
|
+
box: { x, y, width: w, height: h }
|
|
10103
|
+
});
|
|
10104
|
+
} else if (geo.shape === "h-cyl" && geo.cylinder) {
|
|
10105
|
+
const { rx, ry } = geo.cylinder;
|
|
10106
|
+
const body = w - 2 * rx;
|
|
10107
|
+
marks.push({
|
|
10108
|
+
kind: "path",
|
|
10109
|
+
key: `element:${node.id}`,
|
|
10110
|
+
role: "element",
|
|
10111
|
+
...common,
|
|
10112
|
+
d: `M${x + rx},${y + h} a${rx},${ry} 0,0,1 0,${-h} l${body},0 a${rx},${ry} 0,0,1 0,${h} M${x + rx + body},${y} a${rx},${ry} 0,0,0 0,${h} l${-body},0`,
|
|
10113
|
+
box: { x, y, width: w, height: h }
|
|
10114
|
+
});
|
|
10115
|
+
} else marks.push({ kind: "rect", key: `element:${node.id}`, role: "element", ...common, x, y, width: w, height: h, radius: 12 });
|
|
10116
|
+
let top = y + geo.textCenter.y - geo.textHeight / 2;
|
|
10117
|
+
for (const section of geo.sections) {
|
|
10118
|
+
const size = section.part === "label" ? NAME_SIZE : section.part === "tech" ? TYPE_SIZE : DESCR_SIZE;
|
|
10119
|
+
const lh = section.fontSize * LINE_HEIGHT2;
|
|
10120
|
+
section.lines.forEach((line4, i) => {
|
|
10121
|
+
if (!line4) return;
|
|
10122
|
+
marks.push({
|
|
10123
|
+
kind: "text",
|
|
10124
|
+
key: `element-${section.part}:${node.id}:${i}`,
|
|
10125
|
+
role: section.part === "label" ? "element-name" : section.part === "tech" ? "element-type" : "element-descr",
|
|
10126
|
+
target: node.id,
|
|
10127
|
+
x: x + geo.textCenter.x,
|
|
10128
|
+
y: top + (i + 0.5) * lh,
|
|
10129
|
+
text: line4,
|
|
10130
|
+
anchor: "middle",
|
|
10131
|
+
baseline: "middle",
|
|
10132
|
+
size,
|
|
10133
|
+
weight: section.bold ? 700 : void 0,
|
|
10134
|
+
fill: fg
|
|
10135
|
+
});
|
|
10136
|
+
});
|
|
10137
|
+
top += section.height + SECTION_GAP;
|
|
10138
|
+
}
|
|
10139
|
+
}
|
|
10140
|
+
marks.push(...labels);
|
|
10141
|
+
const title = titleMark(graph, layout2, theme);
|
|
10142
|
+
if (title) marks.push(title);
|
|
10143
|
+
return marks;
|
|
10144
|
+
};
|
|
10145
|
+
|
|
10146
|
+
// src/canvas/mermaid/families/architecture.ts
|
|
10147
|
+
var A = ARCH_METRICS;
|
|
10148
|
+
var ICON_BG = "#087ebf";
|
|
10149
|
+
var ICON_FG = "#ffffff";
|
|
10150
|
+
var r2 = (n3) => Math.round(n3 * 100) / 100;
|
|
10151
|
+
function placePath(d, s, ox, oy) {
|
|
10152
|
+
const tokens = d.match(/[MmLlHhVvCcSsQqZz]|-?(?:\d*\.\d+|\d+\.?)(?:e[-+]?\d+)?/g) ?? [];
|
|
10153
|
+
const out = [];
|
|
10154
|
+
const P = (x2, y2) => `${r2(ox + x2 * s)},${r2(oy + y2 * s)}`;
|
|
10155
|
+
let i = 0;
|
|
10156
|
+
let cmd = "";
|
|
10157
|
+
let x = 0, y = 0, sx = 0, sy = 0;
|
|
10158
|
+
let lastC = null;
|
|
10159
|
+
const num4 = () => Number(tokens[i++]);
|
|
10160
|
+
while (i < tokens.length) {
|
|
10161
|
+
if (/[A-Za-z]/.test(tokens[i])) cmd = tokens[i++];
|
|
10162
|
+
const rel = cmd === cmd.toLowerCase();
|
|
10163
|
+
const bx = rel ? x : 0;
|
|
10164
|
+
const by = rel ? y : 0;
|
|
10165
|
+
switch (cmd.toUpperCase()) {
|
|
10166
|
+
case "M":
|
|
10167
|
+
x = bx + num4();
|
|
10168
|
+
y = by + num4();
|
|
10169
|
+
sx = x;
|
|
10170
|
+
sy = y;
|
|
10171
|
+
out.push(`M${P(x, y)}`);
|
|
10172
|
+
cmd = rel ? "l" : "L";
|
|
10173
|
+
lastC = null;
|
|
10174
|
+
break;
|
|
10175
|
+
case "L":
|
|
10176
|
+
x = bx + num4();
|
|
10177
|
+
y = by + num4();
|
|
10178
|
+
out.push(`L${P(x, y)}`);
|
|
10179
|
+
lastC = null;
|
|
10180
|
+
break;
|
|
10181
|
+
case "H":
|
|
10182
|
+
x = bx + num4();
|
|
10183
|
+
out.push(`L${P(x, y)}`);
|
|
10184
|
+
lastC = null;
|
|
10185
|
+
break;
|
|
10186
|
+
case "V":
|
|
10187
|
+
y = (rel ? y : 0) + num4();
|
|
10188
|
+
out.push(`L${P(x, y)}`);
|
|
10189
|
+
lastC = null;
|
|
10190
|
+
break;
|
|
10191
|
+
case "C": {
|
|
10192
|
+
const c1x = bx + num4(), c1y = by + num4(), c2x = bx + num4(), c2y = by + num4();
|
|
10193
|
+
x = bx + num4();
|
|
10194
|
+
y = by + num4();
|
|
10195
|
+
out.push(`C${P(c1x, c1y)} ${P(c2x, c2y)} ${P(x, y)}`);
|
|
10196
|
+
lastC = [c2x, c2y];
|
|
10197
|
+
break;
|
|
10198
|
+
}
|
|
10199
|
+
case "S": {
|
|
10200
|
+
const c1x = lastC ? 2 * x - lastC[0] : x;
|
|
10201
|
+
const c1y = lastC ? 2 * y - lastC[1] : y;
|
|
10202
|
+
const c2x = bx + num4(), c2y = by + num4();
|
|
10203
|
+
x = bx + num4();
|
|
10204
|
+
y = by + num4();
|
|
10205
|
+
out.push(`C${P(c1x, c1y)} ${P(c2x, c2y)} ${P(x, y)}`);
|
|
10206
|
+
lastC = [c2x, c2y];
|
|
10207
|
+
break;
|
|
10208
|
+
}
|
|
10209
|
+
case "Q": {
|
|
10210
|
+
const cx = bx + num4(), cy = by + num4();
|
|
10211
|
+
x = bx + num4();
|
|
10212
|
+
y = by + num4();
|
|
10213
|
+
out.push(`Q${P(cx, cy)} ${P(x, y)}`);
|
|
10214
|
+
lastC = null;
|
|
10215
|
+
break;
|
|
10216
|
+
}
|
|
10217
|
+
case "Z":
|
|
10218
|
+
x = sx;
|
|
10219
|
+
y = sy;
|
|
10220
|
+
out.push("Z");
|
|
10221
|
+
lastC = null;
|
|
10222
|
+
break;
|
|
10223
|
+
default:
|
|
10224
|
+
i++;
|
|
10225
|
+
}
|
|
10226
|
+
}
|
|
10227
|
+
return out.join(" ");
|
|
10228
|
+
}
|
|
10229
|
+
function ellipse(cx, cy, rx, ry) {
|
|
10230
|
+
const k = 0.5523;
|
|
10231
|
+
return `M${cx - rx},${cy} C${cx - rx},${cy - ry * k} ${cx - rx * k},${cy - ry} ${cx},${cy - ry} C${cx + rx * k},${cy - ry} ${cx + rx},${cy - ry * k} ${cx + rx},${cy} C${cx + rx},${cy + ry * k} ${cx + rx * k},${cy + ry} ${cx},${cy + ry} C${cx - rx * k},${cy + ry} ${cx - rx},${cy + ry * k} ${cx - rx},${cy} Z`;
|
|
10232
|
+
}
|
|
10233
|
+
function roundRect(x, y, w, h, r) {
|
|
10234
|
+
return `M${x + r},${y} H${x + w - r} Q${x + w},${y} ${x + w},${y + r} V${y + h - r} Q${x + w},${y + h} ${x + w - r},${y + h} H${x + r} Q${x},${y + h} ${x},${y + h - r} V${y + r} Q${x},${y} ${x + r},${y} Z`;
|
|
10235
|
+
}
|
|
10236
|
+
var line2 = (x1, y1, x2, y2) => `M${x1},${y1} L${x2},${y2}`;
|
|
10237
|
+
var BAR = (y) => ({ d: `m56.25,${y}c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z`, paint: "both", width: 1 });
|
|
10238
|
+
var DOTS = (y) => [32.5, 27.5, 22.5].map((x) => ({ d: ellipse(x, y, 0.75, 0.75), paint: "both", width: 1 }));
|
|
10239
|
+
var ARCH_GLYPHS = {
|
|
10240
|
+
database: [
|
|
10241
|
+
{ d: "m20,57.86c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14", paint: "stroke" },
|
|
10242
|
+
{ d: "m20,45.95c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14", paint: "stroke" },
|
|
10243
|
+
{ d: "m20,34.05c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14", paint: "stroke" },
|
|
10244
|
+
{ d: ellipse(40, 22.14, 20, 7.14), paint: "stroke" },
|
|
10245
|
+
{ d: line2(20, 57.86, 20, 22.14), paint: "stroke" },
|
|
10246
|
+
{ d: line2(60, 57.86, 60, 22.14), paint: "stroke" }
|
|
10247
|
+
],
|
|
10248
|
+
server: [
|
|
10249
|
+
{ d: roundRect(17.5, 17.5, 45, 45, 2), paint: "stroke" },
|
|
10250
|
+
{ d: line2(17.5, 32.5, 62.5, 32.5), paint: "stroke" },
|
|
10251
|
+
{ d: line2(17.5, 47.5, 62.5, 47.5), paint: "stroke" },
|
|
10252
|
+
BAR(25),
|
|
10253
|
+
BAR(40),
|
|
10254
|
+
BAR(55),
|
|
10255
|
+
...DOTS(25),
|
|
10256
|
+
...DOTS(40),
|
|
10257
|
+
...DOTS(55)
|
|
10258
|
+
],
|
|
10259
|
+
disk: [
|
|
10260
|
+
{ d: roundRect(20, 15, 40, 50, 1), paint: "stroke" },
|
|
10261
|
+
{ d: ellipse(24, 19.17, 0.8, 0.83), paint: "stroke" },
|
|
10262
|
+
{ d: ellipse(56, 19.17, 0.8, 0.83), paint: "stroke" },
|
|
10263
|
+
{ d: ellipse(24, 60.83, 0.8, 0.83), paint: "stroke" },
|
|
10264
|
+
{ d: ellipse(56, 60.83, 0.8, 0.83), paint: "stroke" },
|
|
10265
|
+
{ d: ellipse(40, 33.75, 14, 14.58), paint: "stroke" },
|
|
10266
|
+
{ d: ellipse(40, 33.75, 4, 4.17), paint: "both" },
|
|
10267
|
+
{ d: "m37.51,42.52l-4.83,13.22c-.26.71-1.1,1.02-1.76.64l-4.18-2.42c-.66-.38-.81-1.26-.33-1.84l9.01-10.8c.88-1.05,2.56-.08,2.09,1.2Z", paint: "fill" }
|
|
10268
|
+
],
|
|
10269
|
+
internet: [
|
|
10270
|
+
{ d: ellipse(40, 40, 22.5, 22.5), paint: "stroke" },
|
|
10271
|
+
{ d: line2(40, 17.5, 40, 62.5), paint: "stroke" },
|
|
10272
|
+
{ d: line2(17.5, 40, 62.5, 40), paint: "stroke" },
|
|
10273
|
+
{ d: "m39.99,17.51c-15.28,11.1-15.28,33.88,0,44.98", paint: "stroke" },
|
|
10274
|
+
{ d: "m40.01,17.51c15.28,11.1,15.28,33.88,0,44.98", paint: "stroke" },
|
|
10275
|
+
{ d: line2(19.75, 30.1, 60.25, 30.1), paint: "stroke" },
|
|
10276
|
+
{ d: line2(19.75, 49.9, 60.25, 49.9), paint: "stroke" }
|
|
10277
|
+
],
|
|
10278
|
+
cloud: [
|
|
10279
|
+
{
|
|
10280
|
+
d: "m65,47.5c0,2.76-2.24,5-5,5H20c-2.76,0-5-2.24-5-5,0-1.87,1.03-3.51,2.56-4.36-.04-.21-.06-.42-.06-.64,0-2.6,2.48-4.74,5.65-4.97,1.65-4.51,6.34-7.76,11.85-7.76.86,0,1.69.08,2.5.23,2.09-1.57,4.69-2.5,7.5-2.5,6.1,0,11.19,4.38,12.28,10.17,2.14.56,3.72,2.51,3.72,4.83,0,.03,0,.07-.01.1,2.29.46,4.01,2.48,4.01,4.9Z",
|
|
10281
|
+
paint: "stroke"
|
|
10282
|
+
}
|
|
10283
|
+
],
|
|
10284
|
+
blank: []
|
|
10285
|
+
};
|
|
10286
|
+
function iconMarks(key, target, icon, x, y, size, theme) {
|
|
10287
|
+
const s = size / 80;
|
|
10288
|
+
if (!icon)
|
|
10289
|
+
return [
|
|
10290
|
+
{
|
|
10291
|
+
kind: "path",
|
|
10292
|
+
key: `icon:${key}`,
|
|
10293
|
+
role: "icon",
|
|
10294
|
+
target,
|
|
10295
|
+
d: placePath("M0,80 V5 Q0,0 5,0 H75 Q80,0 80,5 V80 Z", s, x, y),
|
|
10296
|
+
fill: "none",
|
|
10297
|
+
stroke: theme.groupStroke,
|
|
10298
|
+
strokeWidth: 2,
|
|
10299
|
+
dash: "8"
|
|
10300
|
+
}
|
|
10301
|
+
];
|
|
10302
|
+
const marks = [{ kind: "rect", key: `icon:${key}`, role: "icon", target, x, y, width: size, height: size, fill: ICON_BG }];
|
|
10303
|
+
const glyph = ARCH_GLYPHS[icon];
|
|
10304
|
+
if (glyph) {
|
|
10305
|
+
glyph.forEach(
|
|
10306
|
+
(part, i) => marks.push({
|
|
10307
|
+
kind: "path",
|
|
10308
|
+
key: `icon-glyph:${key}:${i}`,
|
|
10309
|
+
role: "icon-glyph",
|
|
10310
|
+
target,
|
|
10311
|
+
d: placePath(part.d, s, x, y),
|
|
10312
|
+
fill: part.paint === "stroke" ? "none" : ICON_FG,
|
|
10313
|
+
stroke: part.paint === "fill" ? void 0 : ICON_FG,
|
|
10314
|
+
strokeWidth: (part.width ?? 2) * s
|
|
10315
|
+
})
|
|
10316
|
+
);
|
|
10317
|
+
return marks;
|
|
10318
|
+
}
|
|
10319
|
+
const font = 11 * s;
|
|
10320
|
+
const perLine = Math.max(1, Math.floor(72 * s / estimateTextWidth2("m", font)));
|
|
10321
|
+
const lines = [];
|
|
10322
|
+
for (let i = 0; i < icon.length; i += perLine) lines.push(icon.slice(i, i + perLine));
|
|
10323
|
+
const shown = lines.slice(0, Math.max(1, Math.floor(72 * s / (font * 1.2))));
|
|
10324
|
+
const lh = font * 1.2;
|
|
10325
|
+
shown.forEach(
|
|
10326
|
+
(text2, i) => marks.push({ kind: "text", key: `icon-name:${key}:${i}`, role: "icon-name", target, x: x + size / 2, y: y + size / 2 + (i - (shown.length - 1) / 2) * lh, text: text2, anchor: "middle", baseline: "middle", size: font, fill: ICON_FG })
|
|
10327
|
+
);
|
|
10328
|
+
return marks;
|
|
10329
|
+
}
|
|
10330
|
+
var isJunction = (n3) => n3.shape === "sm-circ" || !!n3.data?.junction;
|
|
10331
|
+
var iconOf = (data) => typeof data?.icon === "string" && data.icon ? data.icon : void 0;
|
|
10332
|
+
function titleMark2(graph, layout2, theme) {
|
|
10333
|
+
if (!graph.title) return null;
|
|
10334
|
+
const groupIds = new Set(graph.groups.map((g) => g.id));
|
|
10335
|
+
const roots = [...graph.nodes, ...graph.groups].filter((n3) => !(n3.parentId && groupIds.has(n3.parentId)) && layout2.positions[n3.id] && layout2.sizes[n3.id]);
|
|
10336
|
+
const minX = roots.length ? Math.min(...roots.map((n3) => layout2.positions[n3.id][0])) : 0;
|
|
10337
|
+
const maxX = roots.length ? Math.max(...roots.map((n3) => layout2.positions[n3.id][0] + layout2.sizes[n3.id].width)) : 240;
|
|
10338
|
+
const minY = roots.length ? Math.min(...roots.map((n3) => layout2.positions[n3.id][1])) : 0;
|
|
10339
|
+
return { kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: (minX + maxX) / 2, y: minY - 56 + 18, text: graph.title, anchor: "middle", baseline: "middle", size: 18, weight: 600, fill: theme.text };
|
|
10340
|
+
}
|
|
10341
|
+
var architectureScene = ({ graph, layout: layout2, theme }) => {
|
|
10342
|
+
const marks = [];
|
|
10343
|
+
const box = (id) => {
|
|
10344
|
+
const p = layout2.positions[id];
|
|
10345
|
+
const s = layout2.sizes[id];
|
|
10346
|
+
return p && s ? { x: p[0], y: p[1], width: s.width, height: s.height } : null;
|
|
10347
|
+
};
|
|
10348
|
+
const groupIds = new Set(graph.groups.map((g) => g.id));
|
|
10349
|
+
const parentOf = new Map(graph.groups.map((g) => [g.id, g.parentId]));
|
|
10350
|
+
const depth2 = (id) => {
|
|
10351
|
+
let d = 0;
|
|
10352
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10353
|
+
let p = parentOf.get(id);
|
|
10354
|
+
while (p && groupIds.has(p) && !seen.has(p)) {
|
|
10355
|
+
seen.add(p);
|
|
10356
|
+
d++;
|
|
10357
|
+
p = parentOf.get(p);
|
|
10358
|
+
}
|
|
10359
|
+
return d;
|
|
10360
|
+
};
|
|
10361
|
+
for (const group of [...graph.groups].sort((a, b) => depth2(a.id) - depth2(b.id))) {
|
|
10362
|
+
const b = box(group.id);
|
|
10363
|
+
if (!b) continue;
|
|
10364
|
+
const icon = iconOf(group.data);
|
|
10365
|
+
marks.push({ kind: "rect", key: `group:${group.id}`, role: "group", target: group.id, ...b, fill: "none", stroke: theme.groupStroke, strokeWidth: 2, dash: "8" });
|
|
10366
|
+
if (icon) marks.push(...iconMarks(`group:${group.id}`, group.id, icon, b.x + 1, b.y + 1, A.groupIconSize, theme));
|
|
10367
|
+
const label = group.data?.untitled ? "" : group.label;
|
|
10368
|
+
if (label)
|
|
10369
|
+
marks.push({ kind: "text", key: `group-label:${group.id}`, role: "group-label", target: group.id, x: b.x + (icon ? A.groupIconSize + 4 : 4), y: b.y + 7 + 19 / 2, text: label, anchor: "start", baseline: "middle", size: A.fontSize, fill: theme.groupText });
|
|
10370
|
+
}
|
|
10371
|
+
const labels = [];
|
|
10372
|
+
const junctions = new Set(graph.nodes.filter(isJunction).map((n3) => n3.id));
|
|
10373
|
+
const port = (b, side) => side === "L" ? { x: b.x, y: b.y + b.height / 2 } : side === "R" ? { x: b.x + b.width, y: b.y + b.height / 2 } : side === "T" ? { x: b.x + b.width / 2, y: b.y } : { x: b.x + b.width / 2, y: b.y + b.height };
|
|
10374
|
+
for (const edge of graph.edges) {
|
|
10375
|
+
const from = box(edge.source);
|
|
10376
|
+
const to = box(edge.target);
|
|
10377
|
+
if (!from || !to) continue;
|
|
10378
|
+
const d = edge.data ?? {};
|
|
10379
|
+
const sourceSide = isSide(d.sourceSide) ? d.sourceSide : "R";
|
|
10380
|
+
const targetSide = isSide(d.targetSide) ? d.targetSide : "L";
|
|
10381
|
+
const s = shiftEndpoint(port(from, sourceSide), sourceSide, { group: !!d.sourceGroup, junction: junctions.has(edge.source) });
|
|
10382
|
+
const t = shiftEndpoint(port(to, targetSide), targetSide, { group: !!d.targetGroup, junction: junctions.has(edge.target) });
|
|
10383
|
+
const route = architectureEdgeRoute(s, sourceSide, t, targetSide);
|
|
10384
|
+
marks.push({ kind: "path", key: `edge:${edge.id}`, role: "edge", target: edge.id, d: route.points.map((p, i) => `${i ? "L" : "M"}${p.x},${p.y}`).join(" "), fill: "none", stroke: theme.edge, strokeWidth: 3 });
|
|
10385
|
+
const head = (key, points) => marks.push({ kind: "path", key, role: "arrow", target: edge.id, d: `M${points.split(" ").join(" L")} Z`, fill: theme.edge });
|
|
10386
|
+
if (edge.arrowStart !== "none") head(`arrow-start:${edge.id}`, architectureArrow(s, sourceSide));
|
|
10387
|
+
if (edge.arrowEnd !== "none") head(`arrow-end:${edge.id}`, architectureArrow(t, targetSide));
|
|
10388
|
+
if (edge.label)
|
|
10389
|
+
labels.push({ kind: "text", key: `edge-label:${edge.id}`, role: "edge-label", target: edge.id, x: route.label.x, y: route.label.y, text: edge.label, anchor: "middle", baseline: "middle", size: A.fontSize, rotate: route.rotate || void 0, fill: theme.text });
|
|
10390
|
+
}
|
|
10391
|
+
for (const node of graph.nodes) {
|
|
10392
|
+
const b = box(node.id);
|
|
10393
|
+
if (!b) continue;
|
|
10394
|
+
if (isJunction(node)) {
|
|
10395
|
+
const cx = b.x + b.width / 2;
|
|
10396
|
+
const cy = b.y + b.height / 2;
|
|
10397
|
+
marks.push(
|
|
10398
|
+
{ kind: "circle", key: `junction:${node.id}`, role: "junction", target: node.id, cx, cy, r: b.width / 2, fill: "transparent" },
|
|
10399
|
+
{ kind: "circle", key: `junction-dot:${node.id}`, role: "junction", target: node.id, cx, cy, r: Math.max(1, b.width / 2 - 3), fill: theme.edge }
|
|
10400
|
+
);
|
|
10401
|
+
continue;
|
|
10402
|
+
}
|
|
10403
|
+
marks.push(...iconMarks(`service:${node.id}`, node.id, iconOf(node.data), b.x, b.y, b.width, theme));
|
|
10404
|
+
if (node.data?.untitled) continue;
|
|
10405
|
+
serviceLabelLines(node.label ?? "").forEach(
|
|
10406
|
+
(text2, i) => marks.push({ kind: "text", key: `service-label:${node.id}:${i}`, role: "service-label", target: node.id, x: b.x + b.width / 2, y: b.y + b.height + (i + 0.5) * A.lineHeight, text: text2, anchor: "middle", baseline: "middle", size: A.fontSize, fill: theme.text })
|
|
10407
|
+
);
|
|
10408
|
+
}
|
|
10409
|
+
marks.push(...labels);
|
|
10410
|
+
const title = titleMark2(graph, layout2, theme);
|
|
10411
|
+
if (title) marks.push(title);
|
|
10412
|
+
return marks;
|
|
10413
|
+
};
|
|
10414
|
+
|
|
10415
|
+
// src/canvas/mermaid/families/gantt.ts
|
|
10416
|
+
var M7 = GANTT_METRICS;
|
|
10417
|
+
var CRIT = 3;
|
|
10418
|
+
function statusOf(node) {
|
|
10419
|
+
const tags = Array.isArray(node?.data?.tags) ? node.data.tags.map(String) : [];
|
|
10420
|
+
const done2 = tags.includes("done");
|
|
10421
|
+
const active = tags.includes("active");
|
|
10422
|
+
const crit = tags.includes("crit");
|
|
10423
|
+
if (crit && done2) return "done-crit";
|
|
10424
|
+
if (crit && active) return "active-crit";
|
|
10425
|
+
if (crit) return "crit";
|
|
10426
|
+
if (done2) return "done";
|
|
10427
|
+
if (active) return "active";
|
|
10428
|
+
return "";
|
|
10429
|
+
}
|
|
10430
|
+
function barColours(theme, status) {
|
|
10431
|
+
const task = sceneColor(theme, 0);
|
|
10432
|
+
const crit = sceneColor(theme, CRIT);
|
|
10433
|
+
switch (status) {
|
|
10434
|
+
case "active":
|
|
10435
|
+
return { fill: theme.background, stroke: task, text: theme.text };
|
|
10436
|
+
case "done":
|
|
10437
|
+
return { fill: theme.grid, stroke: theme.mutedText, text: theme.text };
|
|
10438
|
+
case "crit":
|
|
10439
|
+
return { fill: crit, stroke: crit, text: theme.paletteText };
|
|
10440
|
+
case "active-crit":
|
|
10441
|
+
return { fill: theme.background, stroke: crit, text: theme.text };
|
|
10442
|
+
case "done-crit":
|
|
10443
|
+
return { fill: theme.grid, stroke: crit, text: theme.text };
|
|
10444
|
+
default:
|
|
10445
|
+
return { fill: task, stroke: task, text: theme.paletteText };
|
|
10446
|
+
}
|
|
10447
|
+
}
|
|
10448
|
+
function bandFill(theme, index) {
|
|
10449
|
+
const slot = (index % 4 + 4) % 4;
|
|
10450
|
+
if (slot === 1 || slot === 3) return theme.background;
|
|
10451
|
+
return sceneColor(theme, slot === 0 ? 0 : 2);
|
|
10452
|
+
}
|
|
10453
|
+
var labelWidth = (text2) => text2.length * 6.8 + 16;
|
|
10454
|
+
function stepPath(from, to) {
|
|
10455
|
+
const offset = 12;
|
|
10456
|
+
const sx = from.x + from.width;
|
|
10457
|
+
const sy = from.y + from.height / 2;
|
|
10458
|
+
const tx = to.x;
|
|
10459
|
+
const ty = to.y + to.height / 2;
|
|
10460
|
+
if (tx >= sx + 2 * offset) {
|
|
10461
|
+
const mx = (sx + tx) / 2;
|
|
10462
|
+
return `M ${sx} ${sy} L ${mx} ${sy} L ${mx} ${ty} L ${tx} ${ty}`;
|
|
10463
|
+
}
|
|
10464
|
+
const my = (sy + ty) / 2;
|
|
10465
|
+
return `M ${sx} ${sy} L ${sx + offset} ${sy} L ${sx + offset} ${my} L ${tx - offset} ${my} L ${tx - offset} ${ty} L ${tx} ${ty}`;
|
|
10466
|
+
}
|
|
10467
|
+
var ganttScene = ({ graph, selection, theme }) => {
|
|
10468
|
+
const geo = ganttGeometry(graph);
|
|
10469
|
+
const nodes = new Map(graph.nodes.map((n3) => [n3.id, n3]));
|
|
10470
|
+
const marks = [];
|
|
10471
|
+
const left = geo.chartX - M7.labelWidth;
|
|
10472
|
+
const fullWidth = M7.labelWidth + geo.chartWidth + M7.rightPadding;
|
|
10473
|
+
for (const band of geo.bands) {
|
|
10474
|
+
const key = band.id ?? "::loose";
|
|
10475
|
+
marks.push({
|
|
10476
|
+
kind: "rect",
|
|
10477
|
+
key: `band:${key}`,
|
|
10478
|
+
role: "section",
|
|
10479
|
+
target: band.id,
|
|
10480
|
+
x: left,
|
|
10481
|
+
y: band.y,
|
|
10482
|
+
width: fullWidth,
|
|
10483
|
+
height: band.height,
|
|
10484
|
+
fill: bandFill(theme, band.id ? band.index : 0),
|
|
10485
|
+
opacity: 0.2
|
|
10486
|
+
});
|
|
10487
|
+
if (band.label !== void 0)
|
|
10488
|
+
marks.push({ kind: "text", key: `section:${key}`, role: "section-label", target: band.id, x: left + 8, y: band.y + 4, text: band.label, anchor: "start", baseline: "top", size: 12, fill: theme.groupText });
|
|
10489
|
+
}
|
|
10490
|
+
for (const tick of geo.ticks) {
|
|
10491
|
+
marks.push(
|
|
10492
|
+
{ kind: "line", key: `tick:${tick.time}`, role: "grid", x1: tick.x, y1: geo.top, x2: tick.x, y2: geo.bottom, stroke: theme.grid, opacity: 0.8 },
|
|
10493
|
+
{ kind: "text", key: `tick-label:${tick.time}`, role: "axis", x: tick.x, y: geo.bottom + 6, text: tick.label, anchor: "middle", baseline: "top", size: 11, fill: theme.mutedText }
|
|
10494
|
+
);
|
|
10495
|
+
}
|
|
10496
|
+
if (geo.today !== void 0)
|
|
10497
|
+
marks.push({ kind: "line", key: "today", role: "today", x1: geo.today, y1: geo.top, x2: geo.today, y2: geo.bottom, stroke: sceneColor(theme, CRIT), strokeWidth: 2 });
|
|
10498
|
+
for (const edge of graph.edges) {
|
|
10499
|
+
if (!selection.has(edge.id) && !selection.has(edge.source) && !selection.has(edge.target)) continue;
|
|
10500
|
+
const from = geo.rowById.get(edge.source);
|
|
10501
|
+
const to = geo.rowById.get(edge.target);
|
|
10502
|
+
if (!from || !to) continue;
|
|
10503
|
+
marks.push({ kind: "path", key: `dependency:${edge.id}`, role: "dependency", target: edge.id, d: stepPath(from, to), stroke: theme.selection, strokeWidth: 1.5, dash: "5 4", markerEnd: "arrowclosed" });
|
|
10504
|
+
}
|
|
10505
|
+
for (const row of geo.rows) {
|
|
10506
|
+
const node = nodes.get(row.id);
|
|
10507
|
+
const status = statusOf(node);
|
|
10508
|
+
const colours2 = barColours(theme, status);
|
|
10509
|
+
const label = (node?.label ?? row.id).replace(/<br\s*\/?>/gi, " ");
|
|
10510
|
+
if (row.milestone) {
|
|
10511
|
+
const cx = row.x + row.width / 2;
|
|
10512
|
+
const cy = row.y + row.height / 2;
|
|
10513
|
+
const h = row.width * 0.8 * Math.SQRT2 / 2;
|
|
10514
|
+
const crit = status.includes("crit");
|
|
10515
|
+
marks.push({
|
|
10516
|
+
kind: "path",
|
|
10517
|
+
key: `milestone:${row.id}`,
|
|
10518
|
+
role: "milestone",
|
|
10519
|
+
target: row.id,
|
|
10520
|
+
d: `M ${cx} ${cy - h} L ${cx + h} ${cy} L ${cx} ${cy + h} L ${cx - h} ${cy} Z`,
|
|
10521
|
+
fill: status.startsWith("done") ? theme.grid : sceneColor(theme, 0),
|
|
10522
|
+
stroke: crit ? sceneColor(theme, CRIT) : status.startsWith("done") ? theme.mutedText : sceneColor(theme, 0),
|
|
10523
|
+
strokeWidth: 2
|
|
10524
|
+
});
|
|
10525
|
+
} else {
|
|
10526
|
+
marks.push({ kind: "rect", key: `bar:${row.id}`, role: "bar", target: row.id, x: row.x, y: row.y, width: row.width, height: row.height, fill: colours2.fill, stroke: colours2.stroke, strokeWidth: 2, radius: 3 });
|
|
10527
|
+
}
|
|
10528
|
+
const outside = row.milestone || labelWidth(label) > row.width;
|
|
10529
|
+
marks.push({
|
|
10530
|
+
kind: "text",
|
|
10531
|
+
key: `label:${row.id}`,
|
|
10532
|
+
role: "task-label",
|
|
10533
|
+
target: row.id,
|
|
10534
|
+
x: outside ? row.x + row.width + 6 : row.x + row.width / 2,
|
|
10535
|
+
y: row.y + row.height / 2,
|
|
10536
|
+
text: label,
|
|
10537
|
+
anchor: outside ? "start" : "middle",
|
|
10538
|
+
baseline: "middle",
|
|
10539
|
+
size: 12,
|
|
10540
|
+
fill: outside ? theme.text : colours2.text,
|
|
10541
|
+
...row.milestone ? { italic: true } : {}
|
|
10542
|
+
});
|
|
10543
|
+
}
|
|
10544
|
+
if (graph.title)
|
|
10545
|
+
marks.push({ kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: left + fullWidth / 2, y: geo.top - 38, text: graph.title, anchor: "middle", baseline: "middle", size: 18, weight: 600, fill: theme.text });
|
|
10546
|
+
return marks;
|
|
10547
|
+
};
|
|
10548
|
+
|
|
10549
|
+
// src/canvas/mermaid/families/timeline.ts
|
|
10550
|
+
var M8 = TIMELINE_METRICS;
|
|
10551
|
+
var RADIUS = 5;
|
|
10552
|
+
var TEXT_TOP = 17;
|
|
10553
|
+
var TEXT_LINE = M8.fontSize * 1.1;
|
|
10554
|
+
function colours(theme, colour) {
|
|
10555
|
+
if (colour === "root") return { fill: theme.nodeStroke, text: theme.background };
|
|
10556
|
+
return { fill: sceneColor(theme, colour), text: theme.paletteText, line: sceneColor(theme, colour + 6) };
|
|
10557
|
+
}
|
|
10558
|
+
function boxPath({ x, y, width: w, height: h }) {
|
|
10559
|
+
const r = Math.min(RADIUS, w / 2, h / 2);
|
|
10560
|
+
return `M ${x} ${y + r} Q ${x} ${y} ${x + r} ${y} L ${x + w - r} ${y} Q ${x + w} ${y} ${x + w} ${y + r} L ${x + w} ${y + h} L ${x} ${y + h} Z`;
|
|
10561
|
+
}
|
|
10562
|
+
function wrap(text2, width) {
|
|
10563
|
+
const out = [];
|
|
10564
|
+
for (const part of String(text2).split(/<br\s*\/?>|\n/i)) {
|
|
10565
|
+
let line4 = "";
|
|
10566
|
+
for (const word of part.split(/\s+/).filter(Boolean)) {
|
|
10567
|
+
const next = line4 ? `${line4} ${word}` : word;
|
|
10568
|
+
if (line4 && textWidth(next) > width) {
|
|
10569
|
+
out.push(line4);
|
|
10570
|
+
line4 = word;
|
|
10571
|
+
} else line4 = next;
|
|
10572
|
+
}
|
|
10573
|
+
out.push(line4);
|
|
10574
|
+
}
|
|
10575
|
+
return out.length ? out : [""];
|
|
10576
|
+
}
|
|
10577
|
+
function arrowLine(key, x1, y1, x2, y2, width, dashed, colour) {
|
|
10578
|
+
const len = Math.hypot(x2 - x1, y2 - y1) || 1;
|
|
10579
|
+
const ux = (x2 - x1) / len;
|
|
10580
|
+
const uy = (y2 - y1) / len;
|
|
10581
|
+
const bx = x2 - ux * 5 * width;
|
|
10582
|
+
const by = y2 - uy * 5 * width;
|
|
10583
|
+
const tx = x2 + ux * width;
|
|
10584
|
+
const ty = y2 + uy * width;
|
|
10585
|
+
return [
|
|
10586
|
+
{ kind: "line", key, role: dashed ? "event-line" : "axis", x1, y1, x2, y2, stroke: colour, strokeWidth: width, ...dashed ? { dash: "5,5" } : {} },
|
|
10587
|
+
{
|
|
10588
|
+
kind: "path",
|
|
10589
|
+
key: `${key}:head`,
|
|
10590
|
+
role: dashed ? "event-line" : "axis",
|
|
10591
|
+
d: `M ${bx - uy * 2 * width} ${by + ux * 2 * width} L ${tx} ${ty} L ${bx + uy * 2 * width} ${by - ux * 2 * width} Z`,
|
|
10592
|
+
fill: colour
|
|
10593
|
+
}
|
|
10594
|
+
];
|
|
10595
|
+
}
|
|
10596
|
+
var timelineScene = ({ graph, theme }) => {
|
|
10597
|
+
const geo = timelineGeometry(graph);
|
|
10598
|
+
const marks = [];
|
|
10599
|
+
const nodes = new Map(graph.nodes.map((n3) => [n3.id, n3]));
|
|
10600
|
+
const groups = new Map(graph.groups.map((g) => [g.id, g]));
|
|
10601
|
+
const line4 = theme.text;
|
|
10602
|
+
const box = (key, role, target, b, colour, text2, opacity, brighten = false) => {
|
|
10603
|
+
const c = colours(theme, colour);
|
|
10604
|
+
marks.push({ kind: "path", key, role, target, d: boxPath(b), fill: c.fill, ...opacity !== void 0 ? { opacity } : {} });
|
|
10605
|
+
if (brighten) marks.push({ kind: "path", key: `${key}:wash`, role, target, d: boxPath(b), fill: theme.background, opacity: 0.2 });
|
|
10606
|
+
if (c.line) marks.push({ kind: "line", key: `${key}:line`, role, target, x1: b.x, y1: b.y + b.height, x2: b.x + b.width, y2: b.y + b.height, stroke: c.line, strokeWidth: 3 });
|
|
10607
|
+
wrap(text2, b.width - 2 * M8.padding).forEach(
|
|
10608
|
+
(t, i) => marks.push({ kind: "text", key: `${key}:text:${i}`, role: `${role}-label`, target, x: b.x + b.width / 2, y: b.y + TEXT_TOP + TEXT_LINE * (i + 0.5), text: t, anchor: "middle", baseline: "middle", size: M8.fontSize, fill: c.text })
|
|
10609
|
+
);
|
|
10610
|
+
};
|
|
10611
|
+
for (const l of geo.eventLines) marks.push(...arrowLine(`event-line:${l.periodId}`, l.x, l.y1, l.x, l.y2, M8.eventLineWidth, true, line4));
|
|
10612
|
+
marks.push(...arrowLine("axis", geo.axis.x1, geo.axis.y, geo.axis.x2, geo.axis.y, M8.axisWidth, false, line4));
|
|
10613
|
+
for (const e of geo.events) box(`event:${e.periodId}:${e.index}`, "event", e.periodId, e, e.colour, e.text, void 0, true);
|
|
10614
|
+
for (const s of geo.sections.values()) box(`section:${s.id}`, "section", s.id, s, s.colour, groups.get(s.id)?.label ?? s.id, s.empty ? 0.6 : void 0);
|
|
10615
|
+
for (const p of geo.periods.values()) {
|
|
10616
|
+
const node = nodes.get(p.id);
|
|
10617
|
+
box(`period:${p.id}`, "period", p.id, p, p.colour, node?.label ?? p.id);
|
|
10618
|
+
}
|
|
10619
|
+
if (graph.title)
|
|
10620
|
+
marks.push({ kind: "text", key: "title", role: "title", target: DIAGRAM_TITLE_TARGET, x: geo.title.x, y: geo.title.baseline, text: graph.title, anchor: "start", baseline: "bottom", size: 32, weight: 700, fill: theme.text });
|
|
10621
|
+
return marks;
|
|
10622
|
+
};
|
|
10623
|
+
|
|
10624
|
+
// src/canvas/mermaid/families/index.ts
|
|
10625
|
+
var BUILTIN_FAMILY_SCENES = {
|
|
10626
|
+
pie: pieScene,
|
|
10627
|
+
xychart: xyChartScene,
|
|
10628
|
+
radar: radarScene,
|
|
10629
|
+
sequence: sequenceScene,
|
|
10630
|
+
journey: journeyScene,
|
|
10631
|
+
quadrant: quadrantScene,
|
|
10632
|
+
gitGraph: gitGraphScene,
|
|
10633
|
+
mindmap: mindmapScene,
|
|
10634
|
+
c4: c4Scene,
|
|
10635
|
+
architecture: architectureScene,
|
|
10636
|
+
gantt: ganttScene,
|
|
10637
|
+
timeline: timelineScene
|
|
10638
|
+
};
|
|
10639
|
+
|
|
10640
|
+
// src/canvas/mermaid/scene.ts
|
|
10641
|
+
var scenes = new Map(Object.entries(BUILTIN_FAMILY_SCENES));
|
|
10642
|
+
function registerFamilyScene(family, scene) {
|
|
10643
|
+
scenes.set(family, scene);
|
|
10644
|
+
}
|
|
10645
|
+
function getFamilyScene(family) {
|
|
10646
|
+
return scenes.get(family);
|
|
10647
|
+
}
|
|
10648
|
+
function hasFamilyScene(family) {
|
|
10649
|
+
return scenes.has(family);
|
|
10650
|
+
}
|
|
10651
|
+
function markBounds(mark) {
|
|
10652
|
+
switch (mark.kind) {
|
|
10653
|
+
case "rect":
|
|
10654
|
+
return [mark.x, mark.y, mark.x + mark.width, mark.y + mark.height];
|
|
10655
|
+
case "circle":
|
|
10656
|
+
return [mark.cx - mark.r, mark.cy - mark.r, mark.cx + mark.r, mark.cy + mark.r];
|
|
10657
|
+
case "line":
|
|
10658
|
+
return [Math.min(mark.x1, mark.x2), Math.min(mark.y1, mark.y2), Math.max(mark.x1, mark.x2), Math.max(mark.y1, mark.y2)];
|
|
10659
|
+
case "text": {
|
|
10660
|
+
const w = estimateTextWidth2(mark.text, mark.size);
|
|
10661
|
+
const x0 = mark.anchor === "start" ? mark.x : mark.anchor === "end" ? mark.x - w : mark.x - w / 2;
|
|
10662
|
+
const y0 = mark.baseline === "top" ? mark.y : mark.baseline === "bottom" ? mark.y - mark.size * 1.2 : mark.y - mark.size * 0.6;
|
|
10663
|
+
if (mark.rotate) {
|
|
10664
|
+
const r = Math.max(w, mark.size * 1.2);
|
|
10665
|
+
return [mark.x - r, mark.y - r, mark.x + r, mark.y + r];
|
|
10666
|
+
}
|
|
10667
|
+
return [x0, y0, x0 + w, y0 + mark.size * 1.2];
|
|
10668
|
+
}
|
|
10669
|
+
case "path": {
|
|
10670
|
+
if (mark.box) return [mark.box.x, mark.box.y, mark.box.x + mark.box.width, mark.box.y + mark.box.height];
|
|
10671
|
+
const nums = mark.d.match(/-?\d*\.?\d+(?:e-?\d+)?/gi)?.map(Number) ?? [];
|
|
10672
|
+
if (nums.length < 2) return null;
|
|
10673
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
10674
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
10675
|
+
x0 = Math.min(x0, nums[i]);
|
|
10676
|
+
y0 = Math.min(y0, nums[i + 1]);
|
|
10677
|
+
x1 = Math.max(x1, nums[i]);
|
|
10678
|
+
y1 = Math.max(y1, nums[i + 1]);
|
|
10679
|
+
}
|
|
10680
|
+
return [x0, y0, x1, y1];
|
|
10681
|
+
}
|
|
10682
|
+
}
|
|
10683
|
+
}
|
|
10684
|
+
function diagramMarksBounds(marks) {
|
|
10685
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
10686
|
+
for (const mark of marks) {
|
|
10687
|
+
const b = markBounds(mark);
|
|
10688
|
+
if (!b) continue;
|
|
10689
|
+
x0 = Math.min(x0, b[0]);
|
|
10690
|
+
y0 = Math.min(y0, b[1]);
|
|
10691
|
+
x1 = Math.max(x1, b[2]);
|
|
10692
|
+
y1 = Math.max(y1, b[3]);
|
|
10693
|
+
}
|
|
10694
|
+
if (x0 === Infinity) return { x: 0, y: 0, width: 0, height: 0 };
|
|
10695
|
+
return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
|
|
10696
|
+
}
|
|
10697
|
+
function mermaidToScene(doc, options = {}) {
|
|
10698
|
+
const scene = scenes.get(doc.family);
|
|
10699
|
+
if (!scene || doc.tier !== "editable") return null;
|
|
10700
|
+
const layout2 = options.layout ?? ensureDiagramLayout(doc.graph, doc.meta, { family: doc.family, ...options });
|
|
10701
|
+
return familySceneFromLayout(doc.family, doc.graph, layout2, options);
|
|
10702
|
+
}
|
|
10703
|
+
function familySceneFromLayout(family, graph, layout2, options = {}) {
|
|
10704
|
+
const scene = scenes.get(family);
|
|
10705
|
+
if (!scene) return null;
|
|
10706
|
+
const theme = { ...DIAGRAM_SCENE_LIGHT_THEME, ...options.theme };
|
|
10707
|
+
const selection = new Set(options.selection ?? []);
|
|
10708
|
+
const marks = scene({ graph, layout: layout2, theme, selection }).map((m) => m.target && selection.has(m.target) ? { ...m, selected: true } : m);
|
|
10709
|
+
return { family, ...diagramMarksBounds(marks), marks };
|
|
10710
|
+
}
|
|
10711
|
+
var esc = (text2) => text2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
10712
|
+
var num3 = (v) => String(Math.round(v * 100) / 100);
|
|
10713
|
+
function diagramTextBaseline(baseline) {
|
|
10714
|
+
return baseline === "top" ? "hanging" : baseline === "bottom" ? "text-after-edge" : "central";
|
|
10715
|
+
}
|
|
10716
|
+
var DIAGRAM_MARKER_IDS = { arrow: "pd-arrow-open", arrowclosed: "pd-arrow-closed" };
|
|
10717
|
+
function diagramMarksToSvg(marks, theme = DIAGRAM_SCENE_LIGHT_THEME) {
|
|
10718
|
+
const out = [];
|
|
10719
|
+
for (const m of marks) {
|
|
10720
|
+
const common = `${m.target ? ` data-target="${esc(m.target)}"` : ""}${m.opacity !== void 0 ? ` opacity="${num3(m.opacity)}"` : ""}`;
|
|
10721
|
+
const sel = m.selected ? ` stroke="${esc(theme.selection)}" stroke-width="2"` : "";
|
|
10722
|
+
const markers = (mk) => `${mk.markerEnd ? ` marker-end="url(#${DIAGRAM_MARKER_IDS[mk.markerEnd]})"` : ""}${mk.markerStart ? ` marker-start="url(#${DIAGRAM_MARKER_IDS[mk.markerStart]})"` : ""}`;
|
|
10723
|
+
switch (m.kind) {
|
|
10724
|
+
case "rect":
|
|
10725
|
+
out.push(
|
|
10726
|
+
`<rect x="${num3(m.x)}" y="${num3(m.y)}" width="${num3(Math.max(0, m.width))}" height="${num3(Math.max(0, m.height))}"${m.radius ? ` rx="${num3(m.radius)}"` : ""} fill="${esc(m.fill)}"${sel || (m.stroke ? ` stroke="${esc(m.stroke)}" stroke-width="${num3(m.strokeWidth ?? 1)}"` : "")}${m.dash ? ` stroke-dasharray="${m.dash}"` : ""}${common}/>`
|
|
10727
|
+
);
|
|
10728
|
+
break;
|
|
10729
|
+
case "circle":
|
|
10730
|
+
out.push(
|
|
10731
|
+
`<circle cx="${num3(m.cx)}" cy="${num3(m.cy)}" r="${num3(m.r)}" fill="${esc(m.fill)}"${sel || (m.stroke ? ` stroke="${esc(m.stroke)}" stroke-width="${num3(m.strokeWidth ?? 1)}"` : "")}${common}/>`
|
|
10732
|
+
);
|
|
10733
|
+
break;
|
|
10734
|
+
case "line":
|
|
10735
|
+
out.push(
|
|
10736
|
+
`<line x1="${num3(m.x1)}" y1="${num3(m.y1)}" x2="${num3(m.x2)}" y2="${num3(m.y2)}" stroke="${esc(m.selected ? theme.selection : m.stroke)}" stroke-width="${num3(m.strokeWidth ?? 1)}"${m.dash ? ` stroke-dasharray="${m.dash}"` : ""}${markers(m)}${common}/>`
|
|
10737
|
+
);
|
|
10738
|
+
break;
|
|
10739
|
+
case "path":
|
|
10740
|
+
out.push(
|
|
10741
|
+
`<path d="${m.d}" fill="${esc(m.fill ?? "none")}"${sel || (m.stroke ? ` stroke="${esc(m.stroke)}" stroke-width="${num3(m.strokeWidth ?? 1)}"` : "")}${m.dash ? ` stroke-dasharray="${m.dash}"` : ""}${markers(m)}${common}/>`
|
|
10742
|
+
);
|
|
10743
|
+
break;
|
|
10744
|
+
case "text":
|
|
10745
|
+
out.push(
|
|
10746
|
+
`<text x="${num3(m.x)}" y="${num3(m.y)}" text-anchor="${m.anchor}" dominant-baseline="${diagramTextBaseline(m.baseline)}" font-size="${num3(m.size)}"${m.weight ? ` font-weight="${m.weight}"` : ""}${m.italic ? ' font-style="italic"' : ""} fill="${esc(m.fill)}"${m.rotate ? ` transform="rotate(${num3(m.rotate)} ${num3(m.x)} ${num3(m.y)})"` : ""}${common}>${esc(m.text)}</text>`
|
|
10747
|
+
);
|
|
10748
|
+
break;
|
|
10749
|
+
}
|
|
10750
|
+
}
|
|
10751
|
+
return out.join("");
|
|
10752
|
+
}
|
|
10753
|
+
var CSS_VARIABLE_DIAGRAM_SCENE_THEME = {
|
|
10754
|
+
...DIAGRAM_SCENE_LIGHT_THEME,
|
|
10755
|
+
background: "var(--background, #ffffff)",
|
|
10756
|
+
nodeFill: "var(--background, #ffffff)",
|
|
10757
|
+
nodeStroke: "var(--foreground, #0f172a)",
|
|
10758
|
+
text: "var(--foreground, #0f172a)",
|
|
10759
|
+
edge: "var(--muted-foreground, #64748b)",
|
|
10760
|
+
edgeLabelBackground: "var(--background, #ffffff)",
|
|
10761
|
+
groupFill: "var(--muted, #f8fafc)",
|
|
10762
|
+
groupStroke: "var(--border, #cbd5e1)",
|
|
10763
|
+
groupText: "var(--muted-foreground, #475569)",
|
|
10764
|
+
grid: "var(--border, #cbd5e1)",
|
|
10765
|
+
mutedText: "var(--muted-foreground, #64748b)",
|
|
10766
|
+
selection: "var(--primary, #2563eb)",
|
|
10767
|
+
fontFamily: "inherit"
|
|
10768
|
+
};
|
|
10769
|
+
function diagramRenameOp(doc, target, label) {
|
|
10770
|
+
const { graph } = doc;
|
|
10771
|
+
if (target === DIAGRAM_TITLE_TARGET) return { type: "setTitle", title: label.trim() || void 0 };
|
|
10772
|
+
if (graph.groups.some((g) => g.id === target)) return { type: "renameGroup", id: target, label };
|
|
10773
|
+
if (graph.edges.some((e) => e.id === target)) return { type: "setEdgeLabel", id: target, label };
|
|
10774
|
+
if (graph.nodes.some((n3) => n3.id === target)) return { type: "renameNode", id: target, label };
|
|
10775
|
+
return null;
|
|
10776
|
+
}
|
|
10777
|
+
function diagramTargetLabel(doc, target) {
|
|
10778
|
+
const { graph } = doc;
|
|
10779
|
+
if (target === DIAGRAM_TITLE_TARGET) return graph.title ?? "";
|
|
10780
|
+
return graph.groups.find((g) => g.id === target)?.label ?? graph.edges.find((e) => e.id === target)?.label ?? graph.nodes.find((n3) => n3.id === target)?.label ?? null;
|
|
10781
|
+
}
|
|
10782
|
+
|
|
8866
10783
|
// src/canvas/mermaid/shapes.ts
|
|
8867
10784
|
var n = (v) => Math.round(v * 100) / 100;
|
|
8868
10785
|
var poly = (points) => `M${points.map(([x, y]) => `${n(x)},${n(y)}`).join(" L")} Z`;
|
|
@@ -8871,8 +10788,8 @@ var rect = (x, y, w, h, r = 0) => {
|
|
|
8871
10788
|
const rr = Math.min(r, w / 2, h / 2);
|
|
8872
10789
|
return `M${n(x + rr)},${n(y)} H${n(x + w - rr)} A${n(rr)},${n(rr)} 0 0 1 ${n(x + w)},${n(y + rr)} V${n(y + h - rr)} A${n(rr)},${n(rr)} 0 0 1 ${n(x + w - rr)},${n(y + h)} H${n(x + rr)} A${n(rr)},${n(rr)} 0 0 1 ${n(x)},${n(y + h - rr)} V${n(y + rr)} A${n(rr)},${n(rr)} 0 0 1 ${n(x + rr)},${n(y)} Z`;
|
|
8873
10790
|
};
|
|
8874
|
-
var
|
|
8875
|
-
var
|
|
10791
|
+
var ellipse2 = (cx, cy, rx, ry) => `M${n(cx - rx)},${n(cy)} A${n(rx)},${n(ry)} 0 1 0 ${n(cx + rx)},${n(cy)} A${n(rx)},${n(ry)} 0 1 0 ${n(cx - rx)},${n(cy)} Z`;
|
|
10792
|
+
var line3 = (x1, y1, x2, y2) => `M${n(x1)},${n(y1)} L${n(x2)},${n(y2)}`;
|
|
8876
10793
|
function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
8877
10794
|
const s = inset;
|
|
8878
10795
|
const W = Math.max(0, width - 2 * s);
|
|
@@ -8895,7 +10812,7 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
8895
10812
|
case "subproc":
|
|
8896
10813
|
case "subroutine": {
|
|
8897
10814
|
const i = Math.min(10, W / 8);
|
|
8898
|
-
return [fill(rect(x0, y0, W, H)), stroke(
|
|
10815
|
+
return [fill(rect(x0, y0, W, H)), stroke(line3(x0 + i, y0, x0 + i, y1)), stroke(line3(x1 - i, y0, x1 - i, y1))];
|
|
8899
10816
|
}
|
|
8900
10817
|
case "cyl":
|
|
8901
10818
|
case "cylinder": {
|
|
@@ -8910,28 +10827,28 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
8910
10827
|
const rx = Math.min(W / 6, 14);
|
|
8911
10828
|
const paths = [
|
|
8912
10829
|
fill(`M${n(x0 + rx)},${n(y0)} L${n(x1 - rx)},${n(y0)} A${n(rx)},${n(H / 2)} 0 0 1 ${n(x1 - rx)},${n(y1)} L${n(x0 + rx)},${n(y1)} A${n(rx)},${n(H / 2)} 0 0 1 ${n(x0 + rx)},${n(y0)} Z`),
|
|
8913
|
-
stroke(
|
|
10830
|
+
stroke(ellipse2(x1 - rx, cy, rx, H / 2))
|
|
8914
10831
|
];
|
|
8915
|
-
if (shape === "lin-cyl") paths.push(stroke(
|
|
10832
|
+
if (shape === "lin-cyl") paths.push(stroke(line3(x0 + rx * 2, y0, x0 + rx * 2, y1)));
|
|
8916
10833
|
return paths;
|
|
8917
10834
|
}
|
|
8918
10835
|
case "circle":
|
|
8919
10836
|
case "circ":
|
|
8920
|
-
return [fill(
|
|
10837
|
+
return [fill(ellipse2(cx, cy, W / 2, H / 2))];
|
|
8921
10838
|
case "dbl-circ":
|
|
8922
|
-
return [fill(
|
|
10839
|
+
return [fill(ellipse2(cx, cy, W / 2, H / 2)), stroke(ellipse2(cx, cy, Math.max(0, W / 2 - 5), Math.max(0, H / 2 - 5)))];
|
|
8923
10840
|
case "sm-circ":
|
|
8924
10841
|
case "f-circ":
|
|
8925
10842
|
case "stateStart":
|
|
8926
|
-
return [solid(
|
|
10843
|
+
return [solid(ellipse2(cx, cy, W / 2, H / 2))];
|
|
8927
10844
|
case "fr-circ":
|
|
8928
10845
|
case "stateEnd":
|
|
8929
|
-
return [fill(
|
|
10846
|
+
return [fill(ellipse2(cx, cy, W / 2, H / 2)), solid(ellipse2(cx, cy, Math.max(0, W / 2 - 5), Math.max(0, H / 2 - 5)))];
|
|
8930
10847
|
case "cross-circ":
|
|
8931
10848
|
return [
|
|
8932
|
-
fill(
|
|
8933
|
-
stroke(
|
|
8934
|
-
stroke(
|
|
10849
|
+
fill(ellipse2(cx, cy, W / 2, H / 2)),
|
|
10850
|
+
stroke(line3(cx - W / 2.83, cy - H / 2.83, cx + W / 2.83, cy + H / 2.83)),
|
|
10851
|
+
stroke(line3(cx + W / 2.83, cy - H / 2.83, cx - W / 2.83, cy + H / 2.83))
|
|
8935
10852
|
];
|
|
8936
10853
|
case "odd":
|
|
8937
10854
|
case "asymmetric": {
|
|
@@ -8973,7 +10890,7 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
8973
10890
|
}
|
|
8974
10891
|
case "lin-rect":
|
|
8975
10892
|
case "shaded-process":
|
|
8976
|
-
return [fill(rect(x0, y0, W, H)), stroke(
|
|
10893
|
+
return [fill(rect(x0, y0, W, H)), stroke(line3(x0 + 8, y0, x0 + 8, y1))];
|
|
8977
10894
|
case "fork":
|
|
8978
10895
|
case "join":
|
|
8979
10896
|
return [solid(rect(x0, y0, W, H, 2))];
|
|
@@ -8986,8 +10903,8 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
8986
10903
|
case "tag-doc": {
|
|
8987
10904
|
const wave = Math.min(12, H / 5);
|
|
8988
10905
|
const paths = [fill(`M${n(x0)},${n(y0)} L${n(x1)},${n(y0)} L${n(x1)},${n(y1 - wave)} Q${n(x1 - W / 4)},${n(y1 - wave * 2.2)} ${n(cx)},${n(y1 - wave)} T${n(x0)},${n(y1 - wave)} Z`)];
|
|
8989
|
-
if (shape === "lin-doc") paths.push(stroke(
|
|
8990
|
-
if (shape === "tag-doc") paths.push(stroke(
|
|
10906
|
+
if (shape === "lin-doc") paths.push(stroke(line3(x0 + 8, y0, x0 + 8, y1 - wave)));
|
|
10907
|
+
if (shape === "tag-doc") paths.push(stroke(line3(x1 - 12, y1 - wave * 1.6, x1, y1 - wave * 2.6)));
|
|
8991
10908
|
return paths;
|
|
8992
10909
|
}
|
|
8993
10910
|
case "docs": {
|
|
@@ -9003,14 +10920,14 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
9003
10920
|
}
|
|
9004
10921
|
case "div-rect": {
|
|
9005
10922
|
const d = Math.min(24, H / 3);
|
|
9006
|
-
return [fill(rect(x0, y0, W, H)), stroke(
|
|
10923
|
+
return [fill(rect(x0, y0, W, H)), stroke(line3(x0, y0 + d, x1, y0 + d))];
|
|
9007
10924
|
}
|
|
9008
10925
|
case "tri":
|
|
9009
10926
|
return [fill(poly([[cx, y0], [x1, y1], [x0, y1]]))];
|
|
9010
10927
|
case "flip-tri":
|
|
9011
10928
|
return [fill(poly([[x0, y0], [x1, y0], [cx, y1]]))];
|
|
9012
10929
|
case "win-pane":
|
|
9013
|
-
return [fill(rect(x0, y0, W, H)), stroke(
|
|
10930
|
+
return [fill(rect(x0, y0, W, H)), stroke(line3(x0 + 10, y0, x0 + 10, y1)), stroke(line3(x0, y0 + 10, x1, y0 + 10))];
|
|
9014
10931
|
case "flag": {
|
|
9015
10932
|
const wave = Math.min(10, H / 5);
|
|
9016
10933
|
return [fill(`M${n(x0)},${n(y0 + wave)} Q${n(x0 + W / 4)},${n(y0 - wave)} ${n(cx)},${n(y0 + wave)} T${n(x1)},${n(y0 + wave)} L${n(x1)},${n(y1 - wave)} Q${n(x1 - W / 4)},${n(y1 + wave)} ${n(cx)},${n(y1 - wave)} T${n(x0)},${n(y1 - wave)} Z`)];
|
|
@@ -9022,7 +10939,7 @@ function mermaidShapePaths(shape, width, height, inset = 1) {
|
|
|
9022
10939
|
return [fill(`M${n(x0)},${n(y0)} Q${n(x0 + d)},${n(cy)} ${n(x0)},${n(y1)} L${n(x1)},${n(y1)} Q${n(x1 - d)},${n(cy)} ${n(x1)},${n(y0)} Z`)];
|
|
9023
10940
|
}
|
|
9024
10941
|
case "tag-rect":
|
|
9025
|
-
return [fill(rect(x0, y0, W, H)), stroke(
|
|
10942
|
+
return [fill(rect(x0, y0, W, H)), stroke(line3(x1 - 14, y1, x1, y1 - 14))];
|
|
9026
10943
|
case "notch-pent": {
|
|
9027
10944
|
const d = Math.min(W / 6, H / 3);
|
|
9028
10945
|
return [fill(poly([[x0 + d, y0], [x1 - d, y0], [x1, y0 + d], [x1, y1], [x0, y1], [x0, y0 + d]]))];
|
|
@@ -9075,7 +10992,7 @@ var MERMAID_SHAPE_PAINT = {
|
|
|
9075
10992
|
hidden: { fill: "transparent", stroke: "none" }
|
|
9076
10993
|
};
|
|
9077
10994
|
function mermaidLabelLines(label) {
|
|
9078
|
-
return String(label).replace(/^"`?|`?"$/g, "").split(/<br\s*\/?>|\n/i).map((
|
|
10995
|
+
return String(label).replace(/^"`?|`?"$/g, "").split(/<br\s*\/?>|\n/i).map((line4) => line4.replace(/<[^>]+>/g, ""));
|
|
9079
10996
|
}
|
|
9080
10997
|
function mermaidNodeMembers(data) {
|
|
9081
10998
|
const list = [...data?.members ?? [], ...data?.attributes ?? []];
|
|
@@ -9083,33 +11000,7 @@ function mermaidNodeMembers(data) {
|
|
|
9083
11000
|
}
|
|
9084
11001
|
|
|
9085
11002
|
// src/canvas/mermaid/export.ts
|
|
9086
|
-
var
|
|
9087
|
-
background: "#ffffff",
|
|
9088
|
-
nodeFill: "#ffffff",
|
|
9089
|
-
nodeStroke: "#0f172a",
|
|
9090
|
-
text: "#0f172a",
|
|
9091
|
-
edge: "#64748b",
|
|
9092
|
-
edgeLabelBackground: "#ffffff",
|
|
9093
|
-
groupFill: "#f8fafc",
|
|
9094
|
-
groupStroke: "#cbd5e1",
|
|
9095
|
-
groupText: "#475569",
|
|
9096
|
-
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
9097
|
-
fontSize: 13
|
|
9098
|
-
};
|
|
9099
|
-
var DIAGRAM_SVG_DARK_THEME = {
|
|
9100
|
-
background: "#0f172a",
|
|
9101
|
-
nodeFill: "#1e293b",
|
|
9102
|
-
nodeStroke: "#e2e8f0",
|
|
9103
|
-
text: "#f1f5f9",
|
|
9104
|
-
edge: "#94a3b8",
|
|
9105
|
-
edgeLabelBackground: "#0f172a",
|
|
9106
|
-
groupFill: "#111c33",
|
|
9107
|
-
groupStroke: "#334155",
|
|
9108
|
-
groupText: "#94a3b8",
|
|
9109
|
-
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
9110
|
-
fontSize: 13
|
|
9111
|
-
};
|
|
9112
|
-
var esc = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
11003
|
+
var esc2 = (text2) => text2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
9113
11004
|
var n2 = (v) => String(Math.round(v * 100) / 100);
|
|
9114
11005
|
function exitPoint(box, to) {
|
|
9115
11006
|
const cx = box.x + box.width / 2;
|
|
@@ -9126,19 +11017,25 @@ function mermaidToSvg(doc, options = {}) {
|
|
|
9126
11017
|
const theme = { ...DIAGRAM_SVG_LIGHT_THEME, ...options.theme };
|
|
9127
11018
|
const pad = options.padding ?? 16;
|
|
9128
11019
|
const graph = doc.graph;
|
|
9129
|
-
const layout2 = options.layout ?? ensureDiagramLayout(graph, doc.meta, options);
|
|
9130
|
-
const
|
|
11020
|
+
const layout2 = options.layout ?? ensureDiagramLayout(graph, doc.meta, { family: doc.family, ...options });
|
|
11021
|
+
const boxOf2 = (id) => {
|
|
9131
11022
|
const p = layout2.positions[id];
|
|
9132
11023
|
if (!p) return null;
|
|
9133
11024
|
const s = layout2.sizes[id] ?? { width: 160, height: 56 };
|
|
9134
11025
|
return { x: p[0], y: p[1], width: s.width, height: s.height };
|
|
9135
11026
|
};
|
|
11027
|
+
const scene = doc.tier === "editable" ? familySceneFromLayout(doc.family, graph, layout2, { theme: { ...DIAGRAM_SCENE_LIGHT_THEME, ...theme } }) : null;
|
|
9136
11028
|
let minX = Infinity;
|
|
9137
11029
|
let minY = Infinity;
|
|
9138
11030
|
let maxX = -Infinity;
|
|
9139
11031
|
let maxY = -Infinity;
|
|
9140
|
-
|
|
9141
|
-
|
|
11032
|
+
if (scene && scene.marks.length) {
|
|
11033
|
+
minX = scene.x;
|
|
11034
|
+
minY = scene.y;
|
|
11035
|
+
maxX = scene.x + scene.width;
|
|
11036
|
+
maxY = scene.y + scene.height;
|
|
11037
|
+
} else for (const id of Object.keys(layout2.positions)) {
|
|
11038
|
+
const b = boxOf2(id);
|
|
9142
11039
|
minX = Math.min(minX, b.x);
|
|
9143
11040
|
minY = Math.min(minY, b.y);
|
|
9144
11041
|
maxX = Math.max(maxX, b.x + b.width);
|
|
@@ -9156,15 +11053,19 @@ function mermaidToSvg(doc, options = {}) {
|
|
|
9156
11053
|
const title = options.title ?? graph.title ?? `${doc.family} diagram`;
|
|
9157
11054
|
const out = [];
|
|
9158
11055
|
out.push(
|
|
9159
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${naturalWidth} ${naturalHeight}" role="img" aria-label="${
|
|
9160
|
-
`<title>${
|
|
11056
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${naturalWidth} ${naturalHeight}" role="img" aria-label="${esc2(title)}" font-family="${esc2(theme.fontFamily)}" font-size="${fs}">`,
|
|
11057
|
+
`<title>${esc2(title)}</title>`,
|
|
9161
11058
|
"<defs>",
|
|
9162
|
-
`<marker id="pd-arrow-closed" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 Z" fill="${
|
|
9163
|
-
`<marker id="pd-arrow-open" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10" fill="none" stroke="${
|
|
11059
|
+
`<marker id="pd-arrow-closed" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 Z" fill="${esc2(theme.edge)}"/></marker>`,
|
|
11060
|
+
`<marker id="pd-arrow-open" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10" fill="none" stroke="${esc2(theme.edge)}" stroke-width="1.5"/></marker>`,
|
|
9164
11061
|
"</defs>"
|
|
9165
11062
|
);
|
|
9166
|
-
if (!options.transparent) out.push(`<rect width="${naturalWidth}" height="${naturalHeight}" fill="${
|
|
11063
|
+
if (!options.transparent) out.push(`<rect width="${naturalWidth}" height="${naturalHeight}" fill="${esc2(theme.background)}"/>`);
|
|
9167
11064
|
out.push(`<g transform="translate(${n2(ox)} ${n2(oy)})">`);
|
|
11065
|
+
if (scene) {
|
|
11066
|
+
out.push(diagramMarksToSvg(scene.marks, { ...DIAGRAM_SCENE_LIGHT_THEME, ...theme }), "</g></svg>");
|
|
11067
|
+
return { svg: out.join(""), width, height, naturalWidth, naturalHeight };
|
|
11068
|
+
}
|
|
9168
11069
|
const depth2 = (id) => {
|
|
9169
11070
|
let d = 0;
|
|
9170
11071
|
let cur = graph.groups.find((g) => g.id === id)?.parentId;
|
|
@@ -9175,17 +11076,17 @@ function mermaidToSvg(doc, options = {}) {
|
|
|
9175
11076
|
return d;
|
|
9176
11077
|
};
|
|
9177
11078
|
for (const g of [...graph.groups].sort((a, b) => depth2(a.id) - depth2(b.id))) {
|
|
9178
|
-
const b =
|
|
11079
|
+
const b = boxOf2(g.id);
|
|
9179
11080
|
if (!b) continue;
|
|
9180
11081
|
const st = resolveMermaidStyles(g.classes, g.styles, graph.classDefs);
|
|
9181
11082
|
out.push(
|
|
9182
|
-
`<g data-group="${
|
|
9183
|
-
`<text x="${n2(b.x + 10)}" y="${n2(b.y + 18)}" fill="${
|
|
11083
|
+
`<g data-group="${esc2(g.id)}"><rect x="${n2(b.x)}" y="${n2(b.y)}" width="${n2(b.width)}" height="${n2(b.height)}" rx="8" fill="${esc2(st.fill ?? theme.groupFill)}" stroke="${esc2(st.stroke ?? theme.groupStroke)}" stroke-dasharray="4 3"/>`,
|
|
11084
|
+
`<text x="${n2(b.x + 10)}" y="${n2(b.y + 18)}" fill="${esc2(st.color ?? theme.groupText)}" font-size="${fs - 1}" font-weight="600">${esc2(mermaidLabelLines(g.label).join(" "))}</text></g>`
|
|
9184
11085
|
);
|
|
9185
11086
|
}
|
|
9186
11087
|
for (const e of graph.edges) {
|
|
9187
|
-
const a =
|
|
9188
|
-
const b =
|
|
11088
|
+
const a = boxOf2(e.source);
|
|
11089
|
+
const b = boxOf2(e.target);
|
|
9189
11090
|
if (!a || !b || e.pattern === "invisible") continue;
|
|
9190
11091
|
const ca = { x: a.x + a.width / 2, y: a.y + a.height / 2 };
|
|
9191
11092
|
const cb = { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
@@ -9197,41 +11098,41 @@ function mermaidToSvg(doc, options = {}) {
|
|
|
9197
11098
|
const marker = (m) => m === "arrow" ? "url(#pd-arrow-open)" : m ? "url(#pd-arrow-closed)" : "";
|
|
9198
11099
|
const dash = mermaidEdgeDash(e.pattern);
|
|
9199
11100
|
out.push(
|
|
9200
|
-
`<line data-edge="${
|
|
11101
|
+
`<line data-edge="${esc2(e.id)}" x1="${n2(p.x)}" y1="${n2(p.y)}" x2="${n2(q.x)}" y2="${n2(q.y)}" stroke="${esc2(st.stroke ?? theme.edge)}" stroke-width="${e.pattern === "thick" ? 3 : 1.5}"${dash ? ` stroke-dasharray="${dash}"` : ""}${end ? ` marker-end="${marker(end)}"` : ""}${start ? ` marker-start="${marker(start)}"` : ""}/>`
|
|
9201
11102
|
);
|
|
9202
11103
|
if (e.label) {
|
|
9203
|
-
const
|
|
9204
|
-
const w =
|
|
11104
|
+
const text2 = mermaidLabelLines(e.label).join(" ");
|
|
11105
|
+
const w = text2.length * fs * 0.55 + 10;
|
|
9205
11106
|
const mx = (p.x + q.x) / 2;
|
|
9206
11107
|
const my = (p.y + q.y) / 2;
|
|
9207
11108
|
out.push(
|
|
9208
|
-
`<rect x="${n2(mx - w / 2)}" y="${n2(my - fs * 0.75)}" width="${n2(w)}" height="${n2(fs * 1.5)}" rx="3" fill="${
|
|
9209
|
-
`<text x="${n2(mx)}" y="${n2(my)}" text-anchor="middle" dominant-baseline="central" fill="${
|
|
11109
|
+
`<rect x="${n2(mx - w / 2)}" y="${n2(my - fs * 0.75)}" width="${n2(w)}" height="${n2(fs * 1.5)}" rx="3" fill="${esc2(theme.edgeLabelBackground)}"/>`,
|
|
11110
|
+
`<text x="${n2(mx)}" y="${n2(my)}" text-anchor="middle" dominant-baseline="central" fill="${esc2(st.color ?? theme.text)}" font-size="${fs - 1}">${esc2(text2)}</text>`
|
|
9210
11111
|
);
|
|
9211
11112
|
}
|
|
9212
11113
|
}
|
|
9213
11114
|
for (const node of graph.nodes) {
|
|
9214
|
-
const b =
|
|
11115
|
+
const b = boxOf2(node.id);
|
|
9215
11116
|
if (!b) continue;
|
|
9216
11117
|
const st = resolveMermaidStyles(node.classes, node.styles, graph.classDefs);
|
|
9217
11118
|
const fill = st.fill ?? theme.nodeFill;
|
|
9218
11119
|
const stroke = st.stroke ?? theme.nodeStroke;
|
|
9219
11120
|
const color = st.color ?? theme.text;
|
|
9220
11121
|
const strokeWidth = st["stroke-width"]?.replace("px", "") ?? "1.25";
|
|
9221
|
-
const paint = (kind) => kind === "shape" ? `fill="${
|
|
9222
|
-
out.push(`<g data-node="${
|
|
11122
|
+
const paint = (kind) => kind === "shape" ? `fill="${esc2(fill)}" stroke="${esc2(stroke)}" stroke-width="${esc2(strokeWidth)}"` : kind === "line" ? `fill="none" stroke="${esc2(stroke)}" stroke-width="${esc2(strokeWidth)}"` : kind === "filled" ? `fill="${esc2(stroke)}" stroke="${esc2(stroke)}"` : 'fill="none" stroke="none"';
|
|
11123
|
+
out.push(`<g data-node="${esc2(node.id)}" transform="translate(${n2(b.x)} ${n2(b.y)})">`);
|
|
9223
11124
|
for (const path of mermaidShapePaths(node.shape, b.width, b.height)) out.push(`<path d="${path.d}" ${paint(path.paint)}/>`);
|
|
9224
11125
|
const lines = mermaidLabelLines(node.label).filter((l, i, all) => l || all.length === 1);
|
|
9225
11126
|
const members = mermaidNodeMembers(node.data);
|
|
9226
11127
|
const lh = fs * 1.3;
|
|
9227
11128
|
if (members.length) {
|
|
9228
|
-
lines.forEach((
|
|
11129
|
+
lines.forEach((line4, i) => out.push(`<text x="${n2(b.width / 2)}" y="${n2(14 + lh * i)}" text-anchor="middle" dominant-baseline="central" fill="${esc2(color)}" font-weight="600">${esc2(line4)}</text>`));
|
|
9229
11130
|
const top = 14 + lh * lines.length - lh / 2 + 4;
|
|
9230
|
-
out.push(`<line x1="0" y1="${n2(top)}" x2="${n2(b.width)}" y2="${n2(top)}" stroke="${
|
|
9231
|
-
members.forEach((m, i) => out.push(`<text x="8" y="${n2(top + 4 + lh * (i + 0.5))}" dominant-baseline="central" fill="${
|
|
11131
|
+
out.push(`<line x1="0" y1="${n2(top)}" x2="${n2(b.width)}" y2="${n2(top)}" stroke="${esc2(stroke)}" stroke-width="1"/>`);
|
|
11132
|
+
members.forEach((m, i) => out.push(`<text x="8" y="${n2(top + 4 + lh * (i + 0.5))}" dominant-baseline="central" fill="${esc2(color)}" font-size="${fs - 1}">${esc2(m)}</text>`));
|
|
9232
11133
|
} else {
|
|
9233
11134
|
const first = b.height / 2 - (lines.length - 1) * lh / 2;
|
|
9234
|
-
lines.forEach((
|
|
11135
|
+
lines.forEach((line4, i) => out.push(`<text x="${n2(b.width / 2)}" y="${n2(first + lh * i)}" text-anchor="middle" dominant-baseline="central" fill="${esc2(color)}">${esc2(line4)}</text>`));
|
|
9235
11136
|
}
|
|
9236
11137
|
out.push("</g>");
|
|
9237
11138
|
}
|
|
@@ -9300,7 +11201,7 @@ async function downloadDiagramPng(doc, options = {}) {
|
|
|
9300
11201
|
|
|
9301
11202
|
// src/canvas/mermaid/index.ts
|
|
9302
11203
|
function mermaidToCanvas(doc, options = {}) {
|
|
9303
|
-
const layout2 = options.layout ?? ensureDiagramLayout(doc.graph, doc.meta, options);
|
|
11204
|
+
const layout2 = options.layout ?? ensureDiagramLayout(doc.graph, doc.meta, { family: doc.family, ...options });
|
|
9304
11205
|
return {
|
|
9305
11206
|
nodes: mermaidFlowNodes(doc.graph, layout2, { editable: options.editable }),
|
|
9306
11207
|
edges: mermaidFlowEdges(doc.graph, { editable: options.editable }),
|
|
@@ -9375,10 +11276,10 @@ function calculateCurvedPath(fromX, fromY, toX, toY, progress, options) {
|
|
|
9375
11276
|
const p = Math.max(0, Math.min(1, progress));
|
|
9376
11277
|
const arcHeight = options?.arcHeight ?? -30;
|
|
9377
11278
|
const wobble = options?.wobble ?? 0;
|
|
9378
|
-
const
|
|
11279
|
+
const arc2 = Math.sin(p * Math.PI) * arcHeight;
|
|
9379
11280
|
const sway = Math.sin(p * Math.PI * 2) * wobble;
|
|
9380
11281
|
const currentX = fromX + (toX - fromX) * p + sway;
|
|
9381
|
-
const currentY = fromY + (toY - fromY) * p +
|
|
11282
|
+
const currentY = fromY + (toY - fromY) * p + arc2;
|
|
9382
11283
|
return { x: currentX, y: currentY };
|
|
9383
11284
|
}
|
|
9384
11285
|
function getNaturalMovementTiming(distance, seedStr = "drag") {
|
|
@@ -9460,6 +11361,7 @@ export {
|
|
|
9460
11361
|
AUTO_LAYOUT_DATA_KEY,
|
|
9461
11362
|
AnimationEditError,
|
|
9462
11363
|
AnimationPlayer,
|
|
11364
|
+
BUILTIN_FAMILY_SCENES,
|
|
9463
11365
|
CANVAS_COMPONENT_DRAG_TYPE,
|
|
9464
11366
|
CANVAS_GRADIENT_PRESETS,
|
|
9465
11367
|
CANVAS_TOKEN_PROPERTIES,
|
|
@@ -9472,6 +11374,7 @@ export {
|
|
|
9472
11374
|
COMPONENT_SOURCE_DATA_KEY,
|
|
9473
11375
|
CONNECTION_LINE_TYPES,
|
|
9474
11376
|
CSS_ANIMATION_PROPERTIES,
|
|
11377
|
+
CSS_VARIABLE_DIAGRAM_SCENE_THEME,
|
|
9475
11378
|
CUBIC_BEZIER_PRESETS,
|
|
9476
11379
|
CanvasScenesStore,
|
|
9477
11380
|
DEFAULT_ARRANGE_SHORTCUTS,
|
|
@@ -9481,9 +11384,13 @@ export {
|
|
|
9481
11384
|
DEFAULT_NODE_HEIGHT,
|
|
9482
11385
|
DEFAULT_NODE_WIDTH,
|
|
9483
11386
|
DEFAULT_PLACEMENT_GAP,
|
|
11387
|
+
DIAGRAM_MARKER_IDS,
|
|
9484
11388
|
DIAGRAM_RASTER_MAX_SIZE,
|
|
11389
|
+
DIAGRAM_SCENE_DARK_THEME,
|
|
11390
|
+
DIAGRAM_SCENE_LIGHT_THEME,
|
|
9485
11391
|
DIAGRAM_SVG_DARK_THEME,
|
|
9486
11392
|
DIAGRAM_SVG_LIGHT_THEME,
|
|
11393
|
+
DIAGRAM_TITLE_TARGET,
|
|
9487
11394
|
DiagramStream,
|
|
9488
11395
|
INSTANCE_DATA_KEY,
|
|
9489
11396
|
LOCKED_DATA_KEY,
|
|
@@ -9515,6 +11422,7 @@ export {
|
|
|
9515
11422
|
applyShapeCombination,
|
|
9516
11423
|
applyShapeReplacement,
|
|
9517
11424
|
arcToCubics,
|
|
11425
|
+
architectureScene,
|
|
9518
11426
|
autoLayoutDiagram,
|
|
9519
11427
|
bezierPathArea,
|
|
9520
11428
|
bezierPathBounds,
|
|
@@ -9527,6 +11435,7 @@ export {
|
|
|
9527
11435
|
blendDiagramLayout,
|
|
9528
11436
|
blendLayout,
|
|
9529
11437
|
boundsOf,
|
|
11438
|
+
c4Scene,
|
|
9530
11439
|
calculateCursorArrowRotation,
|
|
9531
11440
|
calculateCurvedPath,
|
|
9532
11441
|
calculateDagreReflowDisplacement,
|
|
@@ -9581,6 +11490,11 @@ export {
|
|
|
9581
11490
|
diagramGroupSize,
|
|
9582
11491
|
diagramImageSize,
|
|
9583
11492
|
diagramLayoutBounds,
|
|
11493
|
+
diagramMarksBounds,
|
|
11494
|
+
diagramMarksToSvg,
|
|
11495
|
+
diagramRenameOp,
|
|
11496
|
+
diagramTargetLabel,
|
|
11497
|
+
diagramTextBaseline,
|
|
9584
11498
|
diffOverrideGroups,
|
|
9585
11499
|
distanceToBezierPath,
|
|
9586
11500
|
distributeNodes,
|
|
@@ -9598,11 +11512,13 @@ export {
|
|
|
9598
11512
|
estimateDiagramCanvasHeight,
|
|
9599
11513
|
estimateDiagramNodeSize,
|
|
9600
11514
|
estimateNodeSize,
|
|
11515
|
+
estimateTextWidth2 as estimateTextWidth,
|
|
9601
11516
|
evaluateAnimation,
|
|
9602
11517
|
evaluateEasing,
|
|
9603
11518
|
evaluateTrack,
|
|
9604
11519
|
excludePaths,
|
|
9605
11520
|
exportCssAnimation,
|
|
11521
|
+
familySceneFromLayout,
|
|
9606
11522
|
findConnectorSnap,
|
|
9607
11523
|
findStrokesAtPoint,
|
|
9608
11524
|
findVariant,
|
|
@@ -9620,6 +11536,7 @@ export {
|
|
|
9620
11536
|
formatNumber,
|
|
9621
11537
|
formatOklab,
|
|
9622
11538
|
formatVariantName,
|
|
11539
|
+
ganttScene,
|
|
9623
11540
|
getAbsolutePosition,
|
|
9624
11541
|
getAgentCardAnchor,
|
|
9625
11542
|
getAnimatableProperty,
|
|
@@ -9644,6 +11561,7 @@ export {
|
|
|
9644
11561
|
getCursorTransitionDuration,
|
|
9645
11562
|
getDefaultVariant,
|
|
9646
11563
|
getEffectiveTokenModes,
|
|
11564
|
+
getFamilyScene,
|
|
9647
11565
|
getFlowChildren,
|
|
9648
11566
|
getInstanceData,
|
|
9649
11567
|
getInstanceProperties,
|
|
@@ -9676,8 +11594,10 @@ export {
|
|
|
9676
11594
|
getVariantOptions,
|
|
9677
11595
|
getVariantSet,
|
|
9678
11596
|
getVariantValues,
|
|
11597
|
+
gitGraphScene,
|
|
9679
11598
|
gradientToSvgDef,
|
|
9680
11599
|
handlePoint,
|
|
11600
|
+
hasFamilyScene,
|
|
9681
11601
|
hasVisibleStroke,
|
|
9682
11602
|
hashString,
|
|
9683
11603
|
hatchPath,
|
|
@@ -9711,6 +11631,7 @@ export {
|
|
|
9711
11631
|
isValidCanvasNode,
|
|
9712
11632
|
isValidCanvasScene,
|
|
9713
11633
|
isValidUrl,
|
|
11634
|
+
journeyScene,
|
|
9714
11635
|
layoutAll,
|
|
9715
11636
|
layoutBounds,
|
|
9716
11637
|
layoutFrame,
|
|
@@ -9741,7 +11662,9 @@ export {
|
|
|
9741
11662
|
mermaidShapePaths,
|
|
9742
11663
|
mermaidThumbnailSvg,
|
|
9743
11664
|
mermaidToCanvas,
|
|
11665
|
+
mermaidToScene,
|
|
9744
11666
|
mermaidToSvg,
|
|
11667
|
+
mindmapScene,
|
|
9745
11668
|
mixColorsOklab,
|
|
9746
11669
|
moveKeyframes,
|
|
9747
11670
|
moveLayoutChild,
|
|
@@ -9773,6 +11696,7 @@ export {
|
|
|
9773
11696
|
pathBooleanSelect,
|
|
9774
11697
|
pathToContours,
|
|
9775
11698
|
pathfinder,
|
|
11699
|
+
pieScene,
|
|
9776
11700
|
placeBeside,
|
|
9777
11701
|
planarSplit,
|
|
9778
11702
|
playWebAnimations,
|
|
@@ -9785,6 +11709,9 @@ export {
|
|
|
9785
11709
|
positionToSide,
|
|
9786
11710
|
pruneCanvasTokenModes,
|
|
9787
11711
|
pushCanvasInstanceOverrides,
|
|
11712
|
+
quadrantScene,
|
|
11713
|
+
radarChartSpec,
|
|
11714
|
+
radarScene,
|
|
9788
11715
|
rasterSize,
|
|
9789
11716
|
rasterizeSvg,
|
|
9790
11717
|
readAnimatableValue,
|
|
@@ -9793,6 +11720,7 @@ export {
|
|
|
9793
11720
|
readStyleSize,
|
|
9794
11721
|
realClock,
|
|
9795
11722
|
recordAnimationChanges,
|
|
11723
|
+
registerFamilyScene,
|
|
9796
11724
|
relayoutUpdates,
|
|
9797
11725
|
remapPastedNodes,
|
|
9798
11726
|
removeCanvasVariant,
|
|
@@ -9815,6 +11743,7 @@ export {
|
|
|
9815
11743
|
runMultiNodeTransition,
|
|
9816
11744
|
sampleAnimationFrames,
|
|
9817
11745
|
scaleKeyframes,
|
|
11746
|
+
sceneColor,
|
|
9818
11747
|
segmentBounds,
|
|
9819
11748
|
segmentCurvature,
|
|
9820
11749
|
segmentDerivative,
|
|
@@ -9825,6 +11754,7 @@ export {
|
|
|
9825
11754
|
segmentParamAtLength,
|
|
9826
11755
|
segmentPoint,
|
|
9827
11756
|
segmentTangent,
|
|
11757
|
+
sequenceScene,
|
|
9828
11758
|
serializeCanvasNodes,
|
|
9829
11759
|
setCanvasComponentProperty,
|
|
9830
11760
|
setCanvasInstanceProperties,
|
|
@@ -9862,6 +11792,7 @@ export {
|
|
|
9862
11792
|
syncCanvasComponents,
|
|
9863
11793
|
syncCanvasInstance,
|
|
9864
11794
|
timeToX,
|
|
11795
|
+
timelineScene,
|
|
9865
11796
|
toBezierPath,
|
|
9866
11797
|
toWebAnimations,
|
|
9867
11798
|
toggleLockNodes,
|
|
@@ -9880,6 +11811,8 @@ export {
|
|
|
9880
11811
|
writeNodeStyleProperty,
|
|
9881
11812
|
writeOverrideGroup,
|
|
9882
11813
|
xToTime,
|
|
9883
|
-
xorPolygons
|
|
11814
|
+
xorPolygons,
|
|
11815
|
+
xyChartScene,
|
|
11816
|
+
xyChartSpec
|
|
9884
11817
|
};
|
|
9885
11818
|
//# sourceMappingURL=index.js.map
|