@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/index.cjs CHANGED
@@ -18495,9 +18495,18 @@ function parseD3(content, palette) {
18495
18495
  continue;
18496
18496
  }
18497
18497
  if (key === "sort") {
18498
- const v = line10.substring(colonIndex + 1).trim().toLowerCase();
18499
- if (v === "time" || v === "group") {
18500
- result.timelineSort = v;
18498
+ const v = line10.substring(colonIndex + 1).trim();
18499
+ const vLower = v.toLowerCase();
18500
+ if (vLower === "time" || vLower === "group") {
18501
+ result.timelineSort = vLower;
18502
+ } else if (vLower === "tag" || vLower.startsWith("tag:")) {
18503
+ result.timelineSort = "tag";
18504
+ if (vLower.startsWith("tag:")) {
18505
+ const groupRef = v.substring(4).trim();
18506
+ if (groupRef) {
18507
+ result.timelineDefaultSwimlaneTG = groupRef;
18508
+ }
18509
+ }
18501
18510
  }
18502
18511
  continue;
18503
18512
  }
@@ -18647,6 +18656,25 @@ function parseD3(content, palette) {
18647
18656
  }
18648
18657
  }
18649
18658
  }
18659
+ if (result.timelineSort === "tag") {
18660
+ if (result.timelineTagGroups.length === 0) {
18661
+ warn(1, '"sort: tag" requires at least one tag group definition');
18662
+ result.timelineSort = "time";
18663
+ } else if (result.timelineDefaultSwimlaneTG) {
18664
+ const ref = result.timelineDefaultSwimlaneTG.toLowerCase();
18665
+ const match = result.timelineTagGroups.find(
18666
+ (g) => g.name.toLowerCase() === ref || g.alias?.toLowerCase() === ref
18667
+ );
18668
+ if (match) {
18669
+ result.timelineDefaultSwimlaneTG = match.name;
18670
+ } else {
18671
+ warn(1, `"sort: tag:${result.timelineDefaultSwimlaneTG}" \u2014 no tag group matches "${result.timelineDefaultSwimlaneTG}"`);
18672
+ result.timelineDefaultSwimlaneTG = result.timelineTagGroups[0].name;
18673
+ }
18674
+ } else {
18675
+ result.timelineDefaultSwimlaneTG = result.timelineTagGroups[0].name;
18676
+ }
18677
+ }
18650
18678
  return result;
18651
18679
  }
