@diagrammo/dgmo 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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) {
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,10 +20171,36 @@ 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
+ );
20203
+ }, drawLegend2 = function() {
20080
20204
  mainSvg.selectAll(".tl-tag-legend-group").remove();
20081
20205
  const totalW = legendGroups.reduce((s, lg) => {
20082
20206
  const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
@@ -20084,14 +20208,16 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20084
20208
  }, 0) + (legendGroups.length - 1) * LG_GROUP_GAP;
20085
20209
  let cx = (width - totalW) / 2;
20086
20210
  for (const lg of legendGroups) {
20087
- const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
20211
+ const groupKey = lg.group.name.toLowerCase();
20212
+ const isActive = currentActiveGroup != null && currentActiveGroup.toLowerCase() === groupKey;
20213
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
20088
20214
  const pillLabel = lg.group.name;
20089
20215
  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();
20216
+ 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__").style("cursor", "pointer").on("click", () => {
20092
20217
  currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
20093
20218
  drawLegend2();
20094
20219
  recolorEvents2();
20220
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
20095
20221
  });
20096
20222
  if (isActive) {
20097
20223
  gEl.append("rect").attr("width", lg.expandedWidth).attr("height", LG_HEIGHT).attr("rx", LG_HEIGHT / 2).attr("fill", groupBg);
@@ -20105,7 +20231,16 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20105
20231
  }
20106
20232
  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
20233
  if (isActive) {
20108
- let entryX = pillXOff + pillWidth + 4;
20234
+ const iconX = pillXOff + pillWidth + 5;
20235
+ const iconY = (LG_HEIGHT - 10) / 2;
20236
+ const iconEl = drawSwimlaneIcon2(gEl, iconX, iconY, isSwimActive);
20237
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
20238
+ event.stopPropagation();
20239
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
20240
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
20241
+ relayout2();
20242
+ });
20243
+ let entryX = pillXOff + pillWidth + LG_ICON_W + 4;
20109
20244
  for (const entry of lg.group.entries) {
20110
20245
  const tagKey = lg.group.name.toLowerCase();
20111
20246
  const tagVal = entry.value.toLowerCase();
@@ -20135,17 +20270,18 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20135
20270
  cx += (isActive ? lg.expandedWidth : lg.minifiedWidth) + LG_GROUP_GAP;
20136
20271
  }
20137
20272
  }, recolorEvents2 = function() {
20273
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
20138
20274
  mainG.selectAll(".tl-event").each(function() {
20139
20275
  const el = d3Selection12.select(this);
20140
20276
  const lineNum = el.attr("data-line-number");
20141
20277
  const ev = lineNum ? eventByLine.get(lineNum) : void 0;
20142
20278
  if (!ev) return;
20143
20279
  let color;
20144
- if (currentActiveGroup) {
20280
+ if (colorTG) {
20145
20281
  const tagColor = resolveTagColor(
20146
20282
  ev.metadata,
20147
20283
  parsed.timelineTagGroups,
20148
- currentActiveGroup
20284
+ colorTG
20149
20285
  );
20150
20286
  color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
20151
20287
  } else {
@@ -20155,12 +20291,12 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20155
20291
  el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
20156
20292
  });
20157
20293
  };
20158
- var drawLegend = drawLegend2, recolorEvents = recolorEvents2;
20294
+ var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
20159
20295
  const legendY = title ? 50 : 10;
20160
20296
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
20161
20297
  const legendGroups = parsed.timelineTagGroups.map((g) => {
20162
20298
  const pillW = g.name.length * LG_PILL_FONT_W + LG_PILL_PAD;
20163
- let entryX = LG_CAPSULE_PAD + pillW + 4;
20299
+ let entryX = LG_CAPSULE_PAD + pillW + LG_ICON_W + 4;
20164
20300
  for (const entry of g.entries) {
20165
20301
  const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
20166
20302
  entryX = textX + entry.value.length * LG_ENTRY_FONT_W + LG_ENTRY_TRAIL;
@@ -20172,6 +20308,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20172
20308
  };
20173
20309
  });
20174
20310
  let currentActiveGroup = activeTagGroup ?? null;
20311
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
20175
20312
  const eventByLine = /* @__PURE__ */ new Map();
20176
20313
  for (const ev of timelineEvents) {
20177
20314
  eventByLine.set(String(ev.lineNumber), ev);
@@ -21146,7 +21283,16 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21146
21283
  } else if (parsed.type === "arc") {
21147
21284
  renderArcDiagram(container, parsed, effectivePalette, isDark, void 0, dims);
21148
21285
  } else if (parsed.type === "timeline") {
21149
- renderTimeline(container, parsed, effectivePalette, isDark, void 0, dims);
21286
+ renderTimeline(
21287
+ container,
21288
+ parsed,
21289
+ effectivePalette,
21290
+ isDark,
21291
+ void 0,
21292
+ dims,
21293
+ orgExportState?.activeTagGroup,
21294
+ orgExportState?.swimlaneTagGroup
21295
+ );
21150
21296
  } else if (parsed.type === "venn") {
21151
21297
  renderVenn(container, parsed, effectivePalette, isDark, void 0, dims);
21152
21298
  } else if (parsed.type === "quadrant") {
@@ -22173,6 +22319,9 @@ function encodeDiagramUrl(dsl, options) {
22173
22319
  if (options?.viewState?.collapsedGroups?.length) {
22174
22320
  hash += `&cg=${encodeURIComponent(options.viewState.collapsedGroups.join(","))}`;
22175
22321
  }
22322
+ if (options?.viewState?.swimlaneTagGroup) {
22323
+ hash += `&swim=${encodeURIComponent(options.viewState.swimlaneTagGroup)}`;
22324
+ }
22176
22325
  return { url: `${baseUrl}?${hash}#${hash}` };
22177
22326
  }
22178
22327
  function decodeDiagramUrl(hash) {
@@ -22196,6 +22345,9 @@ function decodeDiagramUrl(hash) {
22196
22345
  if (key === "cg" && val) {
22197
22346
  viewState.collapsedGroups = val.split(",").filter(Boolean);
22198
22347
  }
22348
+ if (key === "swim" && val) {
22349
+ viewState.swimlaneTagGroup = val;
22350
+ }
22199
22351
  }
22200
22352
  if (payload.startsWith("dgmo=")) {
22201
22353
  payload = payload.slice(5);