@diagrammo/dgmo 0.5.0 → 0.5.2
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/cli.cjs +146 -146
- package/dist/index.cjs +235 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +235 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/d3.ts +308 -90
- package/src/sharing.ts +8 -0
package/dist/index.d.cts
CHANGED
|
@@ -397,7 +397,7 @@ interface ArcNodeGroup {
|
|
|
397
397
|
color: string | null;
|
|
398
398
|
lineNumber: number;
|
|
399
399
|
}
|
|
400
|
-
type TimelineSort = 'time' | 'group';
|
|
400
|
+
type TimelineSort = 'time' | 'group' | 'tag';
|
|
401
401
|
interface TimelineEvent {
|
|
402
402
|
date: string;
|
|
403
403
|
endDate: string | null;
|
|
@@ -477,6 +477,7 @@ interface ParsedD3 {
|
|
|
477
477
|
timelineMarkers: TimelineMarker[];
|
|
478
478
|
timelineTagGroups: TagGroup[];
|
|
479
479
|
timelineSort: TimelineSort;
|
|
480
|
+
timelineDefaultSwimlaneTG?: string;
|
|
480
481
|
timelineScale: boolean;
|
|
481
482
|
timelineSwimlanes: boolean;
|
|
482
483
|
vennSets: VennSet[];
|
|
@@ -545,7 +546,7 @@ declare function computeTimeTicks(domainMin: number, domainMax: number, scale: d
|
|
|
545
546
|
* Renders a timeline chart into the given container using D3.
|
|
546
547
|
* Supports horizontal (default) and vertical orientation.
|
|
547
548
|
*/
|
|
548
|
-
declare function renderTimeline(container: HTMLDivElement, parsed: ParsedD3, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions, activeTagGroup?: string | null): void;
|
|
549
|
+
declare function renderTimeline(container: HTMLDivElement, parsed: ParsedD3, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions, activeTagGroup?: string | null, swimlaneTagGroup?: string | null, onTagStateChange?: (activeTagGroup: string | null, swimlaneTagGroup: string | null) => void, viewMode?: boolean): void;
|
|
549
550
|
/**
|
|
550
551
|
* Renders a word cloud into the given container using d3-cloud.
|
|
551
552
|
*/
|
|
@@ -564,6 +565,7 @@ declare function renderD3ForExport(content: string, theme: 'light' | 'dark' | 't
|
|
|
564
565
|
collapsedNodes?: Set<string>;
|
|
565
566
|
activeTagGroup?: string | null;
|
|
566
567
|
hiddenAttributes?: Set<string>;
|
|
568
|
+
swimlaneTagGroup?: string | null;
|
|
567
569
|
}, options?: {
|
|
568
570
|
branding?: boolean;
|
|
569
571
|
c4Level?: 'context' | 'containers' | 'components' | 'deployment';
|
|
@@ -1974,6 +1976,7 @@ declare const seriesColors: string[];
|
|
|
1974
1976
|
interface DiagramViewState {
|
|
1975
1977
|
activeTagGroup?: string;
|
|
1976
1978
|
collapsedGroups?: string[];
|
|
1979
|
+
swimlaneTagGroup?: string;
|
|
1977
1980
|
}
|
|
1978
1981
|
interface DecodedDiagramUrl {
|
|
1979
1982
|
dsl: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -397,7 +397,7 @@ interface ArcNodeGroup {
|
|
|
397
397
|
color: string | null;
|
|
398
398
|
lineNumber: number;
|
|
399
399
|
}
|
|
400
|
-
type TimelineSort = 'time' | 'group';
|
|
400
|
+
type TimelineSort = 'time' | 'group' | 'tag';
|
|
401
401
|
interface TimelineEvent {
|
|
402
402
|
date: string;
|
|
403
403
|
endDate: string | null;
|
|
@@ -477,6 +477,7 @@ interface ParsedD3 {
|
|
|
477
477
|
timelineMarkers: TimelineMarker[];
|
|
478
478
|
timelineTagGroups: TagGroup[];
|
|
479
479
|
timelineSort: TimelineSort;
|
|
480
|
+
timelineDefaultSwimlaneTG?: string;
|
|
480
481
|
timelineScale: boolean;
|
|
481
482
|
timelineSwimlanes: boolean;
|
|
482
483
|
vennSets: VennSet[];
|
|
@@ -545,7 +546,7 @@ declare function computeTimeTicks(domainMin: number, domainMax: number, scale: d
|
|
|
545
546
|
* Renders a timeline chart into the given container using D3.
|
|
546
547
|
* Supports horizontal (default) and vertical orientation.
|
|
547
548
|
*/
|
|
548
|
-
declare function renderTimeline(container: HTMLDivElement, parsed: ParsedD3, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions, activeTagGroup?: string | null): void;
|
|
549
|
+
declare function renderTimeline(container: HTMLDivElement, parsed: ParsedD3, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions, activeTagGroup?: string | null, swimlaneTagGroup?: string | null, onTagStateChange?: (activeTagGroup: string | null, swimlaneTagGroup: string | null) => void, viewMode?: boolean): void;
|
|
549
550
|
/**
|
|
550
551
|
* Renders a word cloud into the given container using d3-cloud.
|
|
551
552
|
*/
|
|
@@ -564,6 +565,7 @@ declare function renderD3ForExport(content: string, theme: 'light' | 'dark' | 't
|
|
|
564
565
|
collapsedNodes?: Set<string>;
|
|
565
566
|
activeTagGroup?: string | null;
|
|
566
567
|
hiddenAttributes?: Set<string>;
|
|
568
|
+
swimlaneTagGroup?: string | null;
|
|
567
569
|
}, options?: {
|
|
568
570
|
branding?: boolean;
|
|
569
571
|
c4Level?: 'context' | 'containers' | 'components' | 'deployment';
|
|
@@ -1974,6 +1976,7 @@ declare const seriesColors: string[];
|
|
|
1974
1976
|
interface DiagramViewState {
|
|
1975
1977
|
activeTagGroup?: string;
|
|
1976
1978
|
collapsedGroups?: string[];
|
|
1979
|
+
swimlaneTagGroup?: string;
|
|
1977
1980
|
}
|
|
1978
1981
|
interface DecodedDiagramUrl {
|
|
1979
1982
|
dsl: string;
|
package/dist/index.js
CHANGED
|
@@ -18478,9 +18478,18 @@ function parseD3(content, palette) {
|
|
|
18478
18478
|
continue;
|
|
18479
18479
|
}
|
|
18480
18480
|
if (key === "sort") {
|
|
18481
|
-
const v = line10.substring(colonIndex + 1).trim()
|
|
18482
|
-
|
|
18483
|
-
|
|
18481
|
+
const v = line10.substring(colonIndex + 1).trim();
|
|
18482
|
+
const vLower = v.toLowerCase();
|
|
18483
|
+
if (vLower === "time" || vLower === "group") {
|
|
18484
|
+
result.timelineSort = vLower;
|
|
18485
|
+
} else if (vLower === "tag" || vLower.startsWith("tag:")) {
|
|
18486
|
+
result.timelineSort = "tag";
|
|
18487
|
+
if (vLower.startsWith("tag:")) {
|
|
18488
|
+
const groupRef = v.substring(4).trim();
|
|
18489
|
+
if (groupRef) {
|
|
18490
|
+
result.timelineDefaultSwimlaneTG = groupRef;
|
|
18491
|
+
}
|
|
18492
|
+
}
|
|
18484
18493
|
}
|
|
18485
18494
|
continue;
|
|
18486
18495
|
}
|
|
@@ -18630,6 +18639,25 @@ function parseD3(content, palette) {
|
|
|
18630
18639
|
}
|
|
18631
18640
|
}
|
|
18632
18641
|
}
|
|
18642
|
+
if (result.timelineSort === "tag") {
|
|
18643
|
+
if (result.timelineTagGroups.length === 0) {
|
|
18644
|
+
warn(1, '"sort: tag" requires at least one tag group definition');
|
|
18645
|
+
result.timelineSort = "time";
|
|
18646
|
+
} else if (result.timelineDefaultSwimlaneTG) {
|
|
18647
|
+
const ref = result.timelineDefaultSwimlaneTG.toLowerCase();
|
|
18648
|
+
const match = result.timelineTagGroups.find(
|
|
18649
|
+
(g) => g.name.toLowerCase() === ref || g.alias?.toLowerCase() === ref
|
|
18650
|
+
);
|
|
18651
|
+
if (match) {
|
|
18652
|
+
result.timelineDefaultSwimlaneTG = match.name;
|
|
18653
|
+
} else {
|
|
18654
|
+
warn(1, `"sort: tag:${result.timelineDefaultSwimlaneTG}" \u2014 no tag group matches "${result.timelineDefaultSwimlaneTG}"`);
|
|
18655
|
+
result.timelineDefaultSwimlaneTG = result.timelineTagGroups[0].name;
|
|
18656
|
+
}
|
|
18657
|
+
} else {
|
|
18658
|
+
result.timelineDefaultSwimlaneTG = result.timelineTagGroups[0].name;
|
|
18659
|
+
}
|
|
18660
|
+
}
|
|
18633
18661
|
return result;
|
|
18634
18662
|
}
|
|
18635
18663
|
if (result.type === "venn") {
|
|
@@ -19388,7 +19416,7 @@ function buildEventTooltipHtml(ev) {
|
|
|
19388
19416
|
function buildEraTooltipHtml(era) {
|
|
19389
19417
|
return `<strong>${era.label}</strong><br>${formatDateLabel(era.startDate)} \u2192 ${formatDateLabel(era.endDate)}`;
|
|
19390
19418
|
}
|
|
19391
|
-
function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
19419
|
+
function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
|
|
19392
19420
|
d3Selection12.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
19393
19421
|
const {
|
|
19394
19422
|
timelineEvents,
|
|
@@ -19402,6 +19430,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19402
19430
|
orientation
|
|
19403
19431
|
} = parsed;
|
|
19404
19432
|
if (timelineEvents.length === 0) return;
|
|
19433
|
+
if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
|
|
19434
|
+
swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
|
|
19435
|
+
}
|
|
19405
19436
|
const tooltip = createTooltip(container, palette, isDark);
|
|
19406
19437
|
const width = exportDims?.width ?? container.clientWidth;
|
|
19407
19438
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -19415,9 +19446,47 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19415
19446
|
timelineGroups.forEach((grp, i) => {
|
|
19416
19447
|
groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
|
|
19417
19448
|
});
|
|
19449
|
+
let tagLanes = null;
|
|
19450
|
+
if (swimlaneTagGroup) {
|
|
19451
|
+
const tagKey = swimlaneTagGroup.toLowerCase();
|
|
19452
|
+
const tagGroup = parsed.timelineTagGroups.find(
|
|
19453
|
+
(g) => g.name.toLowerCase() === tagKey
|
|
19454
|
+
);
|
|
19455
|
+
if (tagGroup) {
|
|
19456
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
19457
|
+
const otherEvents = [];
|
|
19458
|
+
for (const ev of timelineEvents) {
|
|
19459
|
+
const val = ev.metadata[tagKey];
|
|
19460
|
+
if (val) {
|
|
19461
|
+
const list = buckets.get(val) ?? [];
|
|
19462
|
+
list.push(ev);
|
|
19463
|
+
buckets.set(val, list);
|
|
19464
|
+
} else {
|
|
19465
|
+
otherEvents.push(ev);
|
|
19466
|
+
}
|
|
19467
|
+
}
|
|
19468
|
+
const laneEntries = [...buckets.entries()].sort((a, b) => {
|
|
19469
|
+
const aMin = Math.min(
|
|
19470
|
+
...a[1].map((e) => parseTimelineDate(e.date))
|
|
19471
|
+
);
|
|
19472
|
+
const bMin = Math.min(
|
|
19473
|
+
...b[1].map((e) => parseTimelineDate(e.date))
|
|
19474
|
+
);
|
|
19475
|
+
return aMin - bMin;
|
|
19476
|
+
});
|
|
19477
|
+
tagLanes = laneEntries.map(([name, events]) => ({ name, events }));
|
|
19478
|
+
if (otherEvents.length > 0) {
|
|
19479
|
+
tagLanes.push({ name: "(Other)", events: otherEvents });
|
|
19480
|
+
}
|
|
19481
|
+
for (const entry of tagGroup.entries) {
|
|
19482
|
+
groupColorMap.set(entry.value, entry.color);
|
|
19483
|
+
}
|
|
19484
|
+
}
|
|
19485
|
+
}
|
|
19486
|
+
const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
|
|
19418
19487
|
function eventColor(ev) {
|
|
19419
|
-
if (
|
|
19420
|
-
const tagColor = resolveTagColor(ev.metadata, parsed.timelineTagGroups,
|
|
19488
|
+
if (effectiveColorTG) {
|
|
19489
|
+
const tagColor = resolveTagColor(ev.metadata, parsed.timelineTagGroups, effectiveColorTG);
|
|
19421
19490
|
if (tagColor) return tagColor;
|
|
19422
19491
|
}
|
|
19423
19492
|
if (ev.group && groupColorMap.has(ev.group)) {
|
|
@@ -19521,12 +19590,28 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19521
19590
|
}
|
|
19522
19591
|
const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
|
|
19523
19592
|
if (isVertical) {
|
|
19524
|
-
|
|
19525
|
-
|
|
19526
|
-
|
|
19527
|
-
|
|
19528
|
-
)
|
|
19529
|
-
|
|
19593
|
+
const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
|
|
19594
|
+
if (useGroupedVertical) {
|
|
19595
|
+
let laneNames;
|
|
19596
|
+
let laneEventsByName;
|
|
19597
|
+
if (tagLanes) {
|
|
19598
|
+
laneNames = tagLanes.map((l) => l.name);
|
|
19599
|
+
laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
|
|
19600
|
+
} else {
|
|
19601
|
+
const groupNames = timelineGroups.map((gr) => gr.name);
|
|
19602
|
+
const ungroupedEvents = timelineEvents.filter(
|
|
19603
|
+
(ev) => ev.group === null || !groupNames.includes(ev.group)
|
|
19604
|
+
);
|
|
19605
|
+
laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
|
|
19606
|
+
laneEventsByName = new Map(
|
|
19607
|
+
laneNames.map((name) => [
|
|
19608
|
+
name,
|
|
19609
|
+
timelineEvents.filter(
|
|
19610
|
+
(ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
|
|
19611
|
+
)
|
|
19612
|
+
])
|
|
19613
|
+
);
|
|
19614
|
+
}
|
|
19530
19615
|
const laneCount = laneNames.length;
|
|
19531
19616
|
const scaleMargin = timelineScale ? 40 : 0;
|
|
19532
19617
|
const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
|
|
@@ -19581,6 +19666,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19581
19666
|
formatDateLabel(latestEndDateStr)
|
|
19582
19667
|
);
|
|
19583
19668
|
}
|
|
19669
|
+
if (timelineSwimlanes || tagLanes) {
|
|
19670
|
+
laneNames.forEach((laneName, laneIdx) => {
|
|
19671
|
+
const laneX = laneIdx * laneWidth;
|
|
19672
|
+
const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
|
|
19673
|
+
g.append("rect").attr("class", "tl-swimlane").attr("data-group", laneName).attr("x", laneX).attr("y", 0).attr("width", laneWidth).attr("height", innerHeight).attr("fill", fillColor).attr("opacity", 0.06);
|
|
19674
|
+
});
|
|
19675
|
+
}
|
|
19584
19676
|
laneNames.forEach((laneName, laneIdx) => {
|
|
19585
19677
|
const laneX = laneIdx * laneWidth;
|
|
19586
19678
|
const laneColor = groupColorMap.get(laneName) ?? textColor;
|
|
@@ -19588,9 +19680,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19588
19680
|
const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", laneName).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, laneName)).on("mouseleave", () => fadeReset(g));
|
|
19589
19681
|
headerG.append("text").attr("x", laneCenter).attr("y", -15).attr("text-anchor", "middle").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(laneName);
|
|
19590
19682
|
g.append("line").attr("x1", laneCenter).attr("y1", 0).attr("x2", laneCenter).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
|
|
19591
|
-
const laneEvents =
|
|
19592
|
-
(ev) => laneName === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === laneName
|
|
19593
|
-
);
|
|
19683
|
+
const laneEvents = laneEventsByName.get(laneName) ?? [];
|
|
19594
19684
|
for (const ev of laneEvents) {
|
|
19595
19685
|
const y = yScale(parseTimelineDate(ev.date));
|
|
19596
19686
|
const evG = g.append("g").attr("class", "tl-event").attr("data-group", laneName).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
|
|
@@ -19608,10 +19698,11 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19608
19698
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19609
19699
|
});
|
|
19610
19700
|
setTagAttrs(evG, ev);
|
|
19701
|
+
const evColor = eventColor(ev);
|
|
19611
19702
|
if (ev.endDate) {
|
|
19612
19703
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
19613
19704
|
const rectH = Math.max(y2 - y, 4);
|
|
19614
|
-
let fill2 =
|
|
19705
|
+
let fill2 = evColor;
|
|
19615
19706
|
if (ev.uncertain) {
|
|
19616
19707
|
const gradientId = `uncertain-vg-${ev.lineNumber}`;
|
|
19617
19708
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -19625,7 +19716,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19625
19716
|
evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
|
|
19626
19717
|
evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
|
|
19627
19718
|
} else {
|
|
19628
|
-
evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill",
|
|
19719
|
+
evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", evColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
|
|
19629
19720
|
evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
|
|
19630
19721
|
}
|
|
19631
19722
|
}
|
|
@@ -19748,18 +19839,24 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19748
19839
|
}
|
|
19749
19840
|
const BAR_H = 22;
|
|
19750
19841
|
const GROUP_GAP = 12;
|
|
19751
|
-
|
|
19752
|
-
|
|
19753
|
-
|
|
19754
|
-
|
|
19755
|
-
|
|
19756
|
-
|
|
19757
|
-
|
|
19758
|
-
|
|
19759
|
-
|
|
19760
|
-
|
|
19761
|
-
)
|
|
19762
|
-
|
|
19842
|
+
const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
|
|
19843
|
+
if (useGroupedHorizontal) {
|
|
19844
|
+
let lanes;
|
|
19845
|
+
if (tagLanes) {
|
|
19846
|
+
lanes = tagLanes;
|
|
19847
|
+
} else {
|
|
19848
|
+
const groupNames = timelineGroups.map((gr) => gr.name);
|
|
19849
|
+
const ungroupedEvents = timelineEvents.filter(
|
|
19850
|
+
(ev) => ev.group === null || !groupNames.includes(ev.group)
|
|
19851
|
+
);
|
|
19852
|
+
const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
|
|
19853
|
+
lanes = laneNames.map((name) => ({
|
|
19854
|
+
name,
|
|
19855
|
+
events: timelineEvents.filter(
|
|
19856
|
+
(ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
|
|
19857
|
+
)
|
|
19858
|
+
}));
|
|
19859
|
+
}
|
|
19763
19860
|
const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
|
|
19764
19861
|
const scaleMargin = timelineScale ? 24 : 0;
|
|
19765
19862
|
const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
|
|
@@ -19819,7 +19916,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19819
19916
|
);
|
|
19820
19917
|
}
|
|
19821
19918
|
let curY = markerMargin;
|
|
19822
|
-
if (timelineSwimlanes) {
|
|
19919
|
+
if (timelineSwimlanes || tagLanes) {
|
|
19823
19920
|
let swimY = markerMargin;
|
|
19824
19921
|
lanes.forEach((lane, idx) => {
|
|
19825
19922
|
const laneSpan = lane.events.length * rowH;
|
|
@@ -19871,12 +19968,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19871
19968
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19872
19969
|
});
|
|
19873
19970
|
setTagAttrs(evG, ev);
|
|
19971
|
+
const evColor = eventColor(ev);
|
|
19874
19972
|
if (ev.endDate) {
|
|
19875
19973
|
const x2 = xScale(parseTimelineDate(ev.endDate));
|
|
19876
19974
|
const rectW = Math.max(x2 - x, 4);
|
|
19877
19975
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
19878
19976
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
19879
|
-
let fill2 =
|
|
19977
|
+
let fill2 = evColor;
|
|
19880
19978
|
if (ev.uncertain) {
|
|
19881
19979
|
const gradientId = `uncertain-${ev.lineNumber}`;
|
|
19882
19980
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -19884,7 +19982,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19884
19982
|
{ offset: "0%", opacity: 1 },
|
|
19885
19983
|
{ offset: "80%", opacity: 1 },
|
|
19886
19984
|
{ offset: "100%", opacity: 0 }
|
|
19887
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color",
|
|
19985
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
|
|
19888
19986
|
fill2 = `url(#${gradientId})`;
|
|
19889
19987
|
}
|
|
19890
19988
|
evG.append("rect").attr("x", x).attr("y", y - BAR_H / 2).attr("width", rectW).attr("height", BAR_H).attr("rx", 4).attr("fill", fill2);
|
|
@@ -19901,7 +19999,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19901
19999
|
const wouldFlipLeft = x > innerWidth * 0.6;
|
|
19902
20000
|
const labelFitsLeft = x - 10 - estLabelWidth > 0;
|
|
19903
20001
|
const flipLeft = wouldFlipLeft && labelFitsLeft;
|
|
19904
|
-
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill",
|
|
20002
|
+
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", evColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
|
|
19905
20003
|
evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
|
|
19906
20004
|
}
|
|
19907
20005
|
});
|
|
@@ -20056,26 +20154,62 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20056
20154
|
const LG_ENTRY_DOT_GAP = 4;
|
|
20057
20155
|
const LG_ENTRY_TRAIL = 8;
|
|
20058
20156
|
const LG_GROUP_GAP = 12;
|
|
20157
|
+
const LG_ICON_W = 20;
|
|
20059
20158
|
const mainSvg = d3Selection12.select(container).select("svg");
|
|
20060
20159
|
const mainG = mainSvg.select("g");
|
|
20061
20160
|
if (!mainSvg.empty() && !mainG.empty()) {
|
|
20062
|
-
let
|
|
20161
|
+
let drawSwimlaneIcon2 = function(parent, x, y, isSwimActive) {
|
|
20162
|
+
const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
|
|
20163
|
+
const barColor = isSwimActive ? palette.primary : palette.textMuted;
|
|
20164
|
+
const barOpacity = isSwimActive ? 1 : 0.35;
|
|
20165
|
+
const bars = [
|
|
20166
|
+
{ y: 0, w: 8 },
|
|
20167
|
+
{ y: 4, w: 12 },
|
|
20168
|
+
{ y: 8, w: 6 }
|
|
20169
|
+
];
|
|
20170
|
+
for (const bar of bars) {
|
|
20171
|
+
iconG.append("rect").attr("x", 0).attr("y", bar.y).attr("width", bar.w).attr("height", 2).attr("rx", 1).attr("fill", barColor).attr("opacity", barOpacity);
|
|
20172
|
+
}
|
|
20173
|
+
return iconG;
|
|
20174
|
+
}, relayout2 = function() {
|
|
20175
|
+
renderTimeline(
|
|
20176
|
+
container,
|
|
20177
|
+
parsed,
|
|
20178
|
+
palette,
|
|
20179
|
+
isDark,
|
|
20180
|
+
onClickItem,
|
|
20181
|
+
exportDims,
|
|
20182
|
+
currentActiveGroup,
|
|
20183
|
+
currentSwimlaneGroup,
|
|
20184
|
+
onTagStateChange,
|
|
20185
|
+
viewMode
|
|
20186
|
+
);
|
|
20187
|
+
}, drawLegend2 = function() {
|
|
20063
20188
|
mainSvg.selectAll(".tl-tag-legend-group").remove();
|
|
20064
|
-
const
|
|
20189
|
+
const visibleGroups = viewMode ? legendGroups.filter(
|
|
20190
|
+
(lg) => currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase()
|
|
20191
|
+
) : legendGroups;
|
|
20192
|
+
if (visibleGroups.length === 0) return;
|
|
20193
|
+
const totalW = visibleGroups.reduce((s, lg) => {
|
|
20065
20194
|
const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
|
|
20066
20195
|
return s + (isActive ? lg.expandedWidth : lg.minifiedWidth);
|
|
20067
|
-
}, 0) + (
|
|
20196
|
+
}, 0) + (visibleGroups.length - 1) * LG_GROUP_GAP;
|
|
20068
20197
|
let cx = (width - totalW) / 2;
|
|
20069
|
-
for (const lg of
|
|
20070
|
-
const
|
|
20198
|
+
for (const lg of visibleGroups) {
|
|
20199
|
+
const groupKey = lg.group.name.toLowerCase();
|
|
20200
|
+
const isActive = currentActiveGroup != null && currentActiveGroup.toLowerCase() === groupKey;
|
|
20201
|
+
const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
|
|
20071
20202
|
const pillLabel = lg.group.name;
|
|
20072
20203
|
const pillWidth = pillLabel.length * LG_PILL_FONT_W + LG_PILL_PAD;
|
|
20073
|
-
const gEl = mainSvg.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group",
|
|
20074
|
-
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
|
|
20204
|
+
const gEl = mainSvg.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group", groupKey).attr("data-tag-group", groupKey).attr("data-legend-entry", "__group__");
|
|
20205
|
+
if (!viewMode) {
|
|
20206
|
+
gEl.style("cursor", "pointer").on("click", () => {
|
|
20207
|
+
currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
|
|
20208
|
+
drawLegend2();
|
|
20209
|
+
recolorEvents2();
|
|
20210
|
+
onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
|
|
20211
|
+
});
|
|
20212
|
+
}
|
|
20079
20213
|
if (isActive) {
|
|
20080
20214
|
gEl.append("rect").attr("width", lg.expandedWidth).attr("height", LG_HEIGHT).attr("rx", LG_HEIGHT / 2).attr("fill", groupBg);
|
|
20081
20215
|
}
|
|
@@ -20088,27 +20222,44 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20088
20222
|
}
|
|
20089
20223
|
gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LG_HEIGHT / 2 + LG_PILL_FONT_SIZE / 2 - 2).attr("font-size", LG_PILL_FONT_SIZE).attr("font-weight", "500").attr("font-family", FONT_FAMILY).attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
|
|
20090
20224
|
if (isActive) {
|
|
20091
|
-
let entryX
|
|
20225
|
+
let entryX;
|
|
20226
|
+
if (!viewMode) {
|
|
20227
|
+
const iconX = pillXOff + pillWidth + 5;
|
|
20228
|
+
const iconY = (LG_HEIGHT - 10) / 2;
|
|
20229
|
+
const iconEl = drawSwimlaneIcon2(gEl, iconX, iconY, isSwimActive);
|
|
20230
|
+
iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
|
|
20231
|
+
event.stopPropagation();
|
|
20232
|
+
currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
|
|
20233
|
+
onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
|
|
20234
|
+
relayout2();
|
|
20235
|
+
});
|
|
20236
|
+
entryX = pillXOff + pillWidth + LG_ICON_W + 4;
|
|
20237
|
+
} else {
|
|
20238
|
+
entryX = pillXOff + pillWidth + 8;
|
|
20239
|
+
}
|
|
20092
20240
|
for (const entry of lg.group.entries) {
|
|
20093
20241
|
const tagKey = lg.group.name.toLowerCase();
|
|
20094
20242
|
const tagVal = entry.value.toLowerCase();
|
|
20095
|
-
const entryG = gEl.append("g").attr("class", "tl-tag-legend-entry").attr("data-tag-group", tagKey).attr("data-legend-entry", tagVal)
|
|
20096
|
-
|
|
20097
|
-
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20101
|
-
|
|
20102
|
-
|
|
20103
|
-
|
|
20243
|
+
const entryG = gEl.append("g").attr("class", "tl-tag-legend-entry").attr("data-tag-group", tagKey).attr("data-legend-entry", tagVal);
|
|
20244
|
+
if (!viewMode) {
|
|
20245
|
+
entryG.style("cursor", "pointer").on("mouseenter", (event) => {
|
|
20246
|
+
event.stopPropagation();
|
|
20247
|
+
fadeToTagValue(mainG, tagKey, tagVal);
|
|
20248
|
+
mainSvg.selectAll(".tl-tag-legend-entry").each(function() {
|
|
20249
|
+
const el = d3Selection12.select(this);
|
|
20250
|
+
const ev = el.attr("data-legend-entry");
|
|
20251
|
+
if (ev === "__group__") return;
|
|
20252
|
+
const eg = el.attr("data-tag-group");
|
|
20253
|
+
el.attr("opacity", eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY);
|
|
20254
|
+
});
|
|
20255
|
+
}).on("mouseleave", (event) => {
|
|
20256
|
+
event.stopPropagation();
|
|
20257
|
+
fadeReset(mainG);
|
|
20258
|
+
mainSvg.selectAll(".tl-tag-legend-entry").attr("opacity", 1);
|
|
20259
|
+
}).on("click", (event) => {
|
|
20260
|
+
event.stopPropagation();
|
|
20104
20261
|
});
|
|
20105
|
-
}
|
|
20106
|
-
event.stopPropagation();
|
|
20107
|
-
fadeReset(mainG);
|
|
20108
|
-
mainSvg.selectAll(".tl-tag-legend-entry").attr("opacity", 1);
|
|
20109
|
-
}).on("click", (event) => {
|
|
20110
|
-
event.stopPropagation();
|
|
20111
|
-
});
|
|
20262
|
+
}
|
|
20112
20263
|
entryG.append("circle").attr("cx", entryX + LG_DOT_R).attr("cy", LG_HEIGHT / 2).attr("r", LG_DOT_R).attr("fill", entry.color);
|
|
20113
20264
|
const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
|
|
20114
20265
|
entryG.append("text").attr("x", textX).attr("y", LG_HEIGHT / 2 + LG_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LG_ENTRY_FONT_SIZE).attr("font-family", FONT_FAMILY).attr("fill", palette.textMuted).text(entry.value);
|
|
@@ -20118,17 +20269,18 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20118
20269
|
cx += (isActive ? lg.expandedWidth : lg.minifiedWidth) + LG_GROUP_GAP;
|
|
20119
20270
|
}
|
|
20120
20271
|
}, recolorEvents2 = function() {
|
|
20272
|
+
const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
|
|
20121
20273
|
mainG.selectAll(".tl-event").each(function() {
|
|
20122
20274
|
const el = d3Selection12.select(this);
|
|
20123
20275
|
const lineNum = el.attr("data-line-number");
|
|
20124
20276
|
const ev = lineNum ? eventByLine.get(lineNum) : void 0;
|
|
20125
20277
|
if (!ev) return;
|
|
20126
20278
|
let color;
|
|
20127
|
-
if (
|
|
20279
|
+
if (colorTG) {
|
|
20128
20280
|
const tagColor = resolveTagColor(
|
|
20129
20281
|
ev.metadata,
|
|
20130
20282
|
parsed.timelineTagGroups,
|
|
20131
|
-
|
|
20283
|
+
colorTG
|
|
20132
20284
|
);
|
|
20133
20285
|
color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
|
|
20134
20286
|
} else {
|
|
@@ -20138,12 +20290,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20138
20290
|
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
|
|
20139
20291
|
});
|
|
20140
20292
|
};
|
|
20141
|
-
var drawLegend = drawLegend2, recolorEvents = recolorEvents2;
|
|
20293
|
+
var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
|
|
20142
20294
|
const legendY = title ? 50 : 10;
|
|
20143
20295
|
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
20144
20296
|
const legendGroups = parsed.timelineTagGroups.map((g) => {
|
|
20145
20297
|
const pillW = g.name.length * LG_PILL_FONT_W + LG_PILL_PAD;
|
|
20146
|
-
|
|
20298
|
+
const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
|
|
20299
|
+
let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
|
|
20147
20300
|
for (const entry of g.entries) {
|
|
20148
20301
|
const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
|
|
20149
20302
|
entryX = textX + entry.value.length * LG_ENTRY_FONT_W + LG_ENTRY_TRAIL;
|
|
@@ -20155,6 +20308,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20155
20308
|
};
|
|
20156
20309
|
});
|
|
20157
20310
|
let currentActiveGroup = activeTagGroup ?? null;
|
|
20311
|
+
let currentSwimlaneGroup = swimlaneTagGroup ?? null;
|
|
20158
20312
|
const eventByLine = /* @__PURE__ */ new Map();
|
|
20159
20313
|
for (const ev of timelineEvents) {
|
|
20160
20314
|
eventByLine.set(String(ev.lineNumber), ev);
|
|
@@ -21129,7 +21283,16 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
|
|
|
21129
21283
|
} else if (parsed.type === "arc") {
|
|
21130
21284
|
renderArcDiagram(container, parsed, effectivePalette, isDark, void 0, dims);
|
|
21131
21285
|
} else if (parsed.type === "timeline") {
|
|
21132
|
-
renderTimeline(
|
|
21286
|
+
renderTimeline(
|
|
21287
|
+
container,
|
|
21288
|
+
parsed,
|
|
21289
|
+
effectivePalette,
|
|
21290
|
+
isDark,
|
|
21291
|
+
void 0,
|
|
21292
|
+
dims,
|
|
21293
|
+
orgExportState?.activeTagGroup,
|
|
21294
|
+
orgExportState?.swimlaneTagGroup
|
|
21295
|
+
);
|
|
21133
21296
|
} else if (parsed.type === "venn") {
|
|
21134
21297
|
renderVenn(container, parsed, effectivePalette, isDark, void 0, dims);
|
|
21135
21298
|
} else if (parsed.type === "quadrant") {
|
|
@@ -22012,6 +22175,9 @@ function encodeDiagramUrl(dsl, options) {
|
|
|
22012
22175
|
if (options?.viewState?.collapsedGroups?.length) {
|
|
22013
22176
|
hash += `&cg=${encodeURIComponent(options.viewState.collapsedGroups.join(","))}`;
|
|
22014
22177
|
}
|
|
22178
|
+
if (options?.viewState?.swimlaneTagGroup) {
|
|
22179
|
+
hash += `&swim=${encodeURIComponent(options.viewState.swimlaneTagGroup)}`;
|
|
22180
|
+
}
|
|
22015
22181
|
return { url: `${baseUrl}?${hash}#${hash}` };
|
|
22016
22182
|
}
|
|
22017
22183
|
function decodeDiagramUrl(hash) {
|
|
@@ -22035,6 +22201,9 @@ function decodeDiagramUrl(hash) {
|
|
|
22035
22201
|
if (key === "cg" && val) {
|
|
22036
22202
|
viewState.collapsedGroups = val.split(",").filter(Boolean);
|
|
22037
22203
|
}
|
|
22204
|
+
if (key === "swim" && val) {
|
|
22205
|
+
viewState.swimlaneTagGroup = val;
|
|
22206
|
+
}
|
|
22038
22207
|
}
|
|
22039
22208
|
if (payload.startsWith("dgmo=")) {
|
|
22040
22209
|
payload = payload.slice(5);
|