18652
18680
  if (result.type === "venn") {
@@ -19405,7 +19433,7 @@ function buildEventTooltipHtml(ev) {
19405
19433
  function buildEraTooltipHtml(era) {
19406
19434
  return `<strong>${era.label}</strong><br>${formatDateLabel(era.startDate)} \u2192 ${formatDateLabel(era.endDate)}`;
19407
19435
  }
19408
- function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup) {
19436
+ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
19409
19437
  d3Selection12.select(container).selectAll(":not([data-d3-tooltip])").remove();
19410
19438
  const {
19411
19439
  timelineEvents,
@@ -19419,6 +19447,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19419
19447
  orientation
19420
19448
  } = parsed;
19421
19449
  if (timelineEvents.length === 0) return;
19450
+ if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
19451
+ swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
19452
+ }
19422
19453
  const tooltip = createTooltip(container, palette, isDark);
19423
19454
  const width = exportDims?.width ?? container.clientWidth;
19424
19455
  const height = exportDims?.height ?? container.clientHeight;
@@ -19432,9 +19463,47 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19432
19463
  timelineGroups.forEach((grp, i) => {
19433
19464
  groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
19434
19465
  });
19466
+ let tagLanes = null;
19467
+ if (swimlaneTagGroup) {
19468
+ const tagKey = swimlaneTagGroup.toLowerCase();
19469
+ const tagGroup = parsed.timelineTagGroups.find(
19470
+ (g) => g.name.toLowerCase() === tagKey
19471
+ );
19472
+ if (tagGroup) {
19473
+ const buckets = /* @__PURE__ */ new Map();
19474
+ const otherEvents = [];
19475
+ for (const ev of timelineEvents) {
19476
+ const val = ev.metadata[tagKey];
19477
+ if (val) {
19478
+ const list = buckets.get(val) ?? [];
19479
+ list.push(ev);
19480
+ buckets.set(val, list);
19481
+ } else {
19482
+ otherEvents.push(ev);
19483
+ }
19484
+ }
19485
+ const laneEntries = [...buckets.entries()].sort((a, b) => {
19486
+ const aMin = Math.min(
19487
+ ...a[1].map((e) => parseTimelineDate(e.date))
19488
+ );
19489
+ const bMin = Math.min(
19490
+ ...b[1].map((e) => parseTimelineDate(e.date))
19491
+ );
19492
+ return aMin - bMin;
19493
+ });
19494
+ tagLanes = laneEntries.map(([name, events]) => ({ name, events }));
19495
+ if (otherEvents.length > 0) {
19496
+ tagLanes.push({ name: "(Other)", events: otherEvents });
19497
+ }
19498
+ for (const entry of tagGroup.entries) {
19499
+ groupColorMap.set(entry.value, entry.color);
19500
+ }
19501
+ }
19502
+ }
19503
+ const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
19435
19504
  function eventColor(ev) {
19436
- if (activeTagGroup) {
19437
- const tagColor = resolveTagColor(ev.metadata, parsed.timelineTagGroups, activeTagGroup);
19505
+ if (effectiveColorTG) {
19506
+ const tagColor = resolveTagColor(ev.metadata, parsed.timelineTagGroups, effectiveColorTG);
19438
19507
  if (tagColor) return tagColor;
19439
19508
  }
19440
19509
  if (ev.group && groupColorMap.has(ev.group)) {
@@ -19538,12 +19607,28 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19538
19607
  }
19539
19608
  const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
19540
19609
  if (isVertical) {
19541
- if (timelineSort === "group" && timelineGroups.length > 0) {
19542
- const groupNames = timelineGroups.map((gr) => gr.name);
19543
- const ungroupedEvents = timelineEvents.filter(
19544
- (ev) => ev.group === null || !groupNames.includes(ev.group)
19545
- );
19546
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
19610
+ const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
19611
+ if (useGroupedVertical) {
19612
+ let laneNames;
19613
+ let laneEventsByName;
19614
+ if (tagLanes) {
19615
+ laneNames = tagLanes.map((l) => l.name);
19616
+ laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
19617
+ } else {
19618
+ const groupNames = timelineGroups.map((gr) => gr.name);
19619
+ const ungroupedEvents = timelineEvents.filter(
19620
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
19621
+ );
19622
+ laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
19623
+ laneEventsByName = new Map(
19624
+ laneNames.map((name) => [
19625
+ name,
19626
+ timelineEvents.filter(
19627
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
19628
+ )
19629
+ ])
19630
+ );
19631
+ }
19547
19632
  const laneCount = laneNames.length;
19548
19633
  const scaleMargin = timelineScale ? 40 : 0;
19549
19634
  const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
@@ -19598,6 +19683,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19598
19683
  formatDateLabel(latestEndDateStr)
19599
19684
  );
19600
19685
  }
19686
+ if (timelineSwimlanes || tagLanes) {
19687
+ laneNames.forEach((laneName, laneIdx) => {
19688
+ const laneX = laneIdx * laneWidth;
19689
+ const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
19690
+ 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);
19691
+ });
19692
+ }
19601
19693
  laneNames.forEach((laneName, laneIdx) => {
19602
19694
  const laneX = laneIdx * laneWidth;
19603
19695
  const laneColor = groupColorMap.get(laneName) ?? textColor;
@@ -19605,9 +19697,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19605
19697
  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));
19606
19698
  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);
19607
19699
  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");
19608
- const laneEvents = timelineEvents.filter(
19609
- (ev) => laneName === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === laneName
19610
- );
19700
+ const laneEvents = laneEventsByName.get(laneName) ?? [];
19611
19701
  for (const ev of laneEvents) {
19612
19702
  const y = yScale(parseTimelineDate(ev.date));
19613
19703
  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(
@@ -19625,10 +19715,11 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19625
19715
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
19626
19716
  });
19627
19717
  setTagAttrs(evG, ev);
19718
+ const evColor = eventColor(ev);
19628
19719
  if (ev.endDate) {
19629
19720
  const y2 = yScale(parseTimelineDate(ev.endDate));
19630
19721
  const rectH = Math.max(y2 - y, 4);
19631
- let fill2 = laneColor;
19722
+ let fill2 = evColor;
19632
19723
  if (ev.uncertain) {
19633
19724
  const gradientId = `uncertain-vg-${ev.lineNumber}`;
19634
19725
  const defs = svg.select("defs").node() || svg.append("defs").node();
@@ -19642,7 +19733,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19642
19733
  evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
19643
19734
  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);
19644
19735
  } else {
19645
- evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", laneColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
19736
+ evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", evColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
19646
19737
  evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
19647
19738
  }
19648
19739
  }
@@ -19765,18 +19856,24 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19765
19856
  }
