@diagrammo/dgmo 0.49.0 → 0.50.1
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/.cursorrules +6 -2
- package/.github/copilot-instructions.md +6 -2
- package/.windsurfrules +6 -2
- package/SKILL.md +6 -2
- package/dist/advanced.js +557 -195
- package/dist/auto.js +129 -119
- package/dist/auto.mjs +19496 -12761
- package/dist/block.js +145 -48
- package/dist/{charts-d3-EW3YQTEA.js → charts-d3-LR6D3D7A.js} +5 -5
- package/dist/{chunk-5FGDJIJX.js → chunk-2C56LEML.js} +3 -3
- package/dist/{chunk-XJ7J6WOO.js → chunk-2KGXHFYK.js} +4 -4
- package/dist/{chunk-T7IKPCMI.js → chunk-3LH5CLP4.js} +3 -3
- package/dist/{chunk-ZDUQGL3N.js → chunk-3LKM6FMW.js} +2 -2
- package/dist/{chunk-4FIV4K4Z.js → chunk-3NODSS6A.js} +7 -7
- package/dist/{chunk-4BD7EVPK.js → chunk-3P2DKJCG.js} +2 -2
- package/dist/{chunk-TC3YWBFO.js → chunk-3UIKSPFB.js} +35 -9
- package/dist/{chunk-SJEGO2QL.js → chunk-3XGZF2QJ.js} +4 -4
- package/dist/chunk-3XPUDB7B.js +420 -0
- package/dist/{chunk-O5MQPK7E.js → chunk-3Y2DRD7S.js} +3 -3
- package/dist/chunk-3YPY3OXD.js +354 -0
- package/dist/{chunk-N4J5KGWG.js → chunk-4MJ7M6YL.js} +8 -8
- package/dist/{chunk-JFPY3UJ7.js → chunk-4S52SK6G.js} +8 -8
- package/dist/{chunk-ALRHIR6I.js → chunk-5GJYGP5Z.js} +4 -4
- package/dist/{chunk-SQDFK5ZQ.js → chunk-5OWVC2A6.js} +3 -3
- package/dist/{chunk-7VLUGEMJ.js → chunk-66NVRO4K.js} +4 -4
- package/dist/{chunk-ZREZOIGS.js → chunk-66RUL3XF.js} +6 -6
- package/dist/{chunk-MJCG5K2O.js → chunk-6BFZKBGD.js} +2 -2
- package/dist/{chunk-2WMBWZY2.js → chunk-6HJBFVLO.js} +3 -3
- package/dist/{chunk-XCC2RENT.js → chunk-6IAA2QQ2.js} +2 -2
- package/dist/{chunk-B57V3DWN.js → chunk-7L3R6I3U.js} +3 -3
- package/dist/chunk-7PQYTZMA.js +681 -0
- package/dist/{chunk-6SA7FJE4.js → chunk-7QKLIMRZ.js} +10 -10
- package/dist/{chunk-YTN572Q2.js → chunk-7TV5Y53Y.js} +2 -2
- package/dist/{chunk-6CLKNXVP.js → chunk-BBGDM4NQ.js} +457 -78
- package/dist/{chunk-3NFJWFNP.js → chunk-BDXC7MDK.js} +1045 -124
- package/dist/{chunk-D5AVQCDN.js → chunk-BH3UYK36.js} +3 -3
- package/dist/chunk-BTUTZMPT.js +482 -0
- package/dist/{chunk-LVHPTBO3.js → chunk-C2CVAM3U.js} +4 -4
- package/dist/{chunk-BCT5G2VN.js → chunk-DFTFPYUD.js} +5 -5
- package/dist/{chunk-KV6Y2HE6.js → chunk-DSWVNQVS.js} +4 -4
- package/dist/{chunk-4YNP6O47.js → chunk-DZXYF2F5.js} +13 -3
- package/dist/{chunk-FUCAB3KQ.js → chunk-EAMEADTV.js} +3 -3
- package/dist/chunk-FA6K3FWM.js +940 -0
- package/dist/{chunk-HBVD67XG.js → chunk-FJUNPCYI.js} +2 -2
- package/dist/{chunk-6VE3VLWM.js → chunk-GBE54KY6.js} +6 -5
- package/dist/{chunk-YRVLP7UU.js → chunk-GKC3HILQ.js} +4 -4
- package/dist/{chunk-ZXL6MB4R.js → chunk-GL5UZ6NY.js} +3 -3
- package/dist/{chunk-GB3YZTAM.js → chunk-H73FP42Q.js} +5 -5
- package/dist/{chunk-4UDKKGHH.js → chunk-HEVYAHLW.js} +2 -2
- package/dist/{chunk-DDTJ5N7Q.js → chunk-HLJVEAOF.js} +6 -6
- package/dist/{chunk-CLR4A2N2.js → chunk-HTMN2Z6U.js} +4 -4
- package/dist/{chunk-TLKMTQYL.js → chunk-I2WKW7C7.js} +3 -3
- package/dist/{chunk-IUK7AGD4.js → chunk-I7F2A35O.js} +2 -2
- package/dist/{chunk-IBC35BTK.js → chunk-IUMPEA64.js} +2 -2
- package/dist/{chunk-5XCM7UUW.js → chunk-J6K7RP6P.js} +100 -36
- package/dist/{chunk-AJ2PEY7J.js → chunk-JJUOHGX2.js} +2 -2
- package/dist/{chunk-CEHZOPGM.js → chunk-KFZYNWWO.js} +2 -2
- package/dist/{chunk-4NQ3IKUM.js → chunk-KHEYDLMT.js} +5 -5
- package/dist/{chunk-YM2BSPYW.js → chunk-LE4MYMLI.js} +2 -2
- package/dist/{chunk-PU3AUQPA.js → chunk-M5RXSRO2.js} +2 -2
- package/dist/{chunk-XKTN7CZF.js → chunk-MCZ5LBZD.js} +4 -4
- package/dist/{chunk-35BBZDFE.js → chunk-NU3XLTGP.js} +4 -4
- package/dist/{chunk-BPIJLRYE.js → chunk-NWED7CYO.js} +3 -3
- package/dist/{chunk-YYX3SU6H.js → chunk-OMNGQPEZ.js} +257 -101
- package/dist/{chunk-BGJV5ATD.js → chunk-ONA5KPV3.js} +2 -2
- package/dist/{chunk-ZNQX6QWH.js → chunk-OTAL43EH.js} +6 -2
- package/dist/{chunk-F743CM2N.js → chunk-OTQKUHRS.js} +3 -3
- package/dist/{chunk-KUBBJ2CD.js → chunk-P7CE7LXL.js} +6 -6
- package/dist/{chunk-UVCXZEGU.js → chunk-PFHVU7UA.js} +2 -2
- package/dist/{chunk-5ZZLLBFK.js → chunk-PGEGPSCZ.js} +2 -2
- package/dist/chunk-Q4V4XQWV.js +158 -0
- package/dist/{chunk-IHLSHCPZ.js → chunk-QJP6PG7F.js} +5 -5
- package/dist/{chunk-EYN7VFKL.js → chunk-QROYX7TT.js} +3 -3
- package/dist/chunk-QXKWYZNR.js +379 -0
- package/dist/{chunk-VC3TR4NL.js → chunk-RZ6YKEUJ.js} +3 -3
- package/dist/{chunk-K6HNAY5V.js → chunk-SCHXJTZL.js} +2 -2
- package/dist/{chunk-7OVSJI2V.js → chunk-SQLNBA64.js} +3 -3
- package/dist/{chunk-65RTDUZH.js → chunk-SXRTRMEE.js} +3 -3
- package/dist/{chunk-3BIAFYD2.js → chunk-T4VOVZT5.js} +2 -2
- package/dist/{chunk-UWDO3O52.js → chunk-TN35C5KM.js} +2 -2
- package/dist/{chunk-IFK3GIUW.js → chunk-TSA237IM.js} +2 -2
- package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
- package/dist/{chunk-4HVNZ7WF.js → chunk-VBYSIOOY.js} +3 -3
- package/dist/{chunk-ZTLWVRNS.js → chunk-VDOOQZUD.js} +2 -2
- package/dist/{chunk-RTERS6S5.js → chunk-VUJGMJE6.js} +4 -4
- package/dist/{chunk-X2CH42BN.js → chunk-VVW3F3MD.js} +7 -7
- package/dist/{chunk-RI4NIMFP.js → chunk-VVZRV54S.js} +75 -35
- package/dist/{chunk-LG4TWW4U.js → chunk-WW32K72E.js} +8 -8
- package/dist/{chunk-NVT6C2VE.js → chunk-X6EZPSW6.js} +4 -4
- package/dist/{chunk-KQAEKMIX.js → chunk-XDXNDSKO.js} +2 -2
- package/dist/{chunk-FMKTYMP4.js → chunk-XJLKLU4D.js} +3 -3
- package/dist/chunk-Y4RNXEAO.js +952 -0
- package/dist/{chunk-26RVGM44.js → chunk-YIA4LEX4.js} +15 -7
- package/dist/chunk-YNRDWYZP.js +295 -0
- package/dist/{chunk-SGHSY3LU.js → chunk-Z6XJQ6KO.js} +81 -6
- package/dist/{chunk-SVDWQGX2.js → chunk-ZAD4HV2G.js} +139 -78
- package/dist/cli.cjs +153 -144
- package/dist/clock.d.ts +10 -0
- package/dist/clock.js +235 -0
- package/dist/countdown.d.ts +12 -0
- package/dist/countdown.js +450 -0
- package/dist/dgmo-router-YTU3ENAX.js +84 -0
- package/dist/{dimensions-WSIJXT5Q.js → dimensions-OTBKC5M6.js} +5 -5
- package/dist/editor.js +39 -1
- package/dist/element.js +131 -121
- package/dist/element.mjs +19496 -12761
- package/dist/{flowchart-parser-IVZN7CQN.js → flowchart-parser-OE4WHLTF.js} +4 -4
- package/dist/{flowchart-renderer-GMI2U3DD.js → flowchart-renderer-GPCSMTOR.js} +6 -6
- package/dist/highlight.d.ts +17 -1
- package/dist/highlight.js +156 -5
- package/dist/index.js +50 -45
- package/dist/{layout-HQMBPJVS.js → layout-46366KBT.js} +2 -2
- package/dist/{layout-D42XE4RE.js → layout-5BG6DFCU.js} +3 -3
- package/dist/{layout-K2ZN3Q42.js → layout-7MZ5NF2N.js} +4 -4
- package/dist/{layout-4Z5JM7PT.js → layout-FWODLIMP.js} +4 -4
- package/dist/{layout-GZ2CWONU.js → layout-J36454XU.js} +4 -4
- package/dist/{layout-S3EK4IYO.js → layout-LD6XTLD6.js} +4 -4
- package/dist/{parser-CLMFZWCC.js → parser-36HVKU5U.js} +5 -5
- package/dist/{parser-MCJWF5G3.js → parser-4AI5ZN5F.js} +3 -3
- package/dist/{parser-DERPY5KC.js → parser-4NO6VZ6S.js} +4 -4
- package/dist/parser-4WQQQXCG.js +13 -0
- package/dist/{parser-4ROBKVUR.js → parser-5OXGPNBF.js} +5 -5
- package/dist/{parser-XWUDFJ7P.js → parser-AGVYTQXV.js} +4 -4
- package/dist/{parser-TITK4YW6.js → parser-AXKBDGNO.js} +5 -5
- package/dist/parser-B5FVS7O6.js +11 -0
- package/dist/parser-CSFUN3CT.js +14 -0
- package/dist/parser-CVMEDULU.js +15 -0
- package/dist/{parser-KPMN5KKE.js → parser-D5VILGN2.js} +4 -4
- package/dist/{parser-IKZFTLOJ.js → parser-DFFEDKHH.js} +3 -3
- package/dist/{parser-JD7OQ2E6.js → parser-H3XEPFPV.js} +4 -4
- package/dist/{parser-UBGPTIZD.js → parser-HYRTF3DO.js} +3 -3
- package/dist/{parser-K647FRI4.js → parser-IBWNAPY4.js} +3 -3
- package/dist/{parser-4BKIFG2C.js → parser-IJBMRXMC.js} +5 -5
- package/dist/{parser-MBJSBTL5.js → parser-JJR52VAT.js} +5 -5
- package/dist/{parser-SMBJO3XN.js → parser-K3XXLMUW.js} +4 -4
- package/dist/{parser-OBQG655V.js → parser-KCR2WS3V.js} +4 -4
- package/dist/{parser-HVJFTOXL.js → parser-LWKKBNSA.js} +3 -3
- package/dist/{parser-ZYC3XGNS.js → parser-MPCE5JBG.js} +4 -4
- package/dist/{parser-QJYS7KQQ.js → parser-MTOMTWTD.js} +4 -4
- package/dist/{parser-GFSOPDB7.js → parser-O4HIUN6G.js} +4 -4
- package/dist/{parser-BL7Z72EY.js → parser-PSA4UBSP.js} +4 -4
- package/dist/{parser-TNYX5S7E.js → parser-RV4M6AS2.js} +4 -4
- package/dist/parser-RZPVAQVX.js +11 -0
- package/dist/{parser-UGA23PYK.js → parser-TGQZJ5OT.js} +4 -4
- package/dist/parser-TXND652E.js +13 -0
- package/dist/{parser-WISPH7LW.js → parser-VKOJM7KS.js} +4 -4
- package/dist/{parser-ZKF5K2H2.js → parser-W4PQUGX3.js} +4 -4
- package/dist/{parser-MRBPXXIV.js → parser-WAV5JRPT.js} +4 -4
- package/dist/{parser-D6ONJQFR.js → parser-YS7TOS2K.js} +3 -3
- package/dist/pert.d.ts +8 -0
- package/dist/{renderer-VFUVRNLK.js → renderer-2AZ5HJFK.js} +4 -4
- package/dist/{renderer-V3JEMWMM.js → renderer-2QPMJ2DA.js} +6 -6
- package/dist/renderer-45PSOL3E.js +19 -0
- package/dist/{renderer-BB5PREMY.js → renderer-4ITCHBT7.js} +4 -4
- package/dist/{renderer-XEKIRPI6.js → renderer-5DSEWF74.js} +5 -5
- package/dist/{renderer-QNHUXCRL.js → renderer-6OKF44KS.js} +9 -9
- package/dist/renderer-72LGR2YF.js +14 -0
- package/dist/{renderer-YHXPN3GF.js → renderer-7SD6MSBS.js} +7 -7
- package/dist/renderer-A5VE5BCI.js +24 -0
- package/dist/{renderer-A5VFZQQK.js → renderer-AUW2BE6G.js} +6 -6
- package/dist/{renderer-LWGJFT3D.js → renderer-B5TBNZJE.js} +5 -5
- package/dist/{renderer-4IUPINAE.js → renderer-BSR2O2H6.js} +7 -7
- package/dist/{renderer-DKESNMU5.js → renderer-CYB4LK3G.js} +6 -6
- package/dist/{renderer-MFJ7HY2H.js → renderer-FF24KZCI.js} +5 -5
- package/dist/{renderer-CGW7QPNA.js → renderer-FPE3J5VZ.js} +7 -7
- package/dist/{renderer-6T3KK4S3.js → renderer-FYSVXL7M.js} +7 -7
- package/dist/{renderer-THD6V5TL.js → renderer-HDCCZURL.js} +9 -7
- package/dist/{renderer-TPIBXNOS.js → renderer-JCCHNECZ.js} +6 -6
- package/dist/{renderer-QL5KO6SK.js → renderer-KS7YZJE2.js} +7 -7
- package/dist/{renderer-SQ3JUAI7.js → renderer-NGXZTRK6.js} +6 -6
- package/dist/{renderer-MJDDU27W.js → renderer-ODUUOPVT.js} +10 -10
- package/dist/renderer-PJM35LJN.js +17 -0
- package/dist/{renderer-TYXRHMRI.js → renderer-PPIHO5FI.js} +9 -9
- package/dist/{renderer-W5RMOURB.js → renderer-PSMMZCKH.js} +6 -6
- package/dist/{renderer-UZF3JROD.js → renderer-QAOBLRXV.js} +8 -8
- package/dist/{renderer-ROV756WT.js → renderer-R2WNIC2C.js} +5 -5
- package/dist/{renderer-VICQ4WNY.js → renderer-SBS3YWU5.js} +5 -5
- package/dist/{renderer-6L3NBEY5.js → renderer-UYMQQCJK.js} +6 -6
- package/dist/{renderer-radial-MHO2VDXN.js → renderer-radial-F7X5F2VU.js} +6 -6
- package/dist/{state-parser-RX3GXOIB.js → state-parser-3REXRK3R.js} +4 -4
- package/dist/{state-renderer-AJUKGNWU.js → state-renderer-XYLNRWXR.js} +6 -6
- package/docs/ai-integration.md +6 -2
- package/docs/language-reference.md +253 -22
- package/gallery/fixtures/body.dgmo +17 -0
- package/gallery/fixtures/bracket.dgmo +30 -0
- package/gallery/fixtures/clock.dgmo +8 -0
- package/gallery/fixtures/countdown.dgmo +3 -0
- package/gallery/fixtures/goal.dgmo +4 -0
- package/package.json +12 -4
- package/dist/advanced.d.ts +0 -6162
- package/dist/auto.d.ts +0 -54
- package/dist/block.d.ts +0 -123
- package/dist/dgmo-router-ODKPEJ3P.js +0 -79
- package/dist/element.d.ts +0 -62
- package/dist/index.d.ts +0 -166
- package/dist/parser-667RGSUW.js +0 -13
- package/dist/parser-J3P2D6IP.js +0 -13
- package/dist/themes-1-CuKpeH.d.ts +0 -908
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
renderNodeCard
|
|
3
|
-
} from "./chunk-AHGF2YYA.js";
|
|
4
1
|
import {
|
|
5
2
|
renderInlineText
|
|
6
3
|
} from "./chunk-3HDBAXF5.js";
|
|
4
|
+
import {
|
|
5
|
+
wrapDescriptionLines
|
|
6
|
+
} from "./chunk-BMR4CIEO.js";
|
|
7
|
+
import {
|
|
8
|
+
renderNodeCard
|
|
9
|
+
} from "./chunk-AHGF2YYA.js";
|
|
7
10
|
import {
|
|
8
11
|
CARD_RADIUS,
|
|
9
12
|
HEADER_HEIGHT,
|
|
@@ -11,15 +14,12 @@ import {
|
|
|
11
14
|
NODE_STROKE_WIDTH,
|
|
12
15
|
SEPARATOR_GAP
|
|
13
16
|
} from "./chunk-3CIOJ5YJ.js";
|
|
14
|
-
import {
|
|
15
|
-
wrapDescriptionLines
|
|
16
|
-
} from "./chunk-BMR4CIEO.js";
|
|
17
17
|
import {
|
|
18
18
|
formatDateLabel
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-66RUL3XF.js";
|
|
20
20
|
import {
|
|
21
21
|
renderIntegratedLegend
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-HEVYAHLW.js";
|
|
23
23
|
import {
|
|
24
24
|
TITLE_FONT_SIZE,
|
|
25
25
|
TITLE_FONT_WEIGHT,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
import {
|
|
42
42
|
resolveActiveTagGroup,
|
|
43
43
|
resolveTagColor
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-FJUNPCYI.js";
|
|
45
45
|
import {
|
|
46
46
|
resolveColor
|
|
47
47
|
} from "./chunk-TLVIHFRO.js";
|
|
@@ -987,4 +987,4 @@ export {
|
|
|
987
987
|
focusEventLine,
|
|
988
988
|
renderEventLineForExport
|
|
989
989
|
};
|
|
990
|
-
//# sourceMappingURL=chunk-
|
|
990
|
+
//# sourceMappingURL=chunk-7QKLIMRZ.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
injectDefaultTagMetadata,
|
|
13
13
|
resolveTagColor
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FJUNPCYI.js";
|
|
15
15
|
|
|
16
16
|
// src/mindmap/text-wrap.ts
|
|
17
17
|
var H_PAD = 16;
|
|
@@ -547,4 +547,4 @@ export {
|
|
|
547
547
|
computeNodeText,
|
|
548
548
|
layoutMindmap
|
|
549
549
|
};
|
|
550
|
-
//# sourceMappingURL=chunk-
|
|
550
|
+
//# sourceMappingURL=chunk-7TV5Y53Y.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-3CIOJ5YJ.js";
|
|
9
9
|
import {
|
|
10
10
|
renderIntegratedLegend
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HEVYAHLW.js";
|
|
12
12
|
import {
|
|
13
13
|
getMaxLegendReservedHeight
|
|
14
14
|
} from "./chunk-7UEMZREK.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
resolveActiveTagGroup,
|
|
29
29
|
resolveTagColor,
|
|
30
30
|
tagAttrKey
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-FJUNPCYI.js";
|
|
32
32
|
|
|
33
33
|
// src/sketch/renderer.ts
|
|
34
34
|
import * as d3 from "d3-selection";
|
|
@@ -338,7 +338,35 @@ function renderSketch(container, parsed, layout, palette, isDark, options = {})
|
|
|
338
338
|
const showTitle = !!parsed.title;
|
|
339
339
|
const titleOffset = showTitle ? 40 : 0;
|
|
340
340
|
const legendGroups = parsed.options.noLegend ? [] : tagGroups;
|
|
341
|
-
const
|
|
341
|
+
const edgeGeom = sketchEdgeGeometry(layout);
|
|
342
|
+
let minX = 0;
|
|
343
|
+
let minY = 0;
|
|
344
|
+
let maxX = layout.width;
|
|
345
|
+
let maxY = layout.height;
|
|
346
|
+
for (let i = 0; i < edgeGeom.length; i++) {
|
|
347
|
+
const g = edgeGeom[i];
|
|
348
|
+
if (!g) continue;
|
|
349
|
+
const nums = (g.d.match(/-?[\d.]+/g) ?? []).map(Number);
|
|
350
|
+
for (let k = 0; k + 1 < nums.length; k += 2) {
|
|
351
|
+
minX = Math.min(minX, nums[k]);
|
|
352
|
+
maxX = Math.max(maxX, nums[k]);
|
|
353
|
+
minY = Math.min(minY, nums[k + 1]);
|
|
354
|
+
maxY = Math.max(maxY, nums[k + 1]);
|
|
355
|
+
}
|
|
356
|
+
const label = layout.edges[i]?.label;
|
|
357
|
+
if (label) {
|
|
358
|
+
const hw = measureText(label, EDGE_LABEL_FONT_SIZE) / 2 + 6;
|
|
359
|
+
const hh = EDGE_LABEL_FONT_SIZE / 2 + 4;
|
|
360
|
+
minX = Math.min(minX, g.mid.x - hw);
|
|
361
|
+
maxX = Math.max(maxX, g.mid.x + hw);
|
|
362
|
+
minY = Math.min(minY, g.mid.y - hh);
|
|
363
|
+
maxY = Math.max(maxY, g.mid.y + hh);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const extraLeft = Math.max(0, -minX);
|
|
367
|
+
const extraTop = Math.max(0, -minY);
|
|
368
|
+
const boundW = maxX + extraLeft;
|
|
369
|
+
const contentWidth = boundW + 2 * DIAGRAM_PADDING;
|
|
342
370
|
const width = Math.max(contentWidth, options.exportDims?.width ?? 0);
|
|
343
371
|
const legendHeight = legendGroups.length > 0 ? getMaxLegendReservedHeight(
|
|
344
372
|
{
|
|
@@ -348,9 +376,9 @@ function renderSketch(container, parsed, layout, palette, isDark, options = {})
|
|
|
348
376
|
},
|
|
349
377
|
width
|
|
350
378
|
) : 0;
|
|
351
|
-
const contentTop = titleOffset + legendHeight + DIAGRAM_PADDING;
|
|
379
|
+
const contentTop = titleOffset + legendHeight + DIAGRAM_PADDING + extraTop;
|
|
352
380
|
const height = Math.max(
|
|
353
|
-
contentTop +
|
|
381
|
+
contentTop + maxY + DIAGRAM_PADDING,
|
|
354
382
|
options.exportDims?.height ?? 0
|
|
355
383
|
);
|
|
356
384
|
d3.select(container).selectAll("*").remove();
|
|
@@ -389,44 +417,23 @@ function renderSketch(container, parsed, layout, palette, isDark, options = {})
|
|
|
389
417
|
});
|
|
390
418
|
legendG.selectAll("[data-legend-group]").classed("sk-legend-group", true);
|
|
391
419
|
}
|
|
392
|
-
const contentX = DIAGRAM_PADDING + Math.max(0, (width - contentWidth) / 2);
|
|
420
|
+
const contentX = DIAGRAM_PADDING + extraLeft + Math.max(0, (width - contentWidth) / 2);
|
|
393
421
|
const root = svg.append("g").attr("class", "sk-root").attr("transform", `translate(${contentX},${contentTop})`);
|
|
394
|
-
const rectById = /* @__PURE__ */ new Map();
|
|
395
|
-
for (const node of layout.nodes) {
|
|
396
|
-
rectById.set(node.id, { x: node.x, y: node.y, w: node.w, h: node.h });
|
|
397
|
-
}
|
|
398
|
-
for (const box of layout.boxes) {
|
|
399
|
-
rectById.set(box.id, { x: box.x, y: box.y, w: box.w, h: box.h });
|
|
400
|
-
}
|
|
401
|
-
const portsById = /* @__PURE__ */ new Map();
|
|
402
|
-
for (const box of layout.boxes) {
|
|
403
|
-
const kids = layout.nodes.filter((n) => n.boxLabel === box.label);
|
|
404
|
-
const ys = kids.map((k) => k.y + k.h / 2);
|
|
405
|
-
const xs = kids.map((k) => k.x + k.w / 2);
|
|
406
|
-
ys.push(box.y + box.h / 2);
|
|
407
|
-
xs.push(box.x + box.w / 2);
|
|
408
|
-
portsById.set(box.id, { ys, xs });
|
|
409
|
-
}
|
|
410
422
|
const boxLayer = root.append("g").attr("class", "sk-boxes");
|
|
411
423
|
for (const box of layout.boxes) {
|
|
412
424
|
drawBoxFrame(boxLayer, box, colorsFor(box.metadata, true), palette);
|
|
413
425
|
}
|
|
414
426
|
const edgeLayer = root.append("g").attr("class", "sk-edges");
|
|
415
427
|
const labelLayerData = [];
|
|
416
|
-
for (
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
if (!
|
|
428
|
+
for (let ei = 0; ei < layout.edges.length; ei++) {
|
|
429
|
+
const edge = layout.edges[ei];
|
|
430
|
+
const geo = edgeGeom[ei];
|
|
431
|
+
if (!geo) continue;
|
|
420
432
|
const color = flowColor(edge);
|
|
421
433
|
const hex = color.replace("#", "");
|
|
422
|
-
const { d, mid } =
|
|
423
|
-
source,
|
|
424
|
-
target,
|
|
425
|
-
portsById.get(edge.sourceId),
|
|
426
|
-
portsById.get(edge.targetId)
|
|
427
|
-
);
|
|
434
|
+
const { d, mid } = geo;
|
|
428
435
|
const g = edgeLayer.append("g").attr("class", "sk-edge-group").attr("data-from", edge.sourceId).attr("data-to", edge.targetId).attr("data-line-number", edge.lineNumber);
|
|
429
|
-
const path = g.append("path").attr("d", d).attr("fill", "none").attr("stroke", color).attr("stroke-width", EDGE_STROKE_WIDTH);
|
|
436
|
+
const path = g.append("path").attr("d", geo.dRender ?? d).attr("fill", "none").attr("stroke", color).attr("stroke-width", EDGE_STROKE_WIDTH);
|
|
430
437
|
if (edge.dashed) path.attr("stroke-dasharray", DASH);
|
|
431
438
|
if (edge.heads === "one" || edge.heads === "both") {
|
|
432
439
|
path.attr("marker-end", `url(#sk-arrow-${hex})`);
|
|
@@ -442,10 +449,78 @@ function renderSketch(container, parsed, layout, palette, isDark, options = {})
|
|
|
442
449
|
text: edge.label,
|
|
443
450
|
color,
|
|
444
451
|
from: edge.sourceId,
|
|
445
|
-
to: edge.targetId
|
|
452
|
+
to: edge.targetId,
|
|
453
|
+
ei,
|
|
454
|
+
cp: (d.match(/-?[\d.]+/g) ?? []).map(Number)
|
|
446
455
|
});
|
|
447
456
|
}
|
|
448
457
|
}
|
|
458
|
+
{
|
|
459
|
+
const labelW = (t) => t.length * EDGE_LABEL_FONT_SIZE * 0.56;
|
|
460
|
+
const halfH = EDGE_LABEL_FONT_SIZE / 2 + 3;
|
|
461
|
+
const GAP = 4;
|
|
462
|
+
const shapeRects = [
|
|
463
|
+
...layout.nodes.map((n) => ({ x: n.x, y: n.y, w: n.w, h: n.h })),
|
|
464
|
+
...layout.boxes.map((b) => ({ x: b.x, y: b.y, w: b.w, h: b.h }))
|
|
465
|
+
];
|
|
466
|
+
const cubicPt = (cp, t) => {
|
|
467
|
+
const u = 1 - t;
|
|
468
|
+
const a = u * u * u;
|
|
469
|
+
const b = 3 * u * u * t;
|
|
470
|
+
const c = 3 * u * t * t;
|
|
471
|
+
const dd = t * t * t;
|
|
472
|
+
return {
|
|
473
|
+
x: a * cp[0] + b * cp[2] + c * cp[4] + dd * cp[6],
|
|
474
|
+
y: a * cp[1] + b * cp[3] + c * cp[5] + dd * cp[7]
|
|
475
|
+
};
|
|
476
|
+
};
|
|
477
|
+
const allPolys = edgeGeom.map((g) => {
|
|
478
|
+
if (!g) return null;
|
|
479
|
+
const cp = (g.d.match(/-?[\d.]+/g) ?? []).map(Number);
|
|
480
|
+
if (cp.length < 8) return null;
|
|
481
|
+
const pts = [];
|
|
482
|
+
for (let s = 0; s <= 32; s++) pts.push(cubicPt(cp, s / 32));
|
|
483
|
+
return pts;
|
|
484
|
+
});
|
|
485
|
+
const covers = (cx, cy, hw, ox, oy, ohw, ohh) => Math.abs(cx - ox) < hw + ohw + GAP && Math.abs(cy - oy) < halfH + ohh + GAP;
|
|
486
|
+
const placed = [];
|
|
487
|
+
const TS = [0.5, 0.4, 0.6, 0.32, 0.68, 0.25, 0.75, 0.18, 0.82];
|
|
488
|
+
for (const l of labelLayerData) {
|
|
489
|
+
const hw = labelW(l.text) / 2 + 3;
|
|
490
|
+
let bestT = 0.5;
|
|
491
|
+
let bestScore = Infinity;
|
|
492
|
+
for (const t of TS) {
|
|
493
|
+
const p2 = cubicPt(l.cp, t);
|
|
494
|
+
let labelHits = 0;
|
|
495
|
+
for (const q of placed)
|
|
496
|
+
if (covers(p2.x, p2.y, hw, q.x, q.y, q.hw, halfH)) labelHits++;
|
|
497
|
+
let shapeHits = 0;
|
|
498
|
+
for (const r of shapeRects)
|
|
499
|
+
if (covers(p2.x, p2.y, hw, r.x + r.w / 2, r.y + r.h / 2, r.w / 2, r.h / 2))
|
|
500
|
+
shapeHits++;
|
|
501
|
+
let lineHits = 0;
|
|
502
|
+
for (let k = 0; k < allPolys.length; k++) {
|
|
503
|
+
if (k === l.ei) continue;
|
|
504
|
+
const poly = allPolys[k];
|
|
505
|
+
if (poly?.some((pt) => covers(p2.x, p2.y, hw, pt.x, pt.y, 0, 0)))
|
|
506
|
+
lineHits++;
|
|
507
|
+
}
|
|
508
|
+
if (labelHits === 0 && shapeHits === 0 && lineHits === 0) {
|
|
509
|
+
bestT = t;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
const score = labelHits * 10 + shapeHits * 6 + lineHits * 4 + Math.abs(t - 0.5);
|
|
513
|
+
if (score < bestScore) {
|
|
514
|
+
bestScore = score;
|
|
515
|
+
bestT = t;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
const p = cubicPt(l.cp, bestT);
|
|
519
|
+
l.x = p.x;
|
|
520
|
+
l.y = p.y;
|
|
521
|
+
placed.push({ x: p.x, y: p.y, hw });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
449
524
|
const nodeLayer = root.append("g").attr("class", "sk-nodes");
|
|
450
525
|
for (const node of layout.nodes) {
|
|
451
526
|
let n = node;
|
|
@@ -465,9 +540,7 @@ function renderSketch(container, parsed, layout, palette, isDark, options = {})
|
|
|
465
540
|
const labelLayer = root.append("g").attr("class", "sk-edge-labels");
|
|
466
541
|
for (const l of labelLayerData) {
|
|
467
542
|
const g = labelLayer.append("g").attr("class", "sk-edge-label").attr("data-from", l.from).attr("data-to", l.to);
|
|
468
|
-
|
|
469
|
-
g.append("rect").attr("x", l.x - textWidth / 2 - 3).attr("y", l.y - EDGE_LABEL_FONT_SIZE / 2 - 3).attr("width", textWidth + 6).attr("height", EDGE_LABEL_FONT_SIZE + 6).attr("rx", 3).attr("fill", palette.bg);
|
|
470
|
-
g.append("text").attr("x", l.x).attr("y", l.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", EDGE_LABEL_FONT_SIZE).attr("fill", l.color).text(l.text);
|
|
543
|
+
g.append("text").attr("x", l.x).attr("y", l.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", EDGE_LABEL_FONT_SIZE).attr("fill", l.color).attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("paint-order", "stroke").text(l.text);
|
|
471
544
|
}
|
|
472
545
|
if (options.onClickItem) {
|
|
473
546
|
const handler = options.onClickItem;
|
|
@@ -600,55 +673,360 @@ function drawNode(layer, node, colors, palette, isDark, tagGroups) {
|
|
|
600
673
|
});
|
|
601
674
|
}
|
|
602
675
|
}
|
|
603
|
-
function
|
|
676
|
+
function assignEdgeSides(edges, rectById) {
|
|
677
|
+
const cx = (r) => r.x + r.w / 2;
|
|
678
|
+
const cy = (r) => r.y + r.h / 2;
|
|
679
|
+
const facing = (dx, dy) => Math.abs(dx) >= Math.abs(dy) ? dx >= 0 ? "R" : "L" : dy >= 0 ? "B" : "T";
|
|
680
|
+
return edges.map((e) => {
|
|
681
|
+
const s = rectById.get(e.sourceId);
|
|
682
|
+
const t = rectById.get(e.targetId);
|
|
683
|
+
if (!s || !t) return null;
|
|
684
|
+
const dx = cx(t) - cx(s);
|
|
685
|
+
const dy = cy(t) - cy(s);
|
|
686
|
+
const xOverlap = Math.min(s.x + s.w, t.x + t.w) - Math.max(s.x, t.x);
|
|
687
|
+
const yOverlap = Math.min(s.y + s.h, t.y + t.h) - Math.max(s.y, t.y);
|
|
688
|
+
if (xOverlap >= 0 && xOverlap >= yOverlap) {
|
|
689
|
+
const below = dy >= 0;
|
|
690
|
+
return { s: below ? "B" : "T", t: below ? "T" : "B" };
|
|
691
|
+
}
|
|
692
|
+
if (yOverlap >= 0 && yOverlap >= xOverlap) {
|
|
693
|
+
const right = dx >= 0;
|
|
694
|
+
return { s: right ? "R" : "L", t: right ? "L" : "R" };
|
|
695
|
+
}
|
|
696
|
+
return { s: facing(dx, dy), t: facing(-dx, -dy) };
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
function edgePath(source, target, sSide, tSide, sourcePorts, targetPorts) {
|
|
604
700
|
const acx = source.x + source.w / 2;
|
|
605
701
|
const acy = source.y + source.h / 2;
|
|
606
702
|
const bcx = target.x + target.w / 2;
|
|
607
703
|
const bcy = target.y + target.h / 2;
|
|
608
|
-
const horiz = Math.abs(bcx - acx) >= Math.abs(bcy - acy);
|
|
609
|
-
let p0;
|
|
610
|
-
let p1;
|
|
611
|
-
let h0;
|
|
612
|
-
let h1;
|
|
613
704
|
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
614
|
-
const CORNER_FRAC = 0.25;
|
|
615
|
-
const midClamp = (v, lo, hi) => {
|
|
616
|
-
const m = (hi - lo) * CORNER_FRAC;
|
|
617
|
-
return clamp(v, lo + m, hi - m);
|
|
618
|
-
};
|
|
619
705
|
const nearest = (arr, v) => arr.reduce((a, b) => Math.abs(b - v) < Math.abs(a - v) ? b : a, arr[0]);
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
p1
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
);
|
|
642
|
-
h0 = { x: p0.x, y: p0.y + sign * k };
|
|
643
|
-
h1 = { x: p1.x, y: p1.y - sign * k };
|
|
644
|
-
}
|
|
706
|
+
const attach = (side, rect, ports, toward) => {
|
|
707
|
+
if (side === "L" || side === "R") {
|
|
708
|
+
const x2 = side === "L" ? rect.x : rect.x + rect.w;
|
|
709
|
+
const y2 = ports ? clamp(nearest(ports.ys, toward.y), rect.y, rect.y + rect.h) : rect.y + rect.h / 2;
|
|
710
|
+
return { x: x2, y: y2 };
|
|
711
|
+
}
|
|
712
|
+
const y = side === "T" ? rect.y : rect.y + rect.h;
|
|
713
|
+
const x = ports ? clamp(nearest(ports.xs, toward.x), rect.x, rect.x + rect.w) : rect.x + rect.w / 2;
|
|
714
|
+
return { x, y };
|
|
715
|
+
};
|
|
716
|
+
const normal = (side) => side === "L" ? { x: -1, y: 0 } : side === "R" ? { x: 1, y: 0 } : side === "T" ? { x: 0, y: -1 } : { x: 0, y: 1 };
|
|
717
|
+
const p0 = attach(sSide, source, sourcePorts, { x: bcx, y: bcy });
|
|
718
|
+
const p1 = attach(tSide, target, targetPorts, { x: acx, y: acy });
|
|
719
|
+
const n0 = normal(sSide);
|
|
720
|
+
const n1 = normal(tSide);
|
|
721
|
+
const k = Math.max(
|
|
722
|
+
CURVE_HANDLE_MIN,
|
|
723
|
+
Math.min(CURVE_HANDLE_MAX, Math.hypot(p1.x - p0.x, p1.y - p0.y) / 2)
|
|
724
|
+
);
|
|
725
|
+
const h0 = { x: p0.x + n0.x * k, y: p0.y + n0.y * k };
|
|
726
|
+
const h1 = { x: p1.x + n1.x * k, y: p1.y + n1.y * k };
|
|
645
727
|
return {
|
|
646
728
|
d: `M ${p0.x} ${p0.y} C ${h0.x} ${h0.y}, ${h1.x} ${h1.y}, ${p1.x} ${p1.y}`,
|
|
647
|
-
// Centered ON the line (
|
|
648
|
-
//
|
|
649
|
-
//
|
|
650
|
-
|
|
729
|
+
// Centered ON the line at its ARC midpoint (t=0.5 on the cubic), not the
|
|
730
|
+
// endpoint average: for a straight edge the two coincide, but for a curve
|
|
731
|
+
// that bulges out to route around a shape the arc midpoint sits at the
|
|
732
|
+
// bulge apex — in open space — while the endpoint average would land on the
|
|
733
|
+
// very shape the edge detoured past. The opaque halo masks the line behind.
|
|
734
|
+
mid: {
|
|
735
|
+
x: 0.125 * p0.x + 0.375 * h0.x + 0.375 * h1.x + 0.125 * p1.x,
|
|
736
|
+
y: 0.125 * p0.y + 0.375 * h0.y + 0.375 * h1.y + 0.125 * p1.y
|
|
737
|
+
},
|
|
738
|
+
p0,
|
|
739
|
+
h0,
|
|
740
|
+
h1,
|
|
741
|
+
p1
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
var SIDES = ["T", "B", "L", "R"];
|
|
745
|
+
function cubicAt(g, t) {
|
|
746
|
+
const u = 1 - t;
|
|
747
|
+
const a = u * u * u;
|
|
748
|
+
const b = 3 * u * u * t;
|
|
749
|
+
const c = 3 * u * t * t;
|
|
750
|
+
const dd = t * t * t;
|
|
751
|
+
return {
|
|
752
|
+
x: a * g.p0.x + b * g.h0.x + c * g.h1.x + dd * g.p1.x,
|
|
753
|
+
y: a * g.p0.y + b * g.h0.y + c * g.h1.y + dd * g.p1.y
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
var EDGE_OBSTACLE_INSET = 6;
|
|
757
|
+
var EDGE_SAMPLES = 24;
|
|
758
|
+
var POLY_SAMPLES = 19;
|
|
759
|
+
function polyline(g) {
|
|
760
|
+
const pts = [];
|
|
761
|
+
for (let i = 0; i <= POLY_SAMPLES; i++)
|
|
762
|
+
pts.push(cubicAt(g, i / POLY_SAMPLES));
|
|
763
|
+
return pts;
|
|
764
|
+
}
|
|
765
|
+
function segmentsCross(p, p2, q, q2) {
|
|
766
|
+
const o = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
|
767
|
+
const d1 = o(p, p2, q);
|
|
768
|
+
const d2 = o(p, p2, q2);
|
|
769
|
+
const d32 = o(q, q2, p);
|
|
770
|
+
const d4 = o(q, q2, p2);
|
|
771
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d32 > 0 && d4 < 0 || d32 < 0 && d4 > 0);
|
|
772
|
+
}
|
|
773
|
+
function polyCrossings(a, b) {
|
|
774
|
+
let n = 0;
|
|
775
|
+
for (let i = 0; i + 1 < a.length; i++)
|
|
776
|
+
for (let j = 0; j + 1 < b.length; j++)
|
|
777
|
+
if (segmentsCross(a[i], a[i + 1], b[j], b[j + 1])) n++;
|
|
778
|
+
return n;
|
|
779
|
+
}
|
|
780
|
+
function polyIntersection(a, b) {
|
|
781
|
+
for (let i = 0; i + 1 < a.length; i++) {
|
|
782
|
+
const p = a[i];
|
|
783
|
+
const p2 = a[i + 1];
|
|
784
|
+
for (let j = 0; j + 1 < b.length; j++) {
|
|
785
|
+
const q = b[j];
|
|
786
|
+
const q2 = b[j + 1];
|
|
787
|
+
if (!segmentsCross(p, p2, q, q2)) continue;
|
|
788
|
+
const rx = p2.x - p.x;
|
|
789
|
+
const ry = p2.y - p.y;
|
|
790
|
+
const sx = q2.x - q.x;
|
|
791
|
+
const sy = q2.y - q.y;
|
|
792
|
+
const denom = rx * sy - ry * sx;
|
|
793
|
+
if (denom === 0) continue;
|
|
794
|
+
const t = ((q.x - p.x) * sy - (q.y - p.y) * sx) / denom;
|
|
795
|
+
return { x: p.x + t * rx, y: p.y + t * ry };
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
var HOP_R = 7;
|
|
801
|
+
function hoppedPath(g, hops) {
|
|
802
|
+
if (hops.length === 0) return null;
|
|
803
|
+
const N = 49;
|
|
804
|
+
const pts = [];
|
|
805
|
+
for (let s = 0; s <= N; s++) pts.push(cubicAt(g, s / N));
|
|
806
|
+
const onSeg = /* @__PURE__ */ new Map();
|
|
807
|
+
for (const hp of hops) {
|
|
808
|
+
let bestSeg = -1;
|
|
809
|
+
let bestD = Infinity;
|
|
810
|
+
let bestPt = null;
|
|
811
|
+
for (let k = 1; k <= N; k++) {
|
|
812
|
+
const a = pts[k - 1];
|
|
813
|
+
const b = pts[k];
|
|
814
|
+
const dx = b.x - a.x;
|
|
815
|
+
const dy = b.y - a.y;
|
|
816
|
+
const len2 = dx * dx + dy * dy || 1;
|
|
817
|
+
let f = ((hp.x - a.x) * dx + (hp.y - a.y) * dy) / len2;
|
|
818
|
+
f = Math.max(0, Math.min(1, f));
|
|
819
|
+
const px = a.x + f * dx;
|
|
820
|
+
const py = a.y + f * dy;
|
|
821
|
+
const d2 = Math.hypot(hp.x - px, hp.y - py);
|
|
822
|
+
if (d2 < bestD) {
|
|
823
|
+
bestD = d2;
|
|
824
|
+
bestSeg = k;
|
|
825
|
+
bestPt = { x: px, y: py };
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (bestSeg >= 3 && bestSeg <= N - 3 && bestPt && !onSeg.has(bestSeg))
|
|
829
|
+
onSeg.set(bestSeg, bestPt);
|
|
830
|
+
}
|
|
831
|
+
if (onSeg.size === 0) return null;
|
|
832
|
+
let d = `M ${pts[0].x} ${pts[0].y}`;
|
|
833
|
+
for (let k = 1; k <= N; k++) {
|
|
834
|
+
const a = pts[k - 1];
|
|
835
|
+
const b = pts[k];
|
|
836
|
+
const hp = onSeg.get(k);
|
|
837
|
+
if (hp) {
|
|
838
|
+
const segLen = Math.hypot(b.x - a.x, b.y - a.y) || 1;
|
|
839
|
+
const dir = { x: (b.x - a.x) / segLen, y: (b.y - a.y) / segLen };
|
|
840
|
+
let perp = { x: dir.y, y: -dir.x };
|
|
841
|
+
if (perp.y > 0) perp = { x: -perp.x, y: -perp.y };
|
|
842
|
+
const A = { x: hp.x - dir.x * HOP_R, y: hp.y - dir.y * HOP_R };
|
|
843
|
+
const B = { x: hp.x + dir.x * HOP_R, y: hp.y + dir.y * HOP_R };
|
|
844
|
+
const k1 = {
|
|
845
|
+
x: A.x + perp.x * HOP_R * 1.33,
|
|
846
|
+
y: A.y + perp.y * HOP_R * 1.33
|
|
847
|
+
};
|
|
848
|
+
const k2 = {
|
|
849
|
+
x: B.x + perp.x * HOP_R * 1.33,
|
|
850
|
+
y: B.y + perp.y * HOP_R * 1.33
|
|
851
|
+
};
|
|
852
|
+
d += ` L ${A.x} ${A.y} C ${k1.x} ${k1.y}, ${k2.x} ${k2.y}, ${B.x} ${B.y} L ${b.x} ${b.y}`;
|
|
853
|
+
} else {
|
|
854
|
+
d += ` L ${b.x} ${b.y}`;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return d;
|
|
858
|
+
}
|
|
859
|
+
function pathCrossings(g, obstacles) {
|
|
860
|
+
if (obstacles.length === 0) return 0;
|
|
861
|
+
let hits = 0;
|
|
862
|
+
for (let i = 1; i < EDGE_SAMPLES; i++) {
|
|
863
|
+
const p = cubicAt(g, i / EDGE_SAMPLES);
|
|
864
|
+
for (const r of obstacles) {
|
|
865
|
+
const x0 = r.x + EDGE_OBSTACLE_INSET;
|
|
866
|
+
const y0 = r.y + EDGE_OBSTACLE_INSET;
|
|
867
|
+
const x1 = r.x + r.w - EDGE_OBSTACLE_INSET;
|
|
868
|
+
const y1 = r.y + r.h - EDGE_OBSTACLE_INSET;
|
|
869
|
+
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1) {
|
|
870
|
+
hits++;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return hits;
|
|
876
|
+
}
|
|
877
|
+
function sketchEdgeGeometry(layout, offsets) {
|
|
878
|
+
const off = (id) => offsets?.get(id) ?? { dx: 0, dy: 0 };
|
|
879
|
+
const rectById = /* @__PURE__ */ new Map();
|
|
880
|
+
for (const n of layout.nodes) {
|
|
881
|
+
const o = off(n.id);
|
|
882
|
+
rectById.set(n.id, { x: n.x + o.dx, y: n.y + o.dy, w: n.w, h: n.h });
|
|
883
|
+
}
|
|
884
|
+
for (const b of layout.boxes) {
|
|
885
|
+
const o = off(b.id);
|
|
886
|
+
rectById.set(b.id, { x: b.x + o.dx, y: b.y + o.dy, w: b.w, h: b.h });
|
|
887
|
+
}
|
|
888
|
+
const portsById = /* @__PURE__ */ new Map();
|
|
889
|
+
for (const box of layout.boxes) {
|
|
890
|
+
const o = off(box.id);
|
|
891
|
+
const kids = layout.nodes.filter((n) => n.boxLabel === box.label);
|
|
892
|
+
const ys = kids.map((k) => k.y + off(k.id).dy + k.h / 2);
|
|
893
|
+
const xs = kids.map((k) => k.x + off(k.id).dx + k.w / 2);
|
|
894
|
+
ys.push(box.y + o.dy + box.h / 2);
|
|
895
|
+
xs.push(box.x + o.dx + box.w / 2);
|
|
896
|
+
portsById.set(box.id, { ys, xs });
|
|
897
|
+
}
|
|
898
|
+
const sides = assignEdgeSides(layout.edges, rectById);
|
|
899
|
+
const boxIdByLabel = /* @__PURE__ */ new Map();
|
|
900
|
+
for (const b of layout.boxes) boxIdByLabel.set(b.label, b.id);
|
|
901
|
+
const boxOf = (id) => {
|
|
902
|
+
const n = layout.nodes.find((m) => m.id === id);
|
|
903
|
+
return n?.boxLabel ? boxIdByLabel.get(n.boxLabel) : void 0;
|
|
904
|
+
};
|
|
905
|
+
const obstacles = [];
|
|
906
|
+
for (const [id, rect] of rectById) obstacles.push({ id, rect });
|
|
907
|
+
const normalOf = (s) => s === "L" ? { x: -1, y: 0 } : s === "R" ? { x: 1, y: 0 } : s === "T" ? { x: 0, y: -1 } : { x: 0, y: 1 };
|
|
908
|
+
const facingCost = (from, to, side) => {
|
|
909
|
+
const dx = to.x + to.w / 2 - (from.x + from.w / 2);
|
|
910
|
+
const dy = to.y + to.h / 2 - (from.y + from.h / 2);
|
|
911
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
912
|
+
const n = normalOf(side);
|
|
913
|
+
return 1 - (n.x * dx + n.y * dy) / len;
|
|
651
914
|
};
|
|
915
|
+
const ctx = layout.edges.map((edge) => {
|
|
916
|
+
const source = rectById.get(edge.sourceId);
|
|
917
|
+
const target = rectById.get(edge.targetId);
|
|
918
|
+
if (!source || !target) return null;
|
|
919
|
+
const exclude = new Set(
|
|
920
|
+
[
|
|
921
|
+
edge.sourceId,
|
|
922
|
+
edge.targetId,
|
|
923
|
+
boxOf(edge.sourceId),
|
|
924
|
+
boxOf(edge.targetId)
|
|
925
|
+
].filter((x) => x !== void 0)
|
|
926
|
+
);
|
|
927
|
+
return {
|
|
928
|
+
source,
|
|
929
|
+
target,
|
|
930
|
+
sPorts: portsById.get(edge.sourceId),
|
|
931
|
+
tPorts: portsById.get(edge.targetId),
|
|
932
|
+
obstacleRects: obstacles.filter((o) => !exclude.has(o.id)).map((o) => o.rect),
|
|
933
|
+
adjacent: /* @__PURE__ */ new Set()
|
|
934
|
+
};
|
|
935
|
+
});
|
|
936
|
+
for (let a = 0; a < layout.edges.length; a++) {
|
|
937
|
+
for (let b = a + 1; b < layout.edges.length; b++) {
|
|
938
|
+
const ea = layout.edges[a];
|
|
939
|
+
const eb = layout.edges[b];
|
|
940
|
+
if (ea.sourceId === eb.sourceId || ea.sourceId === eb.targetId || ea.targetId === eb.sourceId || ea.targetId === eb.targetId) {
|
|
941
|
+
ctx[a]?.adjacent.add(b);
|
|
942
|
+
ctx[b]?.adjacent.add(a);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
const W_NODE = 100;
|
|
947
|
+
const W_EDGE = 8;
|
|
948
|
+
const scoreOf = (c, g, poly, self, polys2, s, t) => {
|
|
949
|
+
let edgeCross = 0;
|
|
950
|
+
for (let j = 0; j < polys2.length; j++) {
|
|
951
|
+
if (j === self || c.adjacent.has(j)) continue;
|
|
952
|
+
const pj = polys2[j];
|
|
953
|
+
if (pj) edgeCross += polyCrossings(poly, pj);
|
|
954
|
+
}
|
|
955
|
+
return pathCrossings(g, c.obstacleRects) * W_NODE + edgeCross * W_EDGE + facingCost(c.source, c.target, s) + facingCost(c.target, c.source, t);
|
|
956
|
+
};
|
|
957
|
+
const chosen = layout.edges.map(
|
|
958
|
+
(_, i) => sides[i] ?? { s: "R", t: "L" }
|
|
959
|
+
);
|
|
960
|
+
const geoms = ctx.map(
|
|
961
|
+
(c, i) => c ? edgePath(
|
|
962
|
+
c.source,
|
|
963
|
+
c.target,
|
|
964
|
+
chosen[i].s,
|
|
965
|
+
chosen[i].t,
|
|
966
|
+
c.sPorts,
|
|
967
|
+
c.tPorts
|
|
968
|
+
) : null
|
|
969
|
+
);
|
|
970
|
+
const polys = geoms.map((g) => g ? polyline(g) : null);
|
|
971
|
+
for (let pass = 0; pass < 3; pass++) {
|
|
972
|
+
let changed = false;
|
|
973
|
+
for (let i = 0; i < ctx.length; i++) {
|
|
974
|
+
const c = ctx[i];
|
|
975
|
+
const g = geoms[i];
|
|
976
|
+
const p = polys[i];
|
|
977
|
+
if (!c || !g || !p) continue;
|
|
978
|
+
const cur = chosen[i];
|
|
979
|
+
const curScore = scoreOf(c, g, p, i, polys, cur.s, cur.t);
|
|
980
|
+
if (curScore < W_EDGE) continue;
|
|
981
|
+
let bestScore = curScore;
|
|
982
|
+
let bestG = g;
|
|
983
|
+
let bestP = p;
|
|
984
|
+
let bestSide = cur;
|
|
985
|
+
for (const s of SIDES) {
|
|
986
|
+
for (const t of SIDES) {
|
|
987
|
+
const cg = edgePath(c.source, c.target, s, t, c.sPorts, c.tPorts);
|
|
988
|
+
const cp = polyline(cg);
|
|
989
|
+
const sc = scoreOf(c, cg, cp, i, polys, s, t);
|
|
990
|
+
if (sc < bestScore) {
|
|
991
|
+
bestScore = sc;
|
|
992
|
+
bestG = cg;
|
|
993
|
+
bestP = cp;
|
|
994
|
+
bestSide = { s, t };
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (bestSide !== cur) {
|
|
999
|
+
chosen[i] = bestSide;
|
|
1000
|
+
geoms[i] = bestG;
|
|
1001
|
+
polys[i] = bestP;
|
|
1002
|
+
changed = true;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (!changed) break;
|
|
1006
|
+
}
|
|
1007
|
+
const hopsFor = layout.edges.map(() => []);
|
|
1008
|
+
for (let i = 0; i < polys.length; i++) {
|
|
1009
|
+
for (let j = i + 1; j < polys.length; j++) {
|
|
1010
|
+
if (ctx[i]?.adjacent.has(j)) continue;
|
|
1011
|
+
const a = polys[i];
|
|
1012
|
+
const b = polys[j];
|
|
1013
|
+
if (!a || !b) continue;
|
|
1014
|
+
const pt = polyIntersection(a, b);
|
|
1015
|
+
if (pt) hopsFor[j].push(pt);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return layout.edges.map((edge, i) => {
|
|
1019
|
+
const g = geoms[i];
|
|
1020
|
+
if (!g) return null;
|
|
1021
|
+
const dRender = hoppedPath(g, hopsFor[i]);
|
|
1022
|
+
return {
|
|
1023
|
+
sourceId: edge.sourceId,
|
|
1024
|
+
targetId: edge.targetId,
|
|
1025
|
+
d: g.d,
|
|
1026
|
+
mid: g.mid,
|
|
1027
|
+
...dRender && { dRender }
|
|
1028
|
+
};
|
|
1029
|
+
});
|
|
652
1030
|
}
|
|
653
1031
|
function renderSketchForExport(container, parsed, layout, palette, isDark, options = {}) {
|
|
654
1032
|
renderSketch(container, parsed, layout, palette, isDark, {
|
|
@@ -659,6 +1037,7 @@ function renderSketchForExport(container, parsed, layout, palette, isDark, optio
|
|
|
659
1037
|
|
|
660
1038
|
export {
|
|
661
1039
|
renderSketch,
|
|
1040
|
+
sketchEdgeGeometry,
|
|
662
1041
|
renderSketchForExport
|
|
663
1042
|
};
|
|
664
|
-
//# sourceMappingURL=chunk-
|
|
1043
|
+
//# sourceMappingURL=chunk-BBGDM4NQ.js.map
|