@diagrammo/dgmo 0.90.0 → 0.91.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/advanced.d.ts +156 -2
- package/dist/advanced.js +558 -115
- package/dist/block.d.ts +10 -1
- package/dist/block.js +46 -39
- package/dist/{calculator-PX3JHKAS.js → calculator-3LZUWOBK.js} +1 -1
- package/dist/chart-meta.js +12 -12
- package/dist/{charts-d3-QW4ERNUE.js → charts-d3-YXD6VGZQ.js} +3 -3
- package/dist/{chunk-64KSPLU2.js → chunk-273GB7WK.js} +4 -4
- package/dist/{chunk-GYBKG4Z6.js → chunk-2A4OFZ2Z.js} +2 -2
- package/dist/{chunk-YWRZG6GN.js → chunk-2AM6VA3A.js} +8 -8
- package/dist/{chunk-PQ5NW3QZ.js → chunk-2UV627GG.js} +4 -4
- package/dist/{chunk-AAC3XQWV.js → chunk-37QQXKFV.js} +8 -9
- package/dist/{chunk-RCBHL2B5.js → chunk-3LINSNJT.js} +112 -112
- package/dist/{chunk-5TZPIKNV.js → chunk-3SLRZKLB.js} +2 -2
- package/dist/{chunk-X3WYJ5T7.js → chunk-3YTAOMMN.js} +1 -1
- package/dist/{chunk-A5EE66RQ.js → chunk-53BJIOLF.js} +1 -1
- package/dist/{chunk-QRIW46LR.js → chunk-57L2JPP2.js} +6 -2
- package/dist/{chunk-IIOLFAGJ.js → chunk-5DIBB2QG.js} +51 -32
- package/dist/{chunk-7Z2VFRP5.js → chunk-5U6DXIMV.js} +47 -24
- package/dist/{chunk-5M6PMV5Z.js → chunk-5VPWIC6T.js} +3 -3
- package/dist/{chunk-SLO22FPS.js → chunk-634LDSN6.js} +1 -1
- package/dist/{chunk-G5BGW4BX.js → chunk-6NO3MNBC.js} +3 -3
- package/dist/{chunk-NUYWNKHH.js → chunk-6QEXWMBP.js} +12 -16
- package/dist/{chunk-POBNN5DP.js → chunk-7BBRSOKS.js} +2 -2
- package/dist/{chunk-NFWRIC2V.js → chunk-AR4QVMWG.js} +4 -1
- package/dist/{chunk-JRQ4LBQI.js → chunk-B6EUFLRP.js} +4 -4
- package/dist/{chunk-LNQDICFJ.js → chunk-CPGKRI7H.js} +5 -8
- package/dist/{chunk-ZNNVI5SR.js → chunk-CU2PZLZP.js} +53 -31
- package/dist/{chunk-LBRHDWEA.js → chunk-CVZBLHHW.js} +1 -1
- package/dist/{chunk-S4LLHDGK.js → chunk-CXIPV2FY.js} +3 -3
- package/dist/{chunk-ICYPGWOV.js → chunk-D7DXNQW5.js} +2 -2
- package/dist/{chunk-54YUDXGP.js → chunk-D7PP35BA.js} +1 -1
- package/dist/{chunk-RRBV4HIM.js → chunk-DLX7MEN4.js} +1 -1
- package/dist/{chunk-S7C32S2T.js → chunk-EDPDAUBL.js} +2 -2
- package/dist/{chunk-LC5LY5V2.js → chunk-EP7BT3HU.js} +1 -1
- package/dist/{chunk-ICZ7M6IZ.js → chunk-EQJ3U5EW.js} +1 -1
- package/dist/{chunk-K4GUO7FV.js → chunk-F2436VRR.js} +1 -1
- package/dist/{chunk-5M52RPAS.js → chunk-F26ZPBSF.js} +2 -2
- package/dist/{chunk-3BQCSQQJ.js → chunk-FJCYK4K3.js} +11 -11
- package/dist/{chunk-PXEUQ7EG.js → chunk-G22UV5AF.js} +4 -4
- package/dist/{chunk-CUY56BK4.js → chunk-G3EUQMV4.js} +3 -3
- package/dist/{chunk-I6FWHICD.js → chunk-GCDW3WAY.js} +5 -5
- package/dist/{chunk-WHRIN7N3.js → chunk-HFG7KQOY.js} +12 -14
- package/dist/{chunk-SVQDLYX7.js → chunk-HLVGZXM5.js} +1 -1
- package/dist/{chunk-3HBR3YAN.js → chunk-HSGWR2FL.js} +6 -6
- package/dist/{chunk-RNXX2GOQ.js → chunk-HWXUQCDY.js} +2 -2
- package/dist/{chunk-YE7D2S75.js → chunk-HYV6GSXM.js} +5 -2
- package/dist/{chunk-AHWA36O7.js → chunk-II4XJETG.js} +1 -1
- package/dist/{chunk-EB7AEM2H.js → chunk-IMKPFW67.js} +3 -3
- package/dist/{chunk-C4W62JZO.js → chunk-IS6WFBX7.js} +2 -2
- package/dist/{chunk-SMEVBJJJ.js → chunk-IUBCDNT2.js} +1 -1
- package/dist/{chunk-TQ644YGV.js → chunk-IWTUXGHN.js} +3 -3
- package/dist/{chunk-PNCKZFPE.js → chunk-J2SQNZ6D.js} +1 -1
- package/dist/{chunk-YKGUSW6D.js → chunk-JA2S7PHR.js} +7 -7
- package/dist/{chunk-IRVQT4GR.js → chunk-JJQWCI35.js} +2 -2
- package/dist/chunk-JJUDOR4I.js +110 -0
- package/dist/{chunk-VCHYS3RD.js → chunk-K3BYD3WU.js} +1 -1
- package/dist/{chunk-EEYQFJVK.js → chunk-KFXY5IW2.js} +2 -2
- package/dist/{chunk-Y6GQQ4Y2.js → chunk-LKR4FACF.js} +1 -3
- package/dist/{chunk-IJ27L3R4.js → chunk-MA42PIGJ.js} +1 -1
- package/dist/{chunk-GQVXYRPC.js → chunk-MI6SJJQU.js} +1 -1
- package/dist/{chunk-DXPT2HPH.js → chunk-MJKQ5ZYY.js} +2 -2
- package/dist/{chunk-J3ODKAWN.js → chunk-MNL547RV.js} +5 -5
- package/dist/{chunk-2EDJPHXQ.js → chunk-N254IJM2.js} +6 -6
- package/dist/{layout-search-YKUL4VBV.js → chunk-NWPMLX2V.js} +27 -30
- package/dist/{chunk-COPSI54O.js → chunk-PSGSFRRE.js} +2 -2
- package/dist/{chunk-FDRHBQUG.js → chunk-PUZ63XZM.js} +8 -8
- package/dist/{chunk-MIVSVEK4.js → chunk-PZVTFQI2.js} +2 -2
- package/dist/{chunk-W7QN5BC5.js → chunk-Q3N7PI3B.js} +180 -7
- package/dist/{chunk-HX2KJEPD.js → chunk-QKJ6MQXW.js} +1 -3
- package/dist/{chunk-NJYA4QSN.js → chunk-QVKTAU7P.js} +1 -1
- package/dist/{chunk-EK7JYFCL.js → chunk-R7BSF7Z7.js} +1 -1
- package/dist/{chunk-PIHAUVA4.js → chunk-RHXIUUWB.js} +1 -1
- package/dist/{chunk-GXP344YZ.js → chunk-RMTOZALT.js} +6 -3
- package/dist/{chunk-CYF2X3CG.js → chunk-ROCBGUJN.js} +7 -7
- package/dist/{chunk-RY5RRKYN.js → chunk-RVTYIGWZ.js} +3 -3
- package/dist/{chunk-NMKLX57Y.js → chunk-SKF7XLCM.js} +1 -1
- package/dist/{chunk-NP2SE6MQ.js → chunk-SMTWQ66K.js} +5 -5
- package/dist/{chunk-3AX6MCI6.js → chunk-SPQVER4T.js} +2 -2
- package/dist/{chunk-A5PUOHIS.js → chunk-SWBHH2UW.js} +1 -1
- package/dist/{chunk-7TF3QOOD.js → chunk-TIVMAITN.js} +14 -0
- package/dist/{chunk-4IYJOXGS.js → chunk-TLPY4ZBI.js} +604 -430
- package/dist/{chunk-U762HK4D.js → chunk-TPEYEOXA.js} +4 -4
- package/dist/{chunk-FS2LZBHG.js → chunk-UWJP4JSZ.js} +2 -2
- package/dist/{chunk-JX4RCC6B.js → chunk-V3KHZQPK.js} +2 -2
- package/dist/{chunk-RJYFHEP4.js → chunk-VGSSAMLA.js} +2 -2
- package/dist/{chunk-HIVJBESO.js → chunk-VMD2CYVP.js} +35 -36
- package/dist/{chunk-OSIUWQ3N.js → chunk-WNTPJZU7.js} +1 -1
- package/dist/{chunk-R2PTZ6QM.js → chunk-WTE27AJT.js} +7 -7
- package/dist/{chunk-OWJVSJLA.js → chunk-XLAREWBK.js} +2 -2
- package/dist/{chunk-NY56FM55.js → chunk-XLPJJ35N.js} +2 -2
- package/dist/{chunk-DNMICILX.js → chunk-XQTRGKQ3.js} +3 -3
- package/dist/{chunk-QOZ4RVQY.js → chunk-YZG37S7L.js} +3 -3
- package/dist/{chunk-62VWZ3SE.js → chunk-ZB2Q67NO.js} +10 -10
- package/dist/completion-registry.js +2 -2
- package/dist/{compute-JAP5E2E4.js → compute-2XWFVO7K.js} +1 -1
- package/dist/{dgmo-router-BJBXSZMV.js → dgmo-router-YHBMKTXY.js} +32 -32
- package/dist/{dimensions-AMA2S7RO.js → dimensions-QMGWJQTR.js} +3 -3
- package/dist/{flowchart-parser-ADZIFVCH.js → flowchart-parser-BLJ6RA53.js} +2 -2
- package/dist/{flowchart-renderer-CAG6ZNJ6.js → flowchart-renderer-FXRQKXAK.js} +10 -6
- package/dist/index.js +37 -37
- package/dist/{layout-5VSMZPMG.js → layout-5HCEF7VO.js} +1 -1
- package/dist/{layout-VQ2USZJ3.js → layout-6PLSBB5X.js} +2 -2
- package/dist/{layout-UIV56NUA.js → layout-B7PQRAMB.js} +1 -1
- package/dist/{layout-C6MKMOBI.js → layout-CCVCLZ6S.js} +1 -1
- package/dist/{layout-T2PGKQUQ.js → layout-CRUAP7JG.js} +2 -2
- package/dist/{layout-UFB2O4AO.js → layout-G42FDCF3.js} +2 -2
- package/dist/{layout-6OSF2UGP.js → layout-IV4H2FLB.js} +2 -2
- package/dist/{layout-4RRC7XU7.js → layout-JTNRSGOS.js} +6 -3
- package/dist/{layout-H4K54IW3.js → layout-RBLD5EGX.js} +6 -3
- package/dist/{layout-SW3XWYKC.js → layout-ROAVGBUC.js} +1 -1
- package/dist/{layout-QS2SESBU.js → layout-T2DQ4M77.js} +6 -2
- package/dist/{layout-ZP7XYVXF.js → layout-YKGQRFDM.js} +2 -4
- package/dist/layout-search-L75YOBME.js +42 -0
- package/dist/{parser-NAUUUCI3.js → parser-2XCDVLSN.js} +2 -2
- package/dist/{parser-ESZ5J5IJ.js → parser-4QNRCGU5.js} +2 -2
- package/dist/{parser-W2DWCCLO.js → parser-6NSQLPTS.js} +2 -2
- package/dist/{parser-223VOHSB.js → parser-6X4GGH2R.js} +2 -2
- package/dist/{parser-B2FWP7ZO.js → parser-D6YRVV75.js} +2 -2
- package/dist/{parser-T2RVIRDG.js → parser-EY3VJWBE.js} +2 -2
- package/dist/{parser-KFIK3EOO.js → parser-EYF4ZSZO.js} +2 -2
- package/dist/{parser-2PNV7UI3.js → parser-H2DJEAPG.js} +2 -2
- package/dist/{parser-OV2WDSEV.js → parser-ILWAA3QJ.js} +2 -2
- package/dist/{parser-FV6RGALQ.js → parser-KMFMNZYI.js} +2 -2
- package/dist/{parser-LGUT7KKH.js → parser-MDSVVCJP.js} +2 -2
- package/dist/{parser-HPR7G7F6.js → parser-QL4DEPVA.js} +3 -3
- package/dist/{parser-BJDQX4KV.js → parser-UEDPLM46.js} +2 -2
- package/dist/{parser-E5HFYL7B.js → parser-UL6WN6W5.js} +2 -2
- package/dist/{parser-5ZD2NKGU.js → parser-ULSUK36C.js} +2 -2
- package/dist/{parser-57YQEEMC.js → parser-UY3K4ROB.js} +1 -1
- package/dist/{parser-MYRGCK7Q.js → parser-UYQNNQKT.js} +2 -2
- package/dist/{parser-NJ5VEZA3.js → parser-VG747VR6.js} +2 -2
- package/dist/{parser-CA5WC5HF.js → parser-VK4PNDX4.js} +2 -2
- package/dist/{parser-JFNDS5E5.js → parser-X5FQ36KJ.js} +2 -2
- package/dist/{parser-I4HZVIHX.js → parser-XO5IAXMT.js} +2 -2
- package/dist/{parser-WFY4ZJUW.js → parser-YVHO2NRM.js} +2 -2
- package/dist/{parser-J3BM2AP2.js → parser-YWZGIU3C.js} +2 -2
- package/dist/{parser-4B2PIXHI.js → parser-ZFLSULFC.js} +2 -2
- package/dist/{parser-RARXAHC7.js → parser-ZR7JAKSW.js} +1 -1
- package/dist/{renderer-3QM2DK7I.js → renderer-43IVPARP.js} +3 -3
- package/dist/{renderer-GWH5ACJ5.js → renderer-4MEZYGU6.js} +2 -2
- package/dist/{renderer-A3PMPUO6.js → renderer-54GXA3UO.js} +5 -5
- package/dist/{renderer-W22GX72R.js → renderer-7EAWN7MC.js} +4 -4
- package/dist/{renderer-IO3D5E4E.js → renderer-7SEXPBGM.js} +3 -3
- package/dist/{renderer-B3CPMS5R.js → renderer-B7B7BQM3.js} +7 -7
- package/dist/{renderer-IG72UJHW.js → renderer-I2LYSQBV.js} +3 -3
- package/dist/{renderer-OPDSKCQS.js → renderer-J2LOMTBC.js} +3 -3
- package/dist/{renderer-TTKTBB4C.js → renderer-JUH6M3XF.js} +6 -6
- package/dist/{renderer-COSJM7UG.js → renderer-KY6O5JTX.js} +33 -33
- package/dist/{renderer-PLRMST57.js → renderer-LHTDI5RV.js} +4 -4
- package/dist/{renderer-3W5T3IU6.js → renderer-LWL3IJOF.js} +3 -3
- package/dist/{renderer-SBXCPA3S.js → renderer-NCIDGJ2R.js} +5 -5
- package/dist/{renderer-AM4VZSBQ.js → renderer-OPA4JJKX.js} +4 -4
- package/dist/{renderer-O5RQHGK2.js → renderer-QMNC7TGN.js} +4 -4
- package/dist/{renderer-UVFGW2O6.js → renderer-QQNPJGAP.js} +3 -3
- package/dist/{renderer-WQ654YT5.js → renderer-R7RK7FKI.js} +1 -1
- package/dist/{renderer-TMQNTUQS.js → renderer-RFP55AW7.js} +10 -7
- package/dist/{renderer-FXCVH2M5.js → renderer-S3NFBJCY.js} +10 -7
- package/dist/{renderer-OA5D3ZKB.js → renderer-SD4ZHHAR.js} +6 -4
- package/dist/{renderer-PSMRAL72.js → renderer-SE7Z5AOL.js} +3 -3
- package/dist/{renderer-ON4PTUHJ.js → renderer-T2WUA7MC.js} +5 -5
- package/dist/{renderer-KK5BU5K2.js → renderer-TWKEZ3DD.js} +3 -3
- package/dist/{renderer-MK47ESCB.js → renderer-U5PD72G7.js} +3 -3
- package/dist/{renderer-52CHSV6S.js → renderer-VCTKBUTR.js} +5 -5
- package/dist/{renderer-PXGCR7N4.js → renderer-VNZTWATB.js} +3 -3
- package/dist/{renderer-4Z7FRQ2A.js → renderer-YDNWK6RI.js} +1 -1
- package/dist/{renderer-B4KE3NM4.js → renderer-YDOWBIUB.js} +4 -4
- package/dist/{renderer-LD2H7WGP.js → renderer-YQPZ7O2C.js} +1 -1
- package/dist/{renderer-6OOJNEQE.js → renderer-ZQ77CM6Y.js} +4 -4
- package/dist/{renderer-radial-42LVSG74.js → renderer-radial-TNNEL3YN.js} +4 -4
- package/dist/{resolver-XSXE2TRX.js → resolver-6DJLZF6Y.js} +1 -1
- package/dist/{state-parser-ROKY5KSI.js → state-parser-NIIVOU2Y.js} +2 -2
- package/dist/{state-renderer-MMG23G4W.js → state-renderer-TVLEG32M.js} +11 -7
- package/package.json +1 -1
- package/dist/chunk-6EK55ART.js +0 -116
- package/dist/chunk-HTNLLT34.js +0 -72
- /package/dist/{chunk-3FCSOYN4.js → chunk-5P2L5QXE.js} +0 -0
- /package/dist/{chunk-HJRP6PXL.js → chunk-BQVTV4LB.js} +0 -0
- /package/dist/{chunk-LYRDIVSY.js → chunk-GLCMUTO5.js} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-24YPR5EH.js";
|
|
10
10
|
import {
|
|
11
11
|
renderIntegratedLegend
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QVKTAU7P.js";
|
|
13
13
|
import {
|
|
14
14
|
ARROWHEAD_HEIGHT,
|
|
15
15
|
ARROWHEAD_WIDTH,
|
|
@@ -36,11 +36,11 @@ import {
|
|
|
36
36
|
isSequenceBlock,
|
|
37
37
|
isSequenceNote,
|
|
38
38
|
isSequenceSection
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-ZB2Q67NO.js";
|
|
40
40
|
import {
|
|
41
41
|
resolveActiveTagGroup,
|
|
42
42
|
tagAttrKey
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-QKJ6MQXW.js";
|
|
44
44
|
import {
|
|
45
45
|
fillModeFromOptions,
|
|
46
46
|
legendInlineRequested,
|
|
@@ -234,7 +234,7 @@ function resolveSequenceTags(parsed, activeTagGroup) {
|
|
|
234
234
|
const groupKey = tagAttrKey(group.name);
|
|
235
235
|
const participantMeta = /* @__PURE__ */ new Map();
|
|
236
236
|
for (const p of parsed.participants) {
|
|
237
|
-
participantMeta.set(p.id, { ...p.metadata
|
|
237
|
+
participantMeta.set(p.id, { ...p.metadata ?? {} });
|
|
238
238
|
}
|
|
239
239
|
propagateGroupTags(participantMeta, parsed.groups);
|
|
240
240
|
const inherited = computeReceiverInheritance(
|
|
@@ -332,7 +332,7 @@ function wrapLabelWords(words, maxWidth, fontSize) {
|
|
|
332
332
|
return lines;
|
|
333
333
|
}
|
|
334
334
|
var fill = (palette, isDark, color, fillMode) => color ? shapeFill(palette, color, isDark, { mode: fillMode }) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
|
|
335
|
-
var stroke = (palette, color) => color
|
|
335
|
+
var stroke = (palette, color) => color ?? palette.border;
|
|
336
336
|
var SW = 1.5;
|
|
337
337
|
var W = PARTICIPANT_BOX_WIDTH;
|
|
338
338
|
var H = PARTICIPANT_BOX_HEIGHT;
|
|
@@ -664,10 +664,29 @@ function applyGroupOrdering(participants, groups, messages = []) {
|
|
|
664
664
|
}
|
|
665
665
|
return result;
|
|
666
666
|
}
|
|
667
|
-
|
|
668
|
-
|
|
667
|
+
var BLOCK_HEADER_SPACE = 30;
|
|
668
|
+
var BLOCK_AFTER_SPACE = 15;
|
|
669
|
+
var FRAME_PADDING_TOP = 42;
|
|
670
|
+
var FRAME_PADDING_X = 30;
|
|
671
|
+
var FRAME_PADDING_BOTTOM = 15;
|
|
672
|
+
var FRAME_LABEL_HEIGHT = 18;
|
|
673
|
+
var SELF_ARROW_FRAME_PAD = 10;
|
|
674
|
+
var GROUP_PADDING_X = 15;
|
|
675
|
+
var GROUP_NEST_INSET_X = 6;
|
|
676
|
+
var GROUP_NEST_MIN_PAD_X = 4;
|
|
677
|
+
var GROUP_NEST_INSET_Y = 6;
|
|
678
|
+
var GROUP_PADDING_TOP = 22;
|
|
679
|
+
var GROUP_PADDING_BOTTOM = 8;
|
|
680
|
+
var GROUP_LABEL_SIZE = 11;
|
|
681
|
+
var GROUP_LABEL_WEIGHT = "bold";
|
|
682
|
+
function groupBottomPad(depth, maxGroupDepth) {
|
|
683
|
+
return GROUP_PADDING_BOTTOM + (maxGroupDepth - depth) * GROUP_NEST_INSET_Y;
|
|
684
|
+
}
|
|
685
|
+
function isSectionCollapsed(sec, collapsedSections) {
|
|
686
|
+
return collapsedSections?.has(sec.lineNumber) ?? false;
|
|
687
|
+
}
|
|
688
|
+
function layoutSequence(parsed, containerWidth, options) {
|
|
669
689
|
const { title, options: parsedOptions } = parsed;
|
|
670
|
-
const fillMode = fillModeFromOptions(parsedOptions);
|
|
671
690
|
const effectiveCollapsedGroups = options?.collapsedGroups ? new Set(options.collapsedGroups) : new Set(
|
|
672
691
|
parsed.groups.filter((g) => g.collapsed).map((g) => g.lineNumber)
|
|
673
692
|
);
|
|
@@ -694,7 +713,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
694
713
|
const participants = applyPositionOverrides(
|
|
695
714
|
applyGroupOrdering(sourceParticipants, groups, messages)
|
|
696
715
|
);
|
|
697
|
-
if (participants.length === 0) return;
|
|
716
|
+
if (participants.length === 0) return null;
|
|
698
717
|
const groupBoundaryIds = /* @__PURE__ */ new Set();
|
|
699
718
|
if (groups.length > 0) {
|
|
700
719
|
const pToG = /* @__PURE__ */ new Map();
|
|
@@ -733,7 +752,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
733
752
|
participants.length * effectiveGap,
|
|
734
753
|
uniformBoxWidth + 40
|
|
735
754
|
);
|
|
736
|
-
const containerWidth = options?.exportWidth ?? container.getBoundingClientRect().width;
|
|
737
755
|
const ctx = options?.exportWidth ? ScaleContext.identity() : ScaleContext.from(containerWidth, idealWidth);
|
|
738
756
|
const sGap = ctx.structural(effectiveGap);
|
|
739
757
|
const sBoxW = ctx.structural(uniformBoxWidth);
|
|
@@ -786,21 +804,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
786
804
|
parsedOptions["active-tag"],
|
|
787
805
|
options?.activeTagGroup
|
|
788
806
|
) ?? void 0;
|
|
789
|
-
let tagMap;
|
|
790
|
-
const tagValueToColor = /* @__PURE__ */ new Map();
|
|
791
|
-
if (activeTagGroup) {
|
|
792
|
-
tagMap = resolveSequenceTags(parsed, activeTagGroup);
|
|
793
|
-
const tg = parsed.tagGroups.find(
|
|
794
|
-
(g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()
|
|
795
|
-
);
|
|
796
|
-
if (tg) {
|
|
797
|
-
for (const entry of tg.entries) {
|
|
798
|
-
tagValueToColor.set(entry.value.toLowerCase(), entry.color);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
const getTagColor = (value) => value ? tagValueToColor.get(value.toLowerCase()) : void 0;
|
|
803
|
-
const tagKey = activeTagGroup ? tagAttrKey(activeTagGroup) : void 0;
|
|
804
807
|
const hiddenMsgIndices = /* @__PURE__ */ new Set();
|
|
805
808
|
if (collapsedSections && collapsedSections.size > 0) {
|
|
806
809
|
const sectionGroups = groupMessagesBySection(elements, messages);
|
|
@@ -836,9 +839,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
836
839
|
};
|
|
837
840
|
});
|
|
838
841
|
const stepSpacing = 35;
|
|
839
|
-
const BLOCK_HEADER_SPACE = 30;
|
|
840
|
-
const BLOCK_AFTER_SPACE = 15;
|
|
841
|
-
const FRAME_PADDING_TOP = 42;
|
|
842
842
|
const msgToFirstStep = /* @__PURE__ */ new Map();
|
|
843
843
|
const msgToLastStep = /* @__PURE__ */ new Map();
|
|
844
844
|
renderSteps.forEach((step, si) => {
|
|
@@ -907,13 +907,12 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
907
907
|
}
|
|
908
908
|
return -1;
|
|
909
909
|
};
|
|
910
|
-
const
|
|
911
|
-
const collapsedBandPad = (sec) => isSectionCollapsed(sec) ? COLLAPSED_SECTION_BAND_EXTRA / 2 : 0;
|
|
910
|
+
const collapsedBandPad = (sec) => isSectionCollapsed(sec, collapsedSections) ? COLLAPSED_SECTION_BAND_EXTRA / 2 : 0;
|
|
912
911
|
const SECTION_TOP_PAD = 35;
|
|
913
912
|
const SECTION_BOTTOM_PAD = 45;
|
|
914
913
|
const extraBeforeMsg = /* @__PURE__ */ new Map();
|
|
915
914
|
const addExtra = (msgIdx, amount) => {
|
|
916
|
-
extraBeforeMsg.set(msgIdx, (extraBeforeMsg.get(msgIdx)
|
|
915
|
+
extraBeforeMsg.set(msgIdx, (extraBeforeMsg.get(msgIdx) ?? 0) + amount);
|
|
917
916
|
};
|
|
918
917
|
const markBlockSpacing = (els) => {
|
|
919
918
|
for (let i = 0; i < els.length; i++) {
|
|
@@ -1093,7 +1092,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1093
1092
|
trailingSections.push(region.section);
|
|
1094
1093
|
continue;
|
|
1095
1094
|
}
|
|
1096
|
-
const existing = sectionsBeforeStep.get(filteredStep)
|
|
1095
|
+
const existing = sectionsBeforeStep.get(filteredStep) ?? [];
|
|
1097
1096
|
existing.push(region.section);
|
|
1098
1097
|
sectionsBeforeStep.set(filteredStep, existing);
|
|
1099
1098
|
}
|
|
@@ -1102,15 +1101,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1102
1101
|
sectionMsgCounts.set(region.section.lineNumber, region.msgIndices.length);
|
|
1103
1102
|
}
|
|
1104
1103
|
const sEdgePad = ctx.aesthetic(20);
|
|
1105
|
-
const GROUP_PADDING_X = 15;
|
|
1106
|
-
const GROUP_NEST_INSET_X = 6;
|
|
1107
|
-
const GROUP_NEST_MIN_PAD_X = 4;
|
|
1108
|
-
const GROUP_NEST_INSET_Y = 6;
|
|
1109
|
-
const GROUP_PADDING_TOP = 22;
|
|
1110
|
-
const GROUP_PADDING_BOTTOM = 8;
|
|
1111
|
-
const GROUP_LABEL_SIZE = 11;
|
|
1112
1104
|
const sGroupLabelSize = ctx.text(GROUP_LABEL_SIZE);
|
|
1113
|
-
const GROUP_LABEL_WEIGHT = "bold";
|
|
1114
1105
|
const showTitle = !!title && parsedOptions["no-title"] !== "on";
|
|
1115
1106
|
const titleOffset = showTitle ? sTitleHeight : 0;
|
|
1116
1107
|
const LEGEND_FIXED_GAP = 8;
|
|
@@ -1152,11 +1143,10 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1152
1143
|
});
|
|
1153
1144
|
const maxGroupDepth = parsed.groups.reduce((d, g) => Math.max(d, g.depth), 0);
|
|
1154
1145
|
const groupOffset = parsed.groups.length > 0 ? (maxGroupDepth + 1) * GROUP_PADDING_TOP + GROUP_LABEL_SIZE : 0;
|
|
1155
|
-
const groupBottomPad = (depth) => GROUP_PADDING_BOTTOM + (maxGroupDepth - depth) * GROUP_NEST_INSET_Y;
|
|
1156
1146
|
const participantStartY = sTopMargin + titleOffset + (header.inline ? 0 : legendTopSpace) + sParticipantYOffset + groupOffset;
|
|
1157
1147
|
const lifelineStartY0 = participantStartY + sBoxH;
|
|
1158
1148
|
const hasActors = participants.some((p) => p.type === "actor");
|
|
1159
|
-
const messageStartOffset = sMsgStartOffset + (hasActors ? 20 : 0) + (parsed.groups.length > 0 ? groupBottomPad(0) : 0);
|
|
1149
|
+
const messageStartOffset = sMsgStartOffset + (hasActors ? 20 : 0) + (parsed.groups.length > 0 ? groupBottomPad(0, maxGroupDepth) : 0);
|
|
1160
1150
|
const totalGaps = participants.length > 1 ? participants.length - 1 : 0;
|
|
1161
1151
|
const numWithinGaps = totalGaps - numGroupGaps;
|
|
1162
1152
|
let sWithinGap = sGap;
|
|
@@ -1223,7 +1213,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1223
1213
|
}
|
|
1224
1214
|
const step = renderSteps[i];
|
|
1225
1215
|
if (msgToFirstStep.get(step.messageIndex) === i) {
|
|
1226
|
-
const extra = extraBeforeMsg.get(step.messageIndex)
|
|
1216
|
+
const extra = extraBeforeMsg.get(step.messageIndex) ?? 0;
|
|
1227
1217
|
curY += extra;
|
|
1228
1218
|
}
|
|
1229
1219
|
curY += labelRoomBefore[i];
|
|
@@ -1303,6 +1293,20 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1303
1293
|
noteTopY + noteH + NOTE_TRAILING_GAP
|
|
1304
1294
|
);
|
|
1305
1295
|
}
|
|
1296
|
+
const noteLayouts = /* @__PURE__ */ new Map();
|
|
1297
|
+
for (const [note, topY] of noteYMap) {
|
|
1298
|
+
const position = effectiveNotePosition(note);
|
|
1299
|
+
const afterSelfCall = isNoteAfterSelfCall(note);
|
|
1300
|
+
const maxW = noteEffectiveMaxW(note.participantId, position, afterSelfCall);
|
|
1301
|
+
noteLayouts.set(note, {
|
|
1302
|
+
topY,
|
|
1303
|
+
position,
|
|
1304
|
+
afterSelfCall,
|
|
1305
|
+
maxW,
|
|
1306
|
+
textWidth: noteTextWidth(maxW)
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
const stepLabels = renderSteps.map((step) => displayMessageLabel(step));
|
|
1306
1310
|
const messageAreaHeight = contentBottomY - lifelineStartY0;
|
|
1307
1311
|
const lifelineLength = messageAreaHeight + sLifelineTail;
|
|
1308
1312
|
const edgeProjection = (id) => {
|
|
@@ -1434,82 +1438,35 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1434
1438
|
offsetX = leftMargin + Math.max(0, (svgWidth - totalWidth) / 2);
|
|
1435
1439
|
buildParticipantX();
|
|
1436
1440
|
}
|
|
1437
|
-
const
|
|
1438
|
-
if (ctx.isBelowFloor) {
|
|
1439
|
-
svg.attr("width", "100%");
|
|
1440
|
-
}
|
|
1441
|
-
const defs = svg.append("defs");
|
|
1442
|
-
defs.append("marker").attr("id", "seq-arrowhead").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polygon").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", palette.text);
|
|
1443
|
-
defs.append("marker").attr("id", "seq-arrowhead-open").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2);
|
|
1444
|
-
defs.append("marker").attr("id", "seq-arrowhead-async").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", "none").attr("stroke", palette.text).attr("stroke-width", 1.2);
|
|
1445
|
-
const arrowPoints = `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`;
|
|
1446
|
-
for (const [, color] of tagValueToColor) {
|
|
1447
|
-
const hex = color.replace("#", "");
|
|
1448
|
-
defs.append("marker").attr("id", `seq-arrowhead-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polygon").attr("points", arrowPoints).attr("fill", color);
|
|
1449
|
-
defs.append("marker").attr("id", `seq-arrowhead-async-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", arrowPoints).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.2);
|
|
1450
|
-
defs.append("marker").attr("id", `seq-arrowhead-open-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", arrowPoints).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.2);
|
|
1451
|
-
}
|
|
1452
|
-
const coloredMarker = (type, tagColor) => {
|
|
1453
|
-
if (tagColor) {
|
|
1454
|
-
const hex = tagColor.replace("#", "");
|
|
1455
|
-
switch (type) {
|
|
1456
|
-
case "call":
|
|
1457
|
-
return `url(#seq-arrowhead-c${hex})`;
|
|
1458
|
-
case "async":
|
|
1459
|
-
return `url(#seq-arrowhead-async-c${hex})`;
|
|
1460
|
-
case "return":
|
|
1461
|
-
return `url(#seq-arrowhead-open-c${hex})`;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
switch (type) {
|
|
1465
|
-
case "call":
|
|
1466
|
-
return "url(#seq-arrowhead)";
|
|
1467
|
-
case "async":
|
|
1468
|
-
return "url(#seq-arrowhead-async)";
|
|
1469
|
-
case "return":
|
|
1470
|
-
return "url(#seq-arrowhead-open)";
|
|
1471
|
-
}
|
|
1472
|
-
};
|
|
1473
|
-
if (showTitle) {
|
|
1474
|
-
const titleEl = svg.append("text").attr("class", "chart-title").attr("x", header.inline ? header.titleX : svgWidth / 2).attr("y", ctx.structural(TITLE_Y)).attr("text-anchor", header.inline ? header.titleAnchor : "middle").attr("fill", palette.text).attr("font-size", ctx.text(TITLE_FONT_SIZE)).attr("font-weight", TITLE_FONT_WEIGHT).text(title);
|
|
1475
|
-
if (parsed.titleLineNumber) {
|
|
1476
|
-
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
const hasTagGroups = parsed.tagGroups.length > 0 && !noLegend;
|
|
1480
|
-
const collapsedGroupNames = /* @__PURE__ */ new Set();
|
|
1481
|
-
const collapsedGroupMeta = /* @__PURE__ */ new Map();
|
|
1482
|
-
for (const group of parsed.groups) {
|
|
1483
|
-
if (effectiveCollapsedGroups.has(group.lineNumber)) {
|
|
1484
|
-
collapsedGroupNames.add(group.name);
|
|
1485
|
-
collapsedGroupMeta.set(group.name, {
|
|
1486
|
-
lineNumber: group.lineNumber,
|
|
1487
|
-
depth: group.depth,
|
|
1488
|
-
participantIds: group.participantIds,
|
|
1489
|
-
...group.metadata !== void 0 && { metadata: group.metadata }
|
|
1490
|
-
});
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
const participantLabels = new Map(
|
|
1494
|
-
parsed.participants.map((p) => [String(p.id), p.label])
|
|
1495
|
-
);
|
|
1496
|
-
const groupToggleName = (groupName, memberIds) => {
|
|
1497
|
-
const labels = memberIds.map((id) => participantLabels.get(id) ?? id);
|
|
1498
|
-
return labels.length > 0 ? `${groupName}, ${labels.join(", ")}` : groupName;
|
|
1499
|
-
};
|
|
1500
|
-
const participantTagColor = (id) => {
|
|
1501
|
-
const direct = getTagColor(tagMap?.participants.get(id));
|
|
1502
|
-
if (direct) return direct;
|
|
1503
|
-
if (!collapsedGroupNames.has(id) || !tagKey) return void 0;
|
|
1504
|
-
const meta = collapsedGroupMeta.get(id);
|
|
1505
|
-
return meta?.metadata ? getTagColor(meta.metadata[tagKey]) : void 0;
|
|
1506
|
-
};
|
|
1441
|
+
const collapsedGroupBoxes = /* @__PURE__ */ new Map();
|
|
1507
1442
|
const hasExpandedGroup = groups.some(
|
|
1508
1443
|
(g) => g.participantIds.some((id) => participantX.has(id))
|
|
1509
1444
|
);
|
|
1445
|
+
for (const group of parsed.groups) {
|
|
1446
|
+
if (!effectiveCollapsedGroups.has(group.lineNumber)) continue;
|
|
1447
|
+
const padTop = hasExpandedGroup ? (maxGroupDepth + 1 - group.depth) * GROUP_PADDING_TOP : 0;
|
|
1448
|
+
const padBottom = hasExpandedGroup ? groupBottomPad(group.depth, maxGroupDepth) : 0;
|
|
1449
|
+
const height = sBoxH + padTop + padBottom;
|
|
1450
|
+
const barHeight = ctx.structural(COLLAPSE_BAR_HEIGHT);
|
|
1451
|
+
collapsedGroupBoxes.set(group.name, {
|
|
1452
|
+
lineNumber: group.lineNumber,
|
|
1453
|
+
depth: group.depth,
|
|
1454
|
+
participantIds: group.participantIds,
|
|
1455
|
+
...group.metadata !== void 0 && { metadata: group.metadata },
|
|
1456
|
+
padTop,
|
|
1457
|
+
padBottom,
|
|
1458
|
+
height,
|
|
1459
|
+
// Centred in the box ABOVE the bar, so the bar does not push the name
|
|
1460
|
+
// off-centre the way it would if the whole box were used.
|
|
1461
|
+
nameY: -padTop + (height - barHeight) / 2,
|
|
1462
|
+
barY: -padTop + height - barHeight,
|
|
1463
|
+
barHeight
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1510
1466
|
const framedGroups = [...groups].sort((a, b) => a.depth - b.depth);
|
|
1511
1467
|
const allColumnXs = [...participantX.values()].sort((a, b) => a - b);
|
|
1512
1468
|
const frameExtents = /* @__PURE__ */ new Map();
|
|
1469
|
+
const groupFrames = [];
|
|
1513
1470
|
for (const group of framedGroups) {
|
|
1514
1471
|
if (group.participantIds.length === 0) continue;
|
|
1515
1472
|
const memberXs = group.participantIds.map((id) => participantX.get(id)).filter((x) => x !== void 0);
|
|
@@ -1535,118 +1492,18 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1535
1492
|
}
|
|
1536
1493
|
frameExtents.set(group.name, { minX, maxX });
|
|
1537
1494
|
const boxY = participantStartY - (maxGroupDepth + 1 - group.depth) * GROUP_PADDING_TOP;
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
const bandLeftmostX = Math.min(...Array.from(participantX.values()));
|
|
1549
|
-
const bandRightmostX = Math.max(...Array.from(participantX.values()));
|
|
1550
|
-
const sectionLineX1 = bandLeftmostX - sBoxW / 2 - 10;
|
|
1551
|
-
const sectionLineX2 = bandRightmostX + sBoxW / 2 + 10;
|
|
1552
|
-
const sectionLabelX = (sectionLineX1 + sectionLineX2) / 2;
|
|
1553
|
-
const sectionLabelTextFor = (sec) => {
|
|
1554
|
-
if (!isSectionCollapsed(sec)) return sec.label;
|
|
1555
|
-
const count = sectionMsgCounts.get(sec.lineNumber) ?? 0;
|
|
1556
|
-
return `${sec.label} (${count} ${count === 1 ? "message" : "messages"})`;
|
|
1557
|
-
};
|
|
1558
|
-
const sectionLabelBaselineFor = (sec, secY) => isSectionCollapsed(sec) ? secY + COLLAPSED_SECTION_LABEL_BASELINE : secY + 4;
|
|
1559
|
-
const sectionLabelBoxes = sectionRegions.map((region) => {
|
|
1560
|
-
const secY = sectionYPositions.get(region.section.lineNumber);
|
|
1561
|
-
if (secY === void 0) return null;
|
|
1562
|
-
const width = measureText(sectionLabelTextFor(region.section), 11, {
|
|
1563
|
-
bold: true
|
|
1495
|
+
groupFrames.push({
|
|
1496
|
+
group,
|
|
1497
|
+
x: minX,
|
|
1498
|
+
y: boxY,
|
|
1499
|
+
width: maxX - minX,
|
|
1500
|
+
height: sBoxH + (participantStartY - boxY) + groupBottomPad(group.depth, maxGroupDepth),
|
|
1501
|
+
headerHeight: participantStartY - boxY,
|
|
1502
|
+
// Centred across the header strip.
|
|
1503
|
+
labelX: (minX + maxX) / 2,
|
|
1504
|
+
labelY: boxY + sGroupLabelSize + 4
|
|
1564
1505
|
});
|
|
1565
|
-
|
|
1566
|
-
return {
|
|
1567
|
-
x1: sectionLabelX - width / 2 - SECTION_LABEL_CLEARANCE_X,
|
|
1568
|
-
x2: sectionLabelX + width / 2 + SECTION_LABEL_CLEARANCE_X,
|
|
1569
|
-
y1: baseline - SECTION_LABEL_CLEARANCE_ABOVE,
|
|
1570
|
-
y2: baseline + SECTION_LABEL_CLEARANCE_BELOW
|
|
1571
|
-
};
|
|
1572
|
-
}).filter((box) => box !== null);
|
|
1573
|
-
const lifelineSegments = (cx, yTop, yBottom) => {
|
|
1574
|
-
const cuts = sectionLabelBoxes.filter((b) => cx >= b.x1 && cx <= b.x2 && b.y2 > yTop && b.y1 < yBottom).sort((a, b) => a.y1 - b.y1);
|
|
1575
|
-
const segments = [];
|
|
1576
|
-
let y = yTop;
|
|
1577
|
-
for (const cut of cuts) {
|
|
1578
|
-
if (cut.y1 > y) segments.push([y, cut.y1]);
|
|
1579
|
-
y = Math.max(y, cut.y2);
|
|
1580
|
-
}
|
|
1581
|
-
if (y < yBottom) segments.push([y, yBottom]);
|
|
1582
|
-
return segments;
|
|
1583
|
-
};
|
|
1584
|
-
const lifelineStartY = lifelineStartY0;
|
|
1585
|
-
participants.forEach((participant) => {
|
|
1586
|
-
const cx = participantX.get(participant.id);
|
|
1587
|
-
const cy = participantStartY;
|
|
1588
|
-
const pTagValue = tagMap?.participants.get(participant.id);
|
|
1589
|
-
const pTagAttr = tagKey && pTagValue ? { key: tagKey, value: pTagValue.toLowerCase() } : void 0;
|
|
1590
|
-
const isCollapsedGroup = collapsedGroupNames.has(participant.id);
|
|
1591
|
-
const effectiveTagColor = participantTagColor(participant.id);
|
|
1592
|
-
renderParticipant(
|
|
1593
|
-
svg,
|
|
1594
|
-
participant,
|
|
1595
|
-
cx,
|
|
1596
|
-
cy,
|
|
1597
|
-
palette,
|
|
1598
|
-
isDark,
|
|
1599
|
-
effectiveTagColor,
|
|
1600
|
-
pTagAttr,
|
|
1601
|
-
fillMode,
|
|
1602
|
-
sBoxW,
|
|
1603
|
-
sBoxH,
|
|
1604
|
-
sLabelTextWidth,
|
|
1605
|
-
sLabelFontSize,
|
|
1606
|
-
isCollapsedGroup
|
|
1607
|
-
);
|
|
1608
|
-
if (isCollapsedGroup) {
|
|
1609
|
-
const meta = collapsedGroupMeta.get(participant.id);
|
|
1610
|
-
const drillColor = effectiveTagColor ?? mix(palette.textMuted, themeBaseBg(palette, isDark), 55);
|
|
1611
|
-
const drillBarH = ctx.structural(COLLAPSE_BAR_HEIGHT);
|
|
1612
|
-
const boxW = sBoxW;
|
|
1613
|
-
const padTop = hasExpandedGroup ? (maxGroupDepth + 1 - meta.depth) * GROUP_PADDING_TOP : 0;
|
|
1614
|
-
const padBottom = hasExpandedGroup ? groupBottomPad(meta.depth) : 0;
|
|
1615
|
-
const fullH = sBoxH + padTop + padBottom;
|
|
1616
|
-
const clipId = `clip-drill-group-${participant.id.replace(/[^a-zA-Z0-9-]/g, "-")}`;
|
|
1617
|
-
const participantG = svg.select(
|
|
1618
|
-
`.participant[data-participant-id="${participant.id}"]`
|
|
1619
|
-
);
|
|
1620
|
-
participantG.attr("data-group-toggle", "").attr("data-group-line", String(meta.lineNumber)).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "false").attr(
|
|
1621
|
-
"aria-label",
|
|
1622
|
-
groupToggleName(participant.id, meta.participantIds)
|
|
1623
|
-
).attr("cursor", "pointer");
|
|
1624
|
-
const pFill = effectiveTagColor ? mix(effectiveTagColor, themeBaseBg(palette, isDark), isDark ? 30 : 40) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
|
|
1625
|
-
const pStroke = effectiveTagColor || palette.border;
|
|
1626
|
-
participantG.append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6).attr("fill", pFill).attr("stroke", pStroke).attr("stroke-width", 1.5);
|
|
1627
|
-
const nameY = -padTop + (fullH - drillBarH) / 2;
|
|
1628
|
-
participantG.append("text").attr("x", 0).attr("y", nameY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", sLabelFontSize).attr("font-weight", "normal").attr("class", "collapsed-group-label").text(truncateText(participant.label, sLabelFontSize, sLabelTextWidth));
|
|
1629
|
-
participantG.append("clipPath").attr("id", clipId).append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6);
|
|
1630
|
-
participantG.append("rect").attr("class", "sequence-drill-bar").attr("x", -boxW / 2).attr("y", -padTop + fullH - drillBarH).attr("width", boxW).attr("height", drillBarH).attr("fill", drillColor).attr("clip-path", `url(#${clipId})`);
|
|
1631
|
-
}
|
|
1632
|
-
const llY = isCollapsedGroup ? lifelineStartY + (hasExpandedGroup ? groupBottomPad(collapsedGroupMeta.get(participant.id)?.depth ?? 0) : 0) : participant.type === "actor" ? lifelineStartY + ACTOR_LABEL_CLEARANCE : lifelineStartY;
|
|
1633
|
-
const llColor = effectiveTagColor || palette.textMuted;
|
|
1634
|
-
for (const [segTop, segBottom] of lifelineSegments(
|
|
1635
|
-
cx,
|
|
1636
|
-
llY,
|
|
1637
|
-
lifelineStartY + lifelineLength
|
|
1638
|
-
)) {
|
|
1639
|
-
const lifelineEl = svg.append("line").attr("x1", cx).attr("y1", segTop).attr("x2", cx).attr("y2", segBottom).attr("stroke", llColor).attr("stroke-width", 1).attr("stroke-dasharray", EDGE_DASH).attr("class", "lifeline").attr("data-participant-id", participant.id);
|
|
1640
|
-
if (tagKey && pTagValue) {
|
|
1641
|
-
lifelineEl.attr(`data-tag-${tagKey}`, pTagValue.toLowerCase());
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
});
|
|
1645
|
-
const FRAME_PADDING_X = 30;
|
|
1646
|
-
const FRAME_PADDING_BOTTOM = 15;
|
|
1647
|
-
const FRAME_LABEL_HEIGHT = 18;
|
|
1648
|
-
const SELF_ARROW_PROJECTION = sActivationWidth / 2 + sSelfCallWidth;
|
|
1649
|
-
const SELF_ARROW_FRAME_PAD = 10;
|
|
1506
|
+
}
|
|
1650
1507
|
const collectMsgIndices = (els) => {
|
|
1651
1508
|
const indices = [];
|
|
1652
1509
|
for (const el of els) {
|
|
@@ -1667,22 +1524,25 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1667
1524
|
}
|
|
1668
1525
|
return indices;
|
|
1669
1526
|
};
|
|
1670
|
-
const
|
|
1671
|
-
|
|
1672
|
-
|
|
1527
|
+
const firstStepOf = (indices) => {
|
|
1528
|
+
let first = Infinity;
|
|
1529
|
+
for (const mi of indices) {
|
|
1530
|
+
const step = msgToFirstStep.get(mi);
|
|
1531
|
+
if (step !== void 0) first = Math.min(first, step);
|
|
1532
|
+
}
|
|
1533
|
+
return first;
|
|
1534
|
+
};
|
|
1535
|
+
const SELF_ARROW_PROJECTION = sActivationWidth / 2 + sSelfCallWidth;
|
|
1536
|
+
const blockFrames = [];
|
|
1537
|
+
const layoutBlockFrames = (els) => {
|
|
1673
1538
|
for (const el of els) {
|
|
1674
1539
|
if (!isSequenceBlock(el)) continue;
|
|
1675
1540
|
const ifIndices = collectMsgIndices(el.children);
|
|
1676
|
-
const elseIfBranchData = []
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
indices: collectMsgIndices(branch.children),
|
|
1682
|
-
lineNumber: branch.lineNumber
|
|
1683
|
-
});
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1541
|
+
const elseIfBranchData = (el.elseIfBranches ?? []).map((branch) => ({
|
|
1542
|
+
label: branch.label,
|
|
1543
|
+
indices: collectMsgIndices(branch.children),
|
|
1544
|
+
lineNumber: branch.lineNumber
|
|
1545
|
+
}));
|
|
1686
1546
|
const elseIndices = collectMsgIndices(el.elseChildren);
|
|
1687
1547
|
const allIndices = [
|
|
1688
1548
|
...ifIndices,
|
|
@@ -1734,93 +1594,467 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1734
1594
|
const frameY = stepY(minStep) - FRAME_PADDING_TOP;
|
|
1735
1595
|
const frameW = maxPX - minPX + FRAME_PADDING_X * 2 + extraRight;
|
|
1736
1596
|
const frameH = stepY(maxStep) - stepY(minStep) + FRAME_PADDING_TOP + FRAME_PADDING_BOTTOM + (maxStepIsSelfCall ? sSelfCallHeight : 0);
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1597
|
+
const divider = (firstStep, text, lineNumber) => {
|
|
1598
|
+
const dividerY = stepY(firstStep) - BLOCK_HEADER_SPACE;
|
|
1599
|
+
return {
|
|
1600
|
+
x1: frameX,
|
|
1601
|
+
x2: frameX + frameW,
|
|
1602
|
+
y: dividerY,
|
|
1603
|
+
label: { x: frameX + 6, y: dividerY + 14, text },
|
|
1604
|
+
...lineNumber !== void 0 && { lineNumber }
|
|
1605
|
+
};
|
|
1606
|
+
};
|
|
1607
|
+
const dividers = [];
|
|
1746
1608
|
for (const branchData of elseIfBranchData) {
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
deferredLines.push({
|
|
1757
|
-
x1: frameX,
|
|
1758
|
-
y1: dividerY,
|
|
1759
|
-
x2: frameX + frameW,
|
|
1760
|
-
y2: dividerY,
|
|
1761
|
-
blockLine: branchData.lineNumber
|
|
1762
|
-
});
|
|
1763
|
-
deferredLabels.push({
|
|
1764
|
-
x: frameX + 6,
|
|
1765
|
-
y: dividerY + 14,
|
|
1766
|
-
text: `else if ${branchData.label}`,
|
|
1767
|
-
bold: false,
|
|
1768
|
-
italic: false,
|
|
1769
|
-
blockLine: branchData.lineNumber
|
|
1770
|
-
});
|
|
1771
|
-
}
|
|
1609
|
+
const firstBranchStep = firstStepOf(branchData.indices);
|
|
1610
|
+
if (firstBranchStep < Infinity) {
|
|
1611
|
+
dividers.push(
|
|
1612
|
+
divider(
|
|
1613
|
+
firstBranchStep,
|
|
1614
|
+
`else if ${branchData.label}`,
|
|
1615
|
+
branchData.lineNumber
|
|
1616
|
+
)
|
|
1617
|
+
);
|
|
1772
1618
|
}
|
|
1773
1619
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
const first = msgToFirstStep.get(mi);
|
|
1778
|
-
if (first !== void 0)
|
|
1779
|
-
firstElseStep = Math.min(firstElseStep, first);
|
|
1780
|
-
}
|
|
1781
|
-
if (firstElseStep < Infinity) {
|
|
1782
|
-
const dividerY = stepY(firstElseStep) - BLOCK_HEADER_SPACE;
|
|
1783
|
-
deferredLines.push({
|
|
1784
|
-
x1: frameX,
|
|
1785
|
-
y1: dividerY,
|
|
1786
|
-
x2: frameX + frameW,
|
|
1787
|
-
y2: dividerY,
|
|
1788
|
-
...el.elseLineNumber !== void 0 && {
|
|
1789
|
-
blockLine: el.elseLineNumber
|
|
1790
|
-
}
|
|
1791
|
-
});
|
|
1792
|
-
deferredLabels.push({
|
|
1793
|
-
x: frameX + 6,
|
|
1794
|
-
y: dividerY + 14,
|
|
1795
|
-
text: "else",
|
|
1796
|
-
bold: false,
|
|
1797
|
-
italic: false,
|
|
1798
|
-
...el.elseLineNumber !== void 0 && {
|
|
1799
|
-
blockLine: el.elseLineNumber
|
|
1800
|
-
}
|
|
1801
|
-
});
|
|
1802
|
-
}
|
|
1620
|
+
const firstElseStep = firstStepOf(elseIndices);
|
|
1621
|
+
if (firstElseStep < Infinity) {
|
|
1622
|
+
dividers.push(divider(firstElseStep, "else", el.elseLineNumber));
|
|
1803
1623
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1624
|
+
blockFrames.push({
|
|
1625
|
+
lineNumber: el.lineNumber,
|
|
1626
|
+
x: frameX,
|
|
1627
|
+
y: frameY,
|
|
1628
|
+
width: frameW,
|
|
1629
|
+
height: frameH,
|
|
1630
|
+
label: {
|
|
1631
|
+
x: frameX + 6,
|
|
1632
|
+
y: frameY + FRAME_LABEL_HEIGHT - 4,
|
|
1633
|
+
text: `${el.type} ${el.label}`
|
|
1634
|
+
},
|
|
1635
|
+
dividers
|
|
1636
|
+
});
|
|
1637
|
+
layoutBlockFrames(el.children);
|
|
1638
|
+
for (const branch of el.elseIfBranches ?? []) {
|
|
1639
|
+
layoutBlockFrames(branch.children);
|
|
1809
1640
|
}
|
|
1810
|
-
|
|
1641
|
+
layoutBlockFrames(el.elseChildren);
|
|
1811
1642
|
}
|
|
1812
1643
|
};
|
|
1813
|
-
if (elements && elements.length > 0)
|
|
1814
|
-
|
|
1644
|
+
if (elements && elements.length > 0) layoutBlockFrames(elements);
|
|
1645
|
+
const sectionLineX1 = Math.min(...Array.from(participantX.values())) - sBoxW / 2 - 10;
|
|
1646
|
+
const sectionLineX2 = Math.max(...Array.from(participantX.values())) + sBoxW / 2 + 10;
|
|
1647
|
+
const sectionLabelX = (sectionLineX1 + sectionLineX2) / 2;
|
|
1648
|
+
const sectionBands = [];
|
|
1649
|
+
for (const region of sectionRegions) {
|
|
1650
|
+
const sec = region.section;
|
|
1651
|
+
const secY = sectionYPositions.get(sec.lineNumber);
|
|
1652
|
+
if (secY === void 0) continue;
|
|
1653
|
+
const isCollapsed = isSectionCollapsed(sec, collapsedSections);
|
|
1654
|
+
const count = sectionMsgCounts.get(sec.lineNumber) ?? 0;
|
|
1655
|
+
const labelText = isCollapsed ? `${sec.label} (${count} ${count === 1 ? "message" : "messages"})` : sec.label;
|
|
1656
|
+
const height = isCollapsed ? COLLAPSED_SECTION_BAND_HEIGHT : SECTION_BAND_HEIGHT;
|
|
1657
|
+
const marks = [];
|
|
1658
|
+
let reach = null;
|
|
1659
|
+
if (isCollapsed) {
|
|
1660
|
+
const participation = summarizeSectionParticipation(
|
|
1661
|
+
messages,
|
|
1662
|
+
region.msgIndices
|
|
1663
|
+
);
|
|
1664
|
+
const involvedXs = participants.filter((p) => participation.has(p.id)).map((p) => participantX.get(p.id)).filter((x) => x !== void 0);
|
|
1665
|
+
if (involvedXs.length > 1) {
|
|
1666
|
+
reach = { x1: Math.min(...involvedXs), x2: Math.max(...involvedXs) };
|
|
1667
|
+
}
|
|
1668
|
+
for (const participant of participants) {
|
|
1669
|
+
const markX = participantX.get(participant.id);
|
|
1670
|
+
if (markX === void 0) continue;
|
|
1671
|
+
const part = participation.get(participant.id);
|
|
1672
|
+
marks.push({
|
|
1673
|
+
participantId: participant.id,
|
|
1674
|
+
x: markX,
|
|
1675
|
+
...part !== void 0 && { part },
|
|
1676
|
+
radius: part ? sectionMarkRadius(part.sends + part.receives) : 2.5
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
sectionBands.push({
|
|
1681
|
+
region,
|
|
1682
|
+
collapsed: isCollapsed,
|
|
1683
|
+
y: secY,
|
|
1684
|
+
x: sectionLineX1 - 10,
|
|
1685
|
+
width: sectionLineX2 - sectionLineX1 + 20,
|
|
1686
|
+
height,
|
|
1687
|
+
labelText,
|
|
1688
|
+
labelX: sectionLabelX,
|
|
1689
|
+
labelBaseline: isCollapsed ? secY + COLLAPSED_SECTION_LABEL_BASELINE : secY + 4,
|
|
1690
|
+
// The section label is set at a fixed 11px, bold.
|
|
1691
|
+
labelWidth: measureText(labelText, 11, { bold: true }),
|
|
1692
|
+
markY: secY + COLLAPSED_SECTION_MARK_OFFSET,
|
|
1693
|
+
marks,
|
|
1694
|
+
reach
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
const sectionLabelBoxes = sectionBands.map((band) => ({
|
|
1698
|
+
x1: band.labelX - band.labelWidth / 2 - SECTION_LABEL_CLEARANCE_X,
|
|
1699
|
+
x2: band.labelX + band.labelWidth / 2 + SECTION_LABEL_CLEARANCE_X,
|
|
1700
|
+
y1: band.labelBaseline - SECTION_LABEL_CLEARANCE_ABOVE,
|
|
1701
|
+
y2: band.labelBaseline + SECTION_LABEL_CLEARANCE_BELOW
|
|
1702
|
+
}));
|
|
1703
|
+
const lifelines = /* @__PURE__ */ new Map();
|
|
1704
|
+
for (const participant of participants) {
|
|
1705
|
+
const cx = participantX.get(participant.id);
|
|
1706
|
+
const collapsedBox = collapsedGroupBoxes.get(participant.id);
|
|
1707
|
+
const yTop = collapsedBox ? lifelineStartY0 + collapsedBox.padBottom : participant.type === "actor" ? lifelineStartY0 + ACTOR_LABEL_CLEARANCE : lifelineStartY0;
|
|
1708
|
+
const yBottom = lifelineStartY0 + lifelineLength;
|
|
1709
|
+
const cuts = sectionLabelBoxes.filter((b) => cx >= b.x1 && cx <= b.x2 && b.y2 > yTop && b.y1 < yBottom).sort((a, b) => a.y1 - b.y1);
|
|
1710
|
+
const segments = [];
|
|
1711
|
+
let y = yTop;
|
|
1712
|
+
for (const cut of cuts) {
|
|
1713
|
+
if (cut.y1 > y) segments.push([y, cut.y1]);
|
|
1714
|
+
y = Math.max(y, cut.y2);
|
|
1715
|
+
}
|
|
1716
|
+
if (y < yBottom) segments.push([y, yBottom]);
|
|
1717
|
+
lifelines.set(participant.id, segments);
|
|
1815
1718
|
}
|
|
1816
|
-
activations.
|
|
1719
|
+
const activationBars = activations.map((act) => {
|
|
1817
1720
|
const px = participantX.get(act.participantId);
|
|
1818
|
-
if (px === void 0) return;
|
|
1721
|
+
if (px === void 0) return null;
|
|
1819
1722
|
const x = px - sActivationWidth / 2 + act.depth * ACTIVATION_NEST_OFFSET;
|
|
1820
1723
|
const y1 = stepY(act.startStep);
|
|
1821
1724
|
const rawY2 = stepY(act.endStep);
|
|
1822
1725
|
const implicitY2 = rawY2 - labelRoomBefore[act.endStep] - ACTIVATION_IMPLICIT_END_CLEARANCE;
|
|
1823
1726
|
const y2 = act.implicitEnd && implicitY2 > y1 + sActivationWidth ? implicitY2 : rawY2;
|
|
1727
|
+
return { x, y: y1, width: sActivationWidth, height: y2 - y1 };
|
|
1728
|
+
});
|
|
1729
|
+
const activeDepthAt = (pid, stepIdx) => {
|
|
1730
|
+
let maxDepth = -1;
|
|
1731
|
+
for (const act of activations) {
|
|
1732
|
+
if (act.participantId === pid && act.startStep <= stepIdx && stepIdx <= act.endStep && act.depth > maxDepth) {
|
|
1733
|
+
maxDepth = act.depth;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return maxDepth;
|
|
1737
|
+
};
|
|
1738
|
+
const arrowEdgeX = (pid, stepIdx, side) => {
|
|
1739
|
+
const px = participantX.get(pid);
|
|
1740
|
+
const depth = activeDepthAt(pid, stepIdx);
|
|
1741
|
+
if (depth < 0) return px;
|
|
1742
|
+
const offset = depth * ACTIVATION_NEST_OFFSET;
|
|
1743
|
+
return side === "right" ? px + sActivationWidth / 2 + offset : px - sActivationWidth / 2 + offset;
|
|
1744
|
+
};
|
|
1745
|
+
const messageArrows = renderSteps.map((step, i) => {
|
|
1746
|
+
const fromX = participantX.get(step.from);
|
|
1747
|
+
const toX = participantX.get(step.to);
|
|
1748
|
+
if (fromX === void 0 || toX === void 0) return null;
|
|
1749
|
+
const y = stepY(i);
|
|
1750
|
+
if (step.from === step.to) {
|
|
1751
|
+
if (step.type !== "call") return null;
|
|
1752
|
+
const x = arrowEdgeX(step.from, i, "right");
|
|
1753
|
+
const loopX = x + sSelfCallWidth;
|
|
1754
|
+
return {
|
|
1755
|
+
kind: "self",
|
|
1756
|
+
x,
|
|
1757
|
+
loopX,
|
|
1758
|
+
y,
|
|
1759
|
+
returnY: y + sSelfCallHeight,
|
|
1760
|
+
label: { x: loopX + 5, y: y + sSelfCallHeight / 2 + 4 }
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
const goingRight = fromX < toX;
|
|
1764
|
+
const x1 = arrowEdgeX(step.from, i, goingRight ? "right" : "left");
|
|
1765
|
+
const x2 = arrowEdgeX(step.to, i, goingRight ? "left" : "right");
|
|
1766
|
+
return {
|
|
1767
|
+
kind: step.type,
|
|
1768
|
+
x1,
|
|
1769
|
+
x2,
|
|
1770
|
+
y,
|
|
1771
|
+
label: {
|
|
1772
|
+
x: (x1 + x2) / 2,
|
|
1773
|
+
y: y - (step.type === "call" ? MSG_LABEL_OFFSET : RETURN_LABEL_OFFSET)
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
});
|
|
1777
|
+
const noteBoxes = /* @__PURE__ */ new Map();
|
|
1778
|
+
const BULLET_BODY_INDENT = 10;
|
|
1779
|
+
for (const [note, noteLayout] of noteLayouts) {
|
|
1780
|
+
const px = participantX.get(note.participantId);
|
|
1781
|
+
if (px === void 0) continue;
|
|
1782
|
+
const { topY, position, afterSelfCall, maxW, textWidth } = noteLayout;
|
|
1783
|
+
const isRight = position === "right";
|
|
1784
|
+
const wrappedLines = wrapTextLines(note.text, textWidth, sNoteFontSize);
|
|
1785
|
+
const noteH = wrappedLines.length * sNoteLineH + sNotePadV * 2;
|
|
1786
|
+
const maxLineW = Math.max(
|
|
1787
|
+
...wrappedLines.map((l) => measureText(l.text, sNoteFontSize))
|
|
1788
|
+
);
|
|
1789
|
+
const noteW = Math.min(
|
|
1790
|
+
maxW,
|
|
1791
|
+
Math.max(80, maxLineW + sNotePadH * 2 + sNoteFold)
|
|
1792
|
+
);
|
|
1793
|
+
const rightOffset = afterSelfCall && isRight ? sActivationWidth / 2 + sSelfCallWidth + sNoteGap : sActivationWidth + sNoteGap;
|
|
1794
|
+
const noteX = isRight ? px + rightOffset : px - sActivationWidth - sNoteGap - noteW;
|
|
1795
|
+
noteBoxes.set(note, {
|
|
1796
|
+
x: noteX,
|
|
1797
|
+
y: topY,
|
|
1798
|
+
width: noteW,
|
|
1799
|
+
height: noteH,
|
|
1800
|
+
lines: wrappedLines.map((line, li) => ({
|
|
1801
|
+
kind: line.kind,
|
|
1802
|
+
text: line.text,
|
|
1803
|
+
x: noteX + sNotePadH + (line.kind === "plain" ? 0 : BULLET_BODY_INDENT),
|
|
1804
|
+
y: topY + sNotePadV + (li + 1) * sNoteLineH - 3,
|
|
1805
|
+
...line.kind === "bullet-first" && { bulletX: noteX + sNotePadH }
|
|
1806
|
+
}))
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
return {
|
|
1810
|
+
ctx,
|
|
1811
|
+
participants,
|
|
1812
|
+
messages,
|
|
1813
|
+
elements,
|
|
1814
|
+
groups,
|
|
1815
|
+
effectiveCollapsedGroups,
|
|
1816
|
+
activeTagGroup,
|
|
1817
|
+
renderSteps,
|
|
1818
|
+
stepLabels,
|
|
1819
|
+
activations,
|
|
1820
|
+
activationBars,
|
|
1821
|
+
messageArrows,
|
|
1822
|
+
labelRoomBefore,
|
|
1823
|
+
msgToFirstStep,
|
|
1824
|
+
msgToLastStep,
|
|
1825
|
+
stepYPositions,
|
|
1826
|
+
sectionYPositions,
|
|
1827
|
+
sectionRegions,
|
|
1828
|
+
sectionMsgCounts,
|
|
1829
|
+
noteLayouts,
|
|
1830
|
+
noteBoxes,
|
|
1831
|
+
participantX,
|
|
1832
|
+
participantStartY,
|
|
1833
|
+
lifelineStartY0,
|
|
1834
|
+
lifelineLength,
|
|
1835
|
+
lifelines,
|
|
1836
|
+
groupFrames,
|
|
1837
|
+
collapsedGroupBoxes,
|
|
1838
|
+
blockFrames,
|
|
1839
|
+
sectionBands,
|
|
1840
|
+
maxGroupDepth,
|
|
1841
|
+
svgWidth,
|
|
1842
|
+
totalHeight,
|
|
1843
|
+
showTitle,
|
|
1844
|
+
titleOffset,
|
|
1845
|
+
noLegend,
|
|
1846
|
+
legendConfig,
|
|
1847
|
+
header,
|
|
1848
|
+
sTopMargin,
|
|
1849
|
+
sBoxW,
|
|
1850
|
+
sBoxH,
|
|
1851
|
+
sLabelFontSize,
|
|
1852
|
+
sLabelTextWidth,
|
|
1853
|
+
sGroupLabelSize,
|
|
1854
|
+
sActivationWidth,
|
|
1855
|
+
ACTIVATION_NEST_OFFSET,
|
|
1856
|
+
sArrowheadW,
|
|
1857
|
+
sArrowheadH,
|
|
1858
|
+
sSelfCallWidth,
|
|
1859
|
+
sSelfCallHeight,
|
|
1860
|
+
sNoteFold,
|
|
1861
|
+
sNoteFontSize,
|
|
1862
|
+
sNoteGap,
|
|
1863
|
+
sNoteLineH,
|
|
1864
|
+
sNotePadH,
|
|
1865
|
+
sNotePadV
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateToLine, options) {
|
|
1869
|
+
d3Selection.select(container).selectAll("*").remove();
|
|
1870
|
+
const layout = layoutSequence(
|
|
1871
|
+
parsed,
|
|
1872
|
+
options?.exportWidth ?? container.getBoundingClientRect().width,
|
|
1873
|
+
options
|
|
1874
|
+
);
|
|
1875
|
+
if (!layout) return;
|
|
1876
|
+
const {
|
|
1877
|
+
ctx,
|
|
1878
|
+
participants,
|
|
1879
|
+
messages,
|
|
1880
|
+
elements,
|
|
1881
|
+
activeTagGroup,
|
|
1882
|
+
renderSteps,
|
|
1883
|
+
stepLabels,
|
|
1884
|
+
activations,
|
|
1885
|
+
activationBars,
|
|
1886
|
+
messageArrows,
|
|
1887
|
+
noteBoxes,
|
|
1888
|
+
participantX,
|
|
1889
|
+
participantStartY,
|
|
1890
|
+
lifelines,
|
|
1891
|
+
groupFrames,
|
|
1892
|
+
collapsedGroupBoxes,
|
|
1893
|
+
blockFrames,
|
|
1894
|
+
sectionBands,
|
|
1895
|
+
svgWidth,
|
|
1896
|
+
totalHeight,
|
|
1897
|
+
showTitle,
|
|
1898
|
+
titleOffset,
|
|
1899
|
+
noLegend,
|
|
1900
|
+
legendConfig,
|
|
1901
|
+
header,
|
|
1902
|
+
sTopMargin,
|
|
1903
|
+
sBoxW,
|
|
1904
|
+
sBoxH,
|
|
1905
|
+
sLabelFontSize,
|
|
1906
|
+
sLabelTextWidth,
|
|
1907
|
+
sGroupLabelSize,
|
|
1908
|
+
sArrowheadW,
|
|
1909
|
+
sArrowheadH,
|
|
1910
|
+
sSelfCallWidth,
|
|
1911
|
+
sSelfCallHeight,
|
|
1912
|
+
sNoteFold,
|
|
1913
|
+
sNoteFontSize
|
|
1914
|
+
} = layout;
|
|
1915
|
+
const { title, options: parsedOptions } = parsed;
|
|
1916
|
+
const fillMode = fillModeFromOptions(parsedOptions);
|
|
1917
|
+
let tagMap;
|
|
1918
|
+
const tagValueToColor = /* @__PURE__ */ new Map();
|
|
1919
|
+
if (activeTagGroup) {
|
|
1920
|
+
tagMap = resolveSequenceTags(parsed, activeTagGroup);
|
|
1921
|
+
const tg = parsed.tagGroups.find(
|
|
1922
|
+
(g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()
|
|
1923
|
+
);
|
|
1924
|
+
if (tg) {
|
|
1925
|
+
for (const entry of tg.entries) {
|
|
1926
|
+
tagValueToColor.set(entry.value.toLowerCase(), entry.color);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
const getTagColor = (value) => value ? tagValueToColor.get(value.toLowerCase()) : void 0;
|
|
1931
|
+
const tagKey = activeTagGroup ? tagAttrKey(activeTagGroup) : void 0;
|
|
1932
|
+
const svg = d3Selection.select(container).append("svg").attr("width", svgWidth).attr("height", totalHeight).attr("viewBox", `0 0 ${svgWidth} ${totalHeight}`).attr("preserveAspectRatio", "xMidYMin meet").attr("class", "sequence-diagram").style("font-family", FONT_FAMILY);
|
|
1933
|
+
if (ctx.isBelowFloor) {
|
|
1934
|
+
svg.attr("width", "100%");
|
|
1935
|
+
}
|
|
1936
|
+
const defs = svg.append("defs");
|
|
1937
|
+
defs.append("marker").attr("id", "seq-arrowhead").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polygon").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", palette.text);
|
|
1938
|
+
defs.append("marker").attr("id", "seq-arrowhead-open").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2);
|
|
1939
|
+
defs.append("marker").attr("id", "seq-arrowhead-async").attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`).attr("fill", "none").attr("stroke", palette.text).attr("stroke-width", 1.2);
|
|
1940
|
+
const arrowPoints = `0,0 ${sArrowheadW},${sArrowheadH / 2} 0,${sArrowheadH}`;
|
|
1941
|
+
for (const [, color] of tagValueToColor) {
|
|
1942
|
+
const hex = color.replace("#", "");
|
|
1943
|
+
defs.append("marker").attr("id", `seq-arrowhead-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polygon").attr("points", arrowPoints).attr("fill", color);
|
|
1944
|
+
defs.append("marker").attr("id", `seq-arrowhead-async-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", arrowPoints).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.2);
|
|
1945
|
+
defs.append("marker").attr("id", `seq-arrowhead-open-c${hex}`).attr("viewBox", `0 0 ${sArrowheadW} ${sArrowheadH}`).attr("refX", sArrowheadW).attr("refY", sArrowheadH / 2).attr("markerWidth", sArrowheadW).attr("markerHeight", sArrowheadH).attr("orient", "auto").append("polyline").attr("points", arrowPoints).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.2);
|
|
1946
|
+
}
|
|
1947
|
+
const coloredMarker = (type, tagColor) => {
|
|
1948
|
+
if (tagColor) {
|
|
1949
|
+
const hex = tagColor.replace("#", "");
|
|
1950
|
+
switch (type) {
|
|
1951
|
+
case "call":
|
|
1952
|
+
return `url(#seq-arrowhead-c${hex})`;
|
|
1953
|
+
case "async":
|
|
1954
|
+
return `url(#seq-arrowhead-async-c${hex})`;
|
|
1955
|
+
case "return":
|
|
1956
|
+
return `url(#seq-arrowhead-open-c${hex})`;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
switch (type) {
|
|
1960
|
+
case "call":
|
|
1961
|
+
return "url(#seq-arrowhead)";
|
|
1962
|
+
case "async":
|
|
1963
|
+
return "url(#seq-arrowhead-async)";
|
|
1964
|
+
case "return":
|
|
1965
|
+
return "url(#seq-arrowhead-open)";
|
|
1966
|
+
}
|
|
1967
|
+
};
|
|
1968
|
+
if (showTitle) {
|
|
1969
|
+
const titleEl = svg.append("text").attr("class", "chart-title").attr("x", header.inline ? header.titleX : svgWidth / 2).attr("y", ctx.structural(TITLE_Y)).attr("text-anchor", header.inline ? header.titleAnchor : "middle").attr("fill", palette.text).attr("font-size", ctx.text(TITLE_FONT_SIZE)).attr("font-weight", TITLE_FONT_WEIGHT).text(title);
|
|
1970
|
+
if (parsed.titleLineNumber) {
|
|
1971
|
+
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
const hasTagGroups = parsed.tagGroups.length > 0 && !noLegend;
|
|
1975
|
+
const participantLabels = new Map(
|
|
1976
|
+
parsed.participants.map((p) => [String(p.id), p.label])
|
|
1977
|
+
);
|
|
1978
|
+
const groupToggleName = (groupName, memberIds) => {
|
|
1979
|
+
const labels = memberIds.map((id) => participantLabels.get(id) ?? id);
|
|
1980
|
+
return labels.length > 0 ? `${groupName}, ${labels.join(", ")}` : groupName;
|
|
1981
|
+
};
|
|
1982
|
+
const participantTagColor = (id) => {
|
|
1983
|
+
const direct = getTagColor(tagMap?.participants.get(id));
|
|
1984
|
+
if (direct) return direct;
|
|
1985
|
+
if (!collapsedGroupBoxes.has(id) || !tagKey) return void 0;
|
|
1986
|
+
const meta = collapsedGroupBoxes.get(id);
|
|
1987
|
+
return meta?.metadata ? getTagColor(meta.metadata[tagKey]) : void 0;
|
|
1988
|
+
};
|
|
1989
|
+
for (const frame of groupFrames) {
|
|
1990
|
+
const { group } = frame;
|
|
1991
|
+
const groupTagValue = tagKey && group.metadata?.[tagKey];
|
|
1992
|
+
const groupTagColor = getTagColor(groupTagValue);
|
|
1993
|
+
const fillColor = groupTagColor ? mix(groupTagColor, themeBaseBg(palette, isDark), isDark ? 15 : 20) : isDark ? palette.surface : palette.bg;
|
|
1994
|
+
const strokeColor = groupTagColor ?? palette.textMuted;
|
|
1995
|
+
const groupG = svg.append("g").attr("class", "group-box-wrapper").attr("data-group-toggle", "").attr("data-group-line", String(group.lineNumber)).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "true").attr("aria-label", groupToggleName(group.name, group.participantIds)).attr("cursor", "pointer");
|
|
1996
|
+
groupG.append("rect").attr("x", frame.x).attr("y", frame.y).attr("width", frame.width).attr("height", frame.height).attr("rx", 6).attr("fill", fillColor).attr("stroke", strokeColor).attr("stroke-width", 1).attr("stroke-opacity", 0.5).attr("pointer-events", "none").attr("class", "group-box");
|
|
1997
|
+
groupG.append("rect").attr("x", frame.x).attr("y", frame.y).attr("width", frame.width).attr("height", frame.headerHeight).attr("fill", "transparent").attr("class", "group-label-hit");
|
|
1998
|
+
groupG.append("text").attr("x", frame.labelX).attr("y", frame.labelY).attr("text-anchor", "middle").attr("fill", strokeColor).attr("font-size", sGroupLabelSize).attr("font-weight", GROUP_LABEL_WEIGHT).attr("opacity", 0.7).attr("pointer-events", "none").attr("class", "group-label").text(group.name);
|
|
1999
|
+
}
|
|
2000
|
+
participants.forEach((participant) => {
|
|
2001
|
+
const cx = participantX.get(participant.id);
|
|
2002
|
+
const cy = participantStartY;
|
|
2003
|
+
const pTagValue = tagMap?.participants.get(participant.id);
|
|
2004
|
+
const pTagAttr = tagKey && pTagValue ? { key: tagKey, value: pTagValue.toLowerCase() } : void 0;
|
|
2005
|
+
const isCollapsedGroup = collapsedGroupBoxes.has(participant.id);
|
|
2006
|
+
const effectiveTagColor = participantTagColor(participant.id);
|
|
2007
|
+
renderParticipant(
|
|
2008
|
+
svg,
|
|
2009
|
+
participant,
|
|
2010
|
+
cx,
|
|
2011
|
+
cy,
|
|
2012
|
+
palette,
|
|
2013
|
+
isDark,
|
|
2014
|
+
effectiveTagColor,
|
|
2015
|
+
pTagAttr,
|
|
2016
|
+
fillMode,
|
|
2017
|
+
sBoxW,
|
|
2018
|
+
sBoxH,
|
|
2019
|
+
sLabelTextWidth,
|
|
2020
|
+
sLabelFontSize,
|
|
2021
|
+
isCollapsedGroup
|
|
2022
|
+
);
|
|
2023
|
+
if (isCollapsedGroup) {
|
|
2024
|
+
const meta = collapsedGroupBoxes.get(participant.id);
|
|
2025
|
+
const drillColor = effectiveTagColor ?? mix(palette.textMuted, themeBaseBg(palette, isDark), 55);
|
|
2026
|
+
const boxW = sBoxW;
|
|
2027
|
+
const { padTop, height: fullH, nameY, barY, barHeight } = meta;
|
|
2028
|
+
const clipId = `clip-drill-group-${participant.id.replace(/[^a-zA-Z0-9-]/g, "-")}`;
|
|
2029
|
+
const participantG = svg.select(
|
|
2030
|
+
`.participant[data-participant-id="${participant.id}"]`
|
|
2031
|
+
);
|
|
2032
|
+
participantG.attr("data-group-toggle", "").attr("data-group-line", String(meta.lineNumber)).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "false").attr(
|
|
2033
|
+
"aria-label",
|
|
2034
|
+
groupToggleName(participant.id, meta.participantIds)
|
|
2035
|
+
).attr("cursor", "pointer");
|
|
2036
|
+
const pFill = effectiveTagColor ? mix(effectiveTagColor, themeBaseBg(palette, isDark), isDark ? 30 : 40) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
|
|
2037
|
+
const pStroke = effectiveTagColor ?? palette.border;
|
|
2038
|
+
participantG.append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6).attr("fill", pFill).attr("stroke", pStroke).attr("stroke-width", 1.5);
|
|
2039
|
+
participantG.append("text").attr("x", 0).attr("y", nameY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", sLabelFontSize).attr("font-weight", "normal").attr("class", "collapsed-group-label").text(truncateText(participant.label, sLabelFontSize, sLabelTextWidth));
|
|
2040
|
+
participantG.append("clipPath").attr("id", clipId).append("rect").attr("x", -boxW / 2).attr("y", -padTop).attr("width", boxW).attr("height", fullH).attr("rx", 6);
|
|
2041
|
+
participantG.append("rect").attr("class", "sequence-drill-bar").attr("x", -boxW / 2).attr("y", barY).attr("width", boxW).attr("height", barHeight).attr("fill", drillColor).attr("clip-path", `url(#${clipId})`);
|
|
2042
|
+
}
|
|
2043
|
+
const llColor = effectiveTagColor ?? palette.textMuted;
|
|
2044
|
+
for (const [segTop, segBottom] of lifelines.get(participant.id) ?? []) {
|
|
2045
|
+
const lifelineEl = svg.append("line").attr("x1", cx).attr("y1", segTop).attr("x2", cx).attr("y2", segBottom).attr("stroke", llColor).attr("stroke-width", 1).attr("stroke-dasharray", EDGE_DASH).attr("class", "lifeline").attr("data-participant-id", participant.id);
|
|
2046
|
+
if (tagKey && pTagValue) {
|
|
2047
|
+
lifelineEl.attr(`data-tag-${tagKey}`, pTagValue.toLowerCase());
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
});
|
|
2051
|
+
for (const frame of blockFrames) {
|
|
2052
|
+
svg.append("rect").attr("x", frame.x).attr("y", frame.y).attr("width", frame.width).attr("height", frame.height).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1).attr("stroke-dasharray", HAIRLINE_DASH).attr("rx", 3).attr("ry", 3).attr("class", "block-frame").attr("data-block-line", String(frame.lineNumber));
|
|
2053
|
+
}
|
|
2054
|
+
activations.forEach((act, ai) => {
|
|
2055
|
+
const bar = activationBars[ai];
|
|
2056
|
+
if (!bar) return;
|
|
2057
|
+
const { x, y: y1, height } = bar;
|
|
1824
2058
|
const coveredLines = [];
|
|
1825
2059
|
for (let si = act.startStep; si <= act.endStep; si++) {
|
|
1826
2060
|
const step = renderSteps[si];
|
|
@@ -1832,162 +2066,125 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1832
2066
|
const triggerMsg = triggerStep !== void 0 ? messages[triggerStep.messageIndex] : void 0;
|
|
1833
2067
|
const actTagValue = triggerMsg ? tagMap?.messages.get(triggerMsg.lineNumber) : void 0;
|
|
1834
2068
|
const actTagColor = getTagColor(actTagValue);
|
|
1835
|
-
const actBaseColor = actTagColor
|
|
1836
|
-
svg.append("rect").attr("x", x).attr("y", y1).attr("width",
|
|
2069
|
+
const actBaseColor = actTagColor ?? palette.primary;
|
|
2070
|
+
svg.append("rect").attr("x", x).attr("y", y1).attr("width", bar.width).attr("height", height).attr("fill", themeBaseBg(palette, isDark));
|
|
1837
2071
|
const actFill = shapeFill(palette, actBaseColor, isDark, {
|
|
1838
2072
|
mode: fillMode
|
|
1839
2073
|
});
|
|
1840
|
-
const actRect = svg.append("rect").attr("x", x).attr("y", y1).attr("width",
|
|
2074
|
+
const actRect = svg.append("rect").attr("x", x).attr("y", y1).attr("width", bar.width).attr("height", height).attr("fill", actFill).attr("stroke", actBaseColor).attr("stroke-width", 1).attr("stroke-opacity", 0.5).attr("data-participant-id", act.participantId).attr("data-msg-lines", coveredLines.join(",")).attr("data-line-number", coveredLines[0] ?? "").attr("class", "activation");
|
|
1841
2075
|
if (tagKey && actTagValue) {
|
|
1842
2076
|
actRect.attr(`data-tag-${tagKey}`, actTagValue.toLowerCase());
|
|
1843
2077
|
}
|
|
1844
2078
|
});
|
|
1845
|
-
for (const
|
|
1846
|
-
const line = svg.append("line").attr("x1",
|
|
1847
|
-
if (
|
|
1848
|
-
line.attr("data-block-line", String(
|
|
2079
|
+
for (const divider of blockFrames.flatMap((frame) => frame.dividers)) {
|
|
2080
|
+
const line = svg.append("line").attr("x1", divider.x1).attr("y1", divider.y).attr("x2", divider.x2).attr("y2", divider.y).attr("stroke", palette.textMuted).attr("stroke-width", 1).attr("stroke-dasharray", HAIRLINE_DASH).attr("class", "block-divider");
|
|
2081
|
+
if (divider.lineNumber !== void 0)
|
|
2082
|
+
line.attr("data-block-line", String(divider.lineNumber));
|
|
1849
2083
|
}
|
|
1850
|
-
|
|
2084
|
+
const blockLabels = blockFrames.flatMap((frame) => [
|
|
2085
|
+
{ ...frame.label, lineNumber: frame.lineNumber },
|
|
2086
|
+
...frame.dividers.map((d) => ({ ...d.label, lineNumber: d.lineNumber }))
|
|
2087
|
+
]);
|
|
2088
|
+
for (const lbl of blockLabels) {
|
|
1851
2089
|
const t = svg.append("text").attr("x", lbl.x).attr("y", lbl.y).attr("fill", palette.text).attr("font-size", 11).attr("class", "block-label").text(lbl.text);
|
|
1852
|
-
if (lbl.
|
|
1853
|
-
|
|
1854
|
-
if (lbl.blockLine !== void 0)
|
|
1855
|
-
t.attr("data-block-line", String(lbl.blockLine));
|
|
2090
|
+
if (lbl.lineNumber !== void 0)
|
|
2091
|
+
t.attr("data-block-line", String(lbl.lineNumber));
|
|
1856
2092
|
}
|
|
1857
|
-
const
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
maxDepth = act.depth;
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
return maxDepth;
|
|
1865
|
-
};
|
|
1866
|
-
const arrowEdgeX = (pid, stepIdx, side) => {
|
|
1867
|
-
const px = participantX.get(pid);
|
|
1868
|
-
const depth = activeDepthAt(pid, stepIdx);
|
|
1869
|
-
if (depth < 0) return px;
|
|
1870
|
-
const offset = depth * ACTIVATION_NEST_OFFSET;
|
|
1871
|
-
return side === "right" ? px + sActivationWidth / 2 + offset : px - sActivationWidth / 2 + offset;
|
|
1872
|
-
};
|
|
1873
|
-
for (const region of sectionRegions) {
|
|
1874
|
-
const sec = region.section;
|
|
1875
|
-
const secY = sectionYPositions.get(sec.lineNumber);
|
|
1876
|
-
if (secY === void 0) continue;
|
|
1877
|
-
const isCollapsed = isSectionCollapsed(sec);
|
|
2093
|
+
for (const band of sectionBands) {
|
|
2094
|
+
const sec = band.region.section;
|
|
2095
|
+
const secY = band.y;
|
|
2096
|
+
const isCollapsed = band.collapsed;
|
|
1878
2097
|
const lineColor = palette.textMuted;
|
|
1879
2098
|
const sectionG = svg.append("g").attr("data-section-toggle", "").attr("data-line-number", String(sec.lineNumber)).attr("data-section", "").attr("tabindex", "0").attr("role", "button").attr("aria-expanded", String(!isCollapsed));
|
|
1880
|
-
const BAND_HEIGHT =
|
|
1881
|
-
const bandX = sectionLineX1 - 10;
|
|
1882
|
-
const bandWidth = sectionLineX2 - sectionLineX1 + 20;
|
|
2099
|
+
const BAND_HEIGHT = band.height;
|
|
1883
2100
|
const bandFill = isCollapsed ? legendChromeColors(palette, isDark).groupBg : lineColor;
|
|
1884
2101
|
const bandOpacity = isCollapsed ? 1 : isDark ? 0.1 : 0.08;
|
|
1885
|
-
sectionG.append("rect").attr("x",
|
|
1886
|
-
const labelText =
|
|
1887
|
-
const labelWidth = measureText(labelText, 11, { bold: true });
|
|
1888
|
-
const labelX = sectionLabelX;
|
|
1889
|
-
const labelBaseline = sectionLabelBaselineFor(sec, secY);
|
|
2102
|
+
sectionG.append("rect").attr("x", band.x).attr("y", secY - BAND_HEIGHT / 2).attr("width", band.width).attr("height", BAND_HEIGHT).attr("fill", bandFill).attr("opacity", bandOpacity).attr("rx", 2).attr("pointer-events", "none").attr("class", "section-divider");
|
|
2103
|
+
const { labelText, labelWidth, labelX, labelBaseline } = band;
|
|
1890
2104
|
const labelHitW = Math.max(80, labelWidth + 24);
|
|
1891
2105
|
sectionG.append("rect").attr("x", labelX - labelHitW / 2).attr("y", secY - BAND_HEIGHT / 2).attr("width", labelHitW).attr("height", BAND_HEIGHT).attr("fill", "transparent").attr("class", "section-label-hit");
|
|
1892
2106
|
sectionG.append("text").attr("x", labelX).attr("y", labelBaseline).attr("text-anchor", "middle").attr("fill", lineColor).attr("font-size", 11).attr("font-weight", "bold").attr("class", "section-label").text(labelText);
|
|
1893
2107
|
if (!isCollapsed) continue;
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
const
|
|
1899
|
-
|
|
1900
|
-
if (involvedXs.length > 1) {
|
|
1901
|
-
sectionG.append("line").attr("x1", Math.min(...involvedXs)).attr("x2", Math.max(...involvedXs)).attr("y1", markY).attr("y2", markY).attr("stroke", lineColor).attr("stroke-width", 1).attr("stroke-dasharray", HAIRLINE_DASH).attr("opacity", 0.5).attr("pointer-events", "none").attr("class", "section-reach");
|
|
1902
|
-
}
|
|
1903
|
-
for (const participant of participants) {
|
|
1904
|
-
const markX = participantX.get(participant.id);
|
|
1905
|
-
if (markX === void 0) continue;
|
|
1906
|
-
const part = participation.get(participant.id);
|
|
1907
|
-
const mark = sectionG.append("circle").attr("cx", markX).attr("cy", markY).attr("pointer-events", "none").attr("data-participant-id", participant.id);
|
|
2108
|
+
const markY = band.markY;
|
|
2109
|
+
if (band.reach) {
|
|
2110
|
+
sectionG.append("line").attr("x1", band.reach.x1).attr("x2", band.reach.x2).attr("y1", markY).attr("y2", markY).attr("stroke", lineColor).attr("stroke-width", 1).attr("stroke-dasharray", HAIRLINE_DASH).attr("opacity", 0.5).attr("pointer-events", "none").attr("class", "section-reach");
|
|
2111
|
+
}
|
|
2112
|
+
for (const { participantId, x: markX, part, radius } of band.marks) {
|
|
2113
|
+
const mark = sectionG.append("circle").attr("cx", markX).attr("cy", markY).attr("pointer-events", "none").attr("data-participant-id", participantId);
|
|
1908
2114
|
if (!part) {
|
|
1909
|
-
mark.attr("r",
|
|
2115
|
+
mark.attr("r", radius).attr("fill", "none").attr("stroke", lineColor).attr("stroke-width", 1).attr("opacity", 0.5).attr("class", "section-mark section-mark-absent");
|
|
1910
2116
|
continue;
|
|
1911
2117
|
}
|
|
1912
|
-
const markColor = participantTagColor(
|
|
1913
|
-
|
|
1914
|
-
sectionG.append("circle").attr("cx", markX).attr("cy", markY).attr("r", Math.max(radius, SECTION_MARK_HIT_RADIUS)).attr("fill", "transparent").attr("class", "section-mark-hit").attr("data-participant-id", participant.id).attr("data-section-mark-line", String(part.firstLine)).attr("cursor", "pointer");
|
|
2118
|
+
const markColor = participantTagColor(participantId) ?? palette.text;
|
|
2119
|
+
sectionG.append("circle").attr("cx", markX).attr("cy", markY).attr("r", Math.max(radius, SECTION_MARK_HIT_RADIUS)).attr("fill", "transparent").attr("class", "section-mark-hit").attr("data-participant-id", participantId).attr("data-section-mark-line", String(part.firstLine)).attr("cursor", "pointer");
|
|
1915
2120
|
if (part.sends === 0) {
|
|
1916
2121
|
mark.attr("r", radius).attr("fill", bandFill).attr("stroke", markColor).attr("stroke-width", 1.6).attr("class", "section-mark section-mark-receives");
|
|
1917
2122
|
} else {
|
|
1918
2123
|
mark.attr("r", radius).attr("fill", markColor).attr("class", "section-mark section-mark-sends");
|
|
1919
2124
|
}
|
|
1920
2125
|
}
|
|
1921
|
-
const
|
|
2126
|
+
const involved = new Set(
|
|
2127
|
+
band.marks.filter((m) => m.part).map((m) => m.participantId)
|
|
2128
|
+
);
|
|
2129
|
+
const involvedLabels = participants.filter((p) => involved.has(p.id)).map((p) => p.label);
|
|
1922
2130
|
if (involvedLabels.length > 0) {
|
|
1923
2131
|
sectionG.attr("aria-label", `${labelText}, ${involvedLabels.join(", ")}`);
|
|
1924
2132
|
}
|
|
1925
2133
|
}
|
|
1926
2134
|
renderSteps.forEach((step, i) => {
|
|
1927
|
-
const
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
const y = stepY(i);
|
|
2135
|
+
const arrow = messageArrows[i];
|
|
2136
|
+
if (!arrow) return;
|
|
2137
|
+
const { y, label } = arrow;
|
|
1931
2138
|
const HIT_H = 20;
|
|
1932
2139
|
const msg = messages[step.messageIndex];
|
|
1933
2140
|
const msgTagValue = msg ? tagMap?.messages.get(msg.lineNumber) : void 0;
|
|
1934
2141
|
const msgTagColor = getTagColor(msgTagValue);
|
|
1935
2142
|
if (step.type === "call") {
|
|
1936
|
-
const arrowColor = msgTagColor
|
|
1937
|
-
if (
|
|
1938
|
-
const x
|
|
1939
|
-
const loopX = x + sSelfCallWidth;
|
|
2143
|
+
const arrowColor = msgTagColor ?? palette.text;
|
|
2144
|
+
if (arrow.kind === "self") {
|
|
2145
|
+
const { x, loopX, returnY } = arrow;
|
|
1940
2146
|
const hitX = x;
|
|
1941
2147
|
svg.append("rect").attr("x", hitX).attr("y", y - 5).attr("width", sSelfCallWidth).attr("height", sSelfCallHeight + 10).attr("fill", "transparent").attr("class", "message-hit-area").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1942
|
-
const selfCallEl = svg.append("path").attr("d", `M ${x} ${y} H ${loopX} V ${
|
|
2148
|
+
const selfCallEl = svg.append("path").attr("d", `M ${x} ${y} H ${loopX} V ${returnY} H ${x}`).attr("fill", "none").attr("stroke", arrowColor).attr("stroke-width", 1.2).attr("marker-end", coloredMarker("call", msgTagColor)).attr("class", "message-arrow self-call").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i)).attr("data-from", step.from).attr("data-to", step.to);
|
|
1943
2149
|
if (tagKey && msgTagValue) {
|
|
1944
2150
|
selfCallEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1945
2151
|
}
|
|
1946
|
-
const displayLabel =
|
|
2152
|
+
const displayLabel = stepLabels[i];
|
|
1947
2153
|
if (displayLabel) {
|
|
1948
|
-
const labelEl = svg.append("text").attr("x",
|
|
2154
|
+
const labelEl = svg.append("text").attr("x", label.x).attr("y", label.y).attr("text-anchor", "start").attr("fill", arrowColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", 12).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1949
2155
|
if (tagKey && msgTagValue) {
|
|
1950
2156
|
labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1951
2157
|
}
|
|
1952
2158
|
labelEl.text(displayLabel);
|
|
1953
2159
|
}
|
|
1954
2160
|
} else {
|
|
1955
|
-
const
|
|
1956
|
-
const x1 = arrowEdgeX(step.from, i, goingRight ? "right" : "left");
|
|
1957
|
-
const x2 = arrowEdgeX(step.to, i, goingRight ? "left" : "right");
|
|
2161
|
+
const { x1, x2 } = arrow;
|
|
1958
2162
|
svg.append("rect").attr("x", Math.min(x1, x2)).attr("y", y - HIT_H / 2).attr("width", Math.abs(x2 - x1)).attr("height", HIT_H).attr("fill", "transparent").attr("class", "message-hit-area").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1959
2163
|
const markerRef = step.async ? coloredMarker("async", msgTagColor) : coloredMarker("call", msgTagColor);
|
|
1960
2164
|
const arrowEl = svg.append("line").attr("x1", x1).attr("y1", y).attr("x2", x2).attr("y2", y).attr("stroke", arrowColor).attr("stroke-width", 1.2).attr("marker-end", markerRef).attr("class", "message-arrow").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i)).attr("data-from", step.from).attr("data-to", step.to);
|
|
1961
2165
|
if (tagKey && msgTagValue) {
|
|
1962
2166
|
arrowEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1963
2167
|
}
|
|
1964
|
-
const displayLabel =
|
|
2168
|
+
const displayLabel = stepLabels[i];
|
|
1965
2169
|
if (displayLabel) {
|
|
1966
|
-
const
|
|
1967
|
-
const labelEl = svg.append("text").attr("x", midX).attr("y", y - MSG_LABEL_OFFSET).attr("text-anchor", "middle").attr("fill", arrowColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", MSG_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
2170
|
+
const labelEl = svg.append("text").attr("x", label.x).attr("y", label.y).attr("text-anchor", "middle").attr("fill", arrowColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", MSG_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1968
2171
|
if (tagKey && msgTagValue) {
|
|
1969
2172
|
labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1970
2173
|
}
|
|
1971
2174
|
labelEl.text(displayLabel);
|
|
1972
2175
|
}
|
|
1973
2176
|
}
|
|
1974
|
-
} else {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
}
|
|
1978
|
-
const goingRight = fromX < toX;
|
|
1979
|
-
const x1 = arrowEdgeX(step.from, i, goingRight ? "right" : "left");
|
|
1980
|
-
const x2 = arrowEdgeX(step.to, i, goingRight ? "left" : "right");
|
|
1981
|
-
const returnColor = msgTagColor || palette.textMuted;
|
|
2177
|
+
} else if (arrow.kind === "return") {
|
|
2178
|
+
const { x1, x2 } = arrow;
|
|
2179
|
+
const returnColor = msgTagColor ?? palette.textMuted;
|
|
1982
2180
|
svg.append("rect").attr("x", Math.min(x1, x2)).attr("y", y - HIT_H / 2).attr("width", Math.abs(x2 - x1)).attr("height", HIT_H).attr("fill", "transparent").attr("class", "message-hit-area").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1983
2181
|
const returnEl = svg.append("line").attr("x1", x1).attr("y1", y).attr("x2", x2).attr("y2", y).attr("stroke", returnColor).attr("stroke-width", 1).attr("stroke-dasharray", EDGE_DASH).attr("marker-end", coloredMarker("return", msgTagColor)).attr("class", "return-arrow").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i)).attr("data-from", step.from).attr("data-to", step.to);
|
|
1984
2182
|
if (tagKey && msgTagValue) {
|
|
1985
2183
|
returnEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1986
2184
|
}
|
|
1987
|
-
const displayLabel =
|
|
2185
|
+
const displayLabel = stepLabels[i];
|
|
1988
2186
|
if (displayLabel) {
|
|
1989
|
-
const
|
|
1990
|
-
const labelEl = svg.append("text").attr("x", midX).attr("y", y - RETURN_LABEL_OFFSET).attr("text-anchor", "middle").attr("fill", returnColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", RETURN_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
2187
|
+
const labelEl = svg.append("text").attr("x", label.x).attr("y", label.y).attr("text-anchor", "middle").attr("fill", returnColor).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("font-size", RETURN_LABEL_FONT_SIZE).attr("class", "message-label").attr("data-line-number", String(msg.lineNumber)).attr("data-msg-index", String(step.messageIndex)).attr("data-step-index", String(i));
|
|
1991
2188
|
if (tagKey && msgTagValue) {
|
|
1992
2189
|
labelEl.attr(`data-tag-${tagKey}`, msgTagValue.toLowerCase());
|
|
1993
2190
|
}
|
|
@@ -1999,30 +2196,9 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
1999
2196
|
const renderNoteElements = (els) => {
|
|
2000
2197
|
for (const el of els) {
|
|
2001
2198
|
if (isSequenceNote(el)) {
|
|
2002
|
-
const
|
|
2003
|
-
if (
|
|
2004
|
-
const noteTopY =
|
|
2005
|
-
if (noteTopY === void 0) continue;
|
|
2006
|
-
const position = effectiveNotePosition(el);
|
|
2007
|
-
const isRight = position === "right";
|
|
2008
|
-
const afterSelfCall = isNoteAfterSelfCall(el);
|
|
2009
|
-
const maxW = noteEffectiveMaxW(
|
|
2010
|
-
el.participantId,
|
|
2011
|
-
position,
|
|
2012
|
-
afterSelfCall
|
|
2013
|
-
);
|
|
2014
|
-
const textWidth = noteTextWidth(maxW);
|
|
2015
|
-
const wrappedLines = wrapTextLines(el.text, textWidth, sNoteFontSize);
|
|
2016
|
-
const noteH = wrappedLines.length * sNoteLineH + sNotePadV * 2;
|
|
2017
|
-
const maxLineW = Math.max(
|
|
2018
|
-
...wrappedLines.map((l) => measureText(l.text, sNoteFontSize))
|
|
2019
|
-
);
|
|
2020
|
-
const noteW = Math.min(
|
|
2021
|
-
maxW,
|
|
2022
|
-
Math.max(80, maxLineW + sNotePadH * 2 + sNoteFold)
|
|
2023
|
-
);
|
|
2024
|
-
const rightOffset = afterSelfCall && isRight ? sActivationWidth / 2 + sSelfCallWidth + sNoteGap : sActivationWidth + sNoteGap;
|
|
2025
|
-
const noteX = isRight ? px + rightOffset : px - sActivationWidth - sNoteGap - noteW;
|
|
2199
|
+
const box = noteBoxes.get(el);
|
|
2200
|
+
if (box === void 0) continue;
|
|
2201
|
+
const { x: noteX, y: noteTopY, width: noteW, height: noteH } = box;
|
|
2026
2202
|
const noteG = svg.append("g").attr("class", "note").attr("data-note-toggle", "").attr("data-line-number", String(el.lineNumber)).attr("data-line-end", String(el.endLineNumber));
|
|
2027
2203
|
noteG.append("path").attr(
|
|
2028
2204
|
"d",
|
|
@@ -2043,16 +2219,13 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
2043
2219
|
`L ${noteX + noteW} ${noteTopY + sNoteFold}`
|
|
2044
2220
|
].join(" ")
|
|
2045
2221
|
).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 0.75).attr("class", "note-fold");
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
const indent = line.kind === "plain" ? 0 : BULLET_BODY_INDENT;
|
|
2050
|
-
if (line.kind === "bullet-first") {
|
|
2051
|
-
noteG.append("text").attr("x", noteX + sNotePadH).attr("y", textY).attr("fill", palette.text).attr("font-size", sNoteFontSize).text("\u2022");
|
|
2222
|
+
for (const line of box.lines) {
|
|
2223
|
+
if (line.bulletX !== void 0) {
|
|
2224
|
+
noteG.append("text").attr("x", line.bulletX).attr("y", line.y).attr("fill", palette.text).attr("font-size", sNoteFontSize).text("\u2022");
|
|
2052
2225
|
}
|
|
2053
|
-
const textEl = noteG.append("text").attr("x",
|
|
2226
|
+
const textEl = noteG.append("text").attr("x", line.x).attr("y", line.y).attr("fill", palette.text).attr("font-size", sNoteFontSize).attr("class", "note-text");
|
|
2054
2227
|
renderInlineText(textEl, line.text, palette, sNoteFontSize);
|
|
2055
|
-
}
|
|
2228
|
+
}
|
|
2056
2229
|
} else if (isSequenceBlock(el)) {
|
|
2057
2230
|
renderNoteElements(el.children);
|
|
2058
2231
|
if (el.elseIfBranches) {
|
|
@@ -2183,6 +2356,7 @@ export {
|
|
|
2183
2356
|
computeActivations,
|
|
2184
2357
|
applyPositionOverrides,
|
|
2185
2358
|
applyGroupOrdering,
|
|
2359
|
+
layoutSequence,
|
|
2186
2360
|
renderSequenceDiagram,
|
|
2187
2361
|
buildNoteMessageMap
|
|
2188
2362
|
};
|