19766
19857
  const BAR_H = 22;
19767
19858
  const GROUP_GAP = 12;
19768
- if (timelineSort === "group" && timelineGroups.length > 0) {
19769
- const groupNames = timelineGroups.map((gr) => gr.name);
19770
- const ungroupedEvents = timelineEvents.filter(
19771
- (ev) => ev.group === null || !groupNames.includes(ev.group)
19772
- );
19773
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
19774
- const lanes = laneNames.map((name) => ({
19775
- name,
19776
- events: timelineEvents.filter(
19777
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
19778
- )
19779
- }));
19859
+ const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
19860
+ if (useGroupedHorizontal) {
19861
+ let lanes;
19862
+ if (tagLanes) {
19863
+ lanes = tagLanes;
19864
+ } else {
19865
+ const groupNames = timelineGroups.map((gr) => gr.name);
19866
+ const ungroupedEvents = timelineEvents.filter(
19867
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
19868
+ );
19869
+ const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
19870
+ lanes = laneNames.map((name) => ({
19871
+ name,
19872
+ events: timelineEvents.filter(
19873
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
19874
+ )
19875
+ }));
19876
+ }
19780
19877
  const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
19781
19878
  const scaleMargin = timelineScale ? 24 : 0;
19782
19879
  const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
@@ -19836,7 +19933,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19836
19933
  );
19837
19934
  }
19838
19935
  let curY = markerMargin;
19839
- if (timelineSwimlanes) {
19936
+ if (timelineSwimlanes || tagLanes) {
19840
19937
  let swimY = markerMargin;
19841
19938
  lanes.forEach((lane, idx) => {
19842
19939
  const laneSpan = lane.events.length * rowH;
@@ -19888,12 +19985,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19888
19985
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
19889
19986
  });
19890
19987
  setTagAttrs(evG, ev);
19988
+ const evColor = eventColor(ev);
19891
19989
  if (ev.endDate) {
19892
19990
  const x2 = xScale(parseTimelineDate(ev.endDate));
19893
19991
  const rectW = Math.max(x2 - x, 4);
19894
19992
  const estLabelWidth = ev.label.length * 7 + 16;
19895
19993
  const labelFitsInside = rectW >= estLabelWidth;
19896
- let fill2 = laneColor;
19994
+ let fill2 = evColor;
19897
19995
  if (ev.uncertain) {
19898
19996
  const gradientId = `uncertain-${ev.lineNumber}`;
19899
19997
  const defs = svg.select("defs").node() || svg.append("defs").node();
@@ -19901,7 +19999,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19901
19999
  { offset: "0%", opacity: 1 },
19902
20000
  { offset: "80%", opacity: 1 },
19903
20001
  { offset: "100%", opacity: 0 }
19904
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", laneColor).attr("stop-opacity", (d) => d.opacity);
20002
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
19905
20003
  fill2 = `url(#${gradientId})`;
19906
20004
  }
19907
20005
  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);
@@ -19918,7 +20016,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
19918
20016
  const wouldFlipLeft = x > innerWidth * 0.6;
19919
20017
  const labelFitsLeft = x - 10 - estLabelWidth > 0;
19920
20018
  const flipLeft = wouldFlipLeft && labelFitsLeft;
19921
- evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", laneColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
20019
+ evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", evColor).attr("stroke", bgColor).attr("stroke-width", 1.5);
19922
20020
  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);
19923
20021
  }
19924
20022
  });
@@ -20073,26 +20171,62 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20073
20171
  const LG_ENTRY_DOT_GAP = 4;
20074
20172
  const LG_ENTRY_TRAIL = 8;
20075
20173
  const LG_GROUP_GAP = 12;
20174
+ const LG_ICON_W = 20;
20076
20175
  const mainSvg = d3Selection12.select(container).select("svg");
20077
20176
  const mainG = mainSvg.select("g");
20078
20177
  if (!mainSvg.empty() && !mainG.empty()) {
20079
- let drawLegend2 = function() {
20178
+ let drawSwimlaneIcon2 = function(parent, x, y, isSwimActive) {
20179
+ const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
20180
+ const barColor = isSwimActive ? palette.primary : palette.textMuted;
20181
+ const barOpacity = isSwimActive ? 1 : 0.35;
20182
+ const bars = [
20183
+ { y: 0, w: 8 },
20184
+ { y: 4, w: 12 },
20185
+ { y: 8, w: 6 }
20186
+ ];
20187
+ for (const bar of bars) {
20188
+ 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);
20189
+ }
20190
+ return iconG;
20191
+ }, relayout2 = function() {
20192
+ renderTimeline(
20193
+ container,
20194
+ parsed,
20195
+ palette,
20196
+ isDark,
20197
+ onClickItem,
20198
+ exportDims,
20199
+ currentActiveGroup,
20200
+ currentSwimlaneGroup,
20201
+ onTagStateChange,
20202
+ viewMode
20203
+ );
20204
+ }, drawLegend2 = function() {
20080
20205
  mainSvg.selectAll(".tl-tag-legend-group").remove();
20081
- const totalW = legendGroups.reduce((s, lg) => {
20206
+ const visibleGroups = viewMode ? legendGroups.filter(
20207
+ (lg) => currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase()
20208
+ ) : legendGroups;
20209
+ if (visibleGroups.length === 0) return;
20210
+ const totalW = visibleGroups.reduce((s, lg) => {
20082
20211
  const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
20083
20212
  return s + (isActive ? lg.expandedWidth : lg.minifiedWidth);
20084
- }, 0) + (legendGroups.length - 1) * LG_GROUP_GAP;
20213
+ }, 0) + (visibleGroups.length - 1) * LG_GROUP_GAP;
20085
20214
  let cx = (width - totalW) / 2;
20086
- for (const lg of legendGroups) {
20087
- const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
20215
+ for (const lg of visibleGroups) {
20216
+ const groupKey = lg.group.name.toLowerCase();
20217
+ const isActive = currentActiveGroup != null && currentActiveGroup.toLowerCase() === groupKey;
20218
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
20088
20219
  const pillLabel = lg.group.name;
20089
20220
  const pillWidth = pillLabel.length * LG_PILL_FONT_W + LG_PILL_PAD;
20090
- const gEl = mainSvg.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group", lg.group.name.toLowerCase()).attr("data-tag-group", lg.group.name.toLowerCase()).attr("data-legend-entry", "__group__").style("cursor", "pointer").on("click", () => {
20091
- const groupKey = lg.group.name.toLowerCase();
20092
- currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
20093
- drawLegend2();
20094
- recolorEvents2();
20095
- });
20221
+ 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__");
20222
+ if (!viewMode) {
20223
+ gEl.style("cursor", "pointer").on("click", () => {
20224
+ currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
20225
+ drawLegend2();
20226
+ recolorEvents2();
20227
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
20228
+ });
20229
+ }
20096
20230
  if (isActive) {
20097
20231
  gEl.append("rect").attr("width", lg.expandedWidth).attr("height", LG_HEIGHT).attr("rx", LG_HEIGHT / 2).attr("fill", groupBg);
20098
20232
  }
@@ -20105,27 +20239,44 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20105
20239
  }
20106
20240
  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);
20107
20241
  if (isActive) {
20108
- let entryX = pillXOff + pillWidth + 4;
20242
+ let entryX;
20243
+ if (!viewMode) {
20244
+ const iconX = pillXOff + pillWidth + 5;
20245
+ const iconY = (LG_HEIGHT - 10) / 2;
20246
+ const iconEl = drawSwimlaneIcon2(gEl, iconX, iconY, isSwimActive);
20247
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
20248
+ event.stopPropagation();
20249
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
20250
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
20251
+ relayout2();
20252
+ });
20253
+ entryX = pillXOff + pillWidth + LG_ICON_W + 4;
20254
+ } else {
20255
+ entryX = pillXOff + pillWidth + 8;
20256
+ }
20109
20257
  for (const entry of lg.group.entries) {
20110
20258
  const tagKey = lg.group.name.toLowerCase();
20111
20259
  const tagVal = entry.value.toLowerCase();
20112
- const entryG = gEl.append("g").attr("class", "tl-tag-legend-entry").attr("data-tag-group", tagKey).attr("data-legend-entry", tagVal).style("cursor", "pointer").on("mouseenter", (event) => {
20113
- event.stopPropagation();
20114
- fadeToTagValue(mainG, tagKey, tagVal);
20115
- mainSvg.selectAll(".tl-tag-legend-entry").each(function() {
20116
- const el = d3Selection12.select(this);
20117
- const ev = el.attr("data-legend-entry");
20118
- if (ev === "__group__") return;
20119
- const eg = el.attr("data-tag-group");
20120
- el.attr("opacity", eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY);
20260
+ const entryG = gEl.append("g").attr("class", "tl-tag-legend-entry").attr("data-tag-group", tagKey).attr("data-legend-entry", tagVal);
20261
+ if (!viewMode) {
20262
+ entryG.style("cursor", "pointer").on("mouseenter", (event) => {
20263
+ event.stopPropagation();
20264
+ fadeToTagValue(mainG, tagKey, tagVal);
20265
+ mainSvg.selectAll(".tl-tag-legend-entry").each(function() {
20266
+ const el = d3Selection12.select(this);
20267
+ const ev = el.attr("data-legend-entry");
20268
+ if (ev === "__group__") return;
20269
+ const eg = el.attr("data-tag-group");
20270
+ el.attr("opacity", eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY);
20271
+ });
20272
+ }).on("mouseleave", (event) => {
20273
+ event.stopPropagation();
20274
+ fadeReset(mainG);
20275
+ mainSvg.selectAll(".tl-tag-legend-entry").attr("opacity", 1);
20276
+ }).on("click", (event) => {
20277
+ event.stopPropagation();
20121
20278
  });
20122
- }).on("mouseleave", (event) => {
20123
- event.stopPropagation();
20124
- fadeReset(mainG);
20125
- mainSvg.selectAll(".tl-tag-legend-entry").attr("opacity", 1);
20126
- }).on("click", (event) => {
20127
- event.stopPropagation();
20128
- });
20279
+ }
20129
20280
  entryG.append("circle").attr("cx", entryX + LG_DOT_R).attr("cy", LG_HEIGHT / 2).attr("r", LG_DOT_R).attr("fill", entry.color);
20130
20281
  const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
20131
20282
  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);
@@ -20135,17 +20286,18 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20135
20286
  cx += (isActive ? lg.expandedWidth : lg.minifiedWidth) + LG_GROUP_GAP;
20136
20287
  }
20137
20288
  }, recolorEvents2 = function() {
20289
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
20138
20290
  mainG.selectAll(".tl-event").each(function() {
20139
20291
  const el = d3Selection12.select(this);
20140
20292
  const lineNum = el.attr("data-line-number");
20141
20293
  const ev = lineNum ? eventByLine.get(lineNum) : void 0;
20142
20294
  if (!ev) return;
20143
20295
  let color;
20144
- if (currentActiveGroup) {
20296
+ if (colorTG) {
20145
20297
  const tagColor = resolveTagColor(
20146
20298
  ev.metadata,
20147
20299
  parsed.timelineTagGroups,
20148
- currentActiveGroup
20300
+ colorTG
20149
20301
  );
20150
20302
  color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
20151
20303
  } else {
@@ -20155,12 +20307,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20155
20307
  el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
20156
20308
  });
20157
20309
  };
20158
- var drawLegend = drawLegend2, recolorEvents = recolorEvents2;
20310
+ var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
20159
20311
  const legendY = title ? 50 : 10;
20160
20312
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
20161
20313
  const legendGroups = parsed.timelineTagGroups.map((g) => {
20162
20314
  const pillW = g.name.length * LG_PILL_FONT_W + LG_PILL_PAD;
20163
- let entryX = LG_CAPSULE_PAD + pillW + 4;
20315
+ const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
20316
+ let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
20164
20317
  for (const entry of g.entries) {
20165
20318
  const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
20166
20319
  entryX = textX + entry.value.length * LG_ENTRY_FONT_W + LG_ENTRY_TRAIL;
@@ -20172,6 +20325,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20172
20325
  };
20173
20326
  });
20174
20327
  let currentActiveGroup = activeTagGroup ?? null;
20328
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
20175
20329
  const eventByLine = /* @__PURE__ */ new Map();
20176
20330
  for (const ev of timelineEvents) {
20177
20331
  eventByLine.set(String(ev.lineNumber), ev);
@@ -21146,7 +21300,16 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21146
21300
  } else if (parsed.type === "arc") {
21147
21301
  renderArcDiagram(container, parsed, effectivePalette, isDark, void 0, dims);
21148
21302
  } else if (parsed.type === "timeline") {
21149
- renderTimeline(container, parsed, effectivePalette, isDark, void 0, dims);
21303
+ renderTimeline(
21304
+ container,
21305
+ parsed,
21306
+ effectivePalette,
21307
+ isDark,
21308
+ void 0,
21309
+ dims,
21310
+ orgExportState?.activeTagGroup,
21311
+ orgExportState?.swimlaneTagGroup
21312
+ );
21150
21313
  } else if (parsed.type === "venn") {
21151
21314
  renderVenn(container, parsed, effectivePalette, isDark, void 0, dims);
21152
21315
  } else if (parsed.type === "quadrant") {
@@ -22173,6 +22336,9 @@ function encodeDiagramUrl(dsl, options) {
22173
22336
  if (options?.viewState?.collapsedGroups?.length) {
22174
22337
  hash += `&cg=${encodeURIComponent(options.viewState.collapsedGroups.join(","))}`;
22175
22338
  }
22339
+ if (options?.viewState?.swimlaneTagGroup) {
22340
+ hash += `&swim=${encodeURIComponent(options.viewState.swimlaneTagGroup)}`;
22341
+ }
22176
22342
  return { url: `${baseUrl}?${hash}#${hash}` };
22177
22343
  }
22178
22344
  function decodeDiagramUrl(hash) {
@@ -22196,6 +22362,9 @@ function decodeDiagramUrl(hash) {
22196
22362
  if (key === "cg" && val) {
22197
22363
  viewState.collapsedGroups = val.split(",").filter(Boolean);
22198
22364
  }
22365
+ if (key === "swim" && val) {
22366
+ viewState.swimlaneTagGroup = val;
22367
+ }
22199
22368
  }
22200
22369
  if (payload.startsWith("dgmo=")) {
22201
22370
  payload = payload.slice(5);