@diagrammo/dgmo 0.7.1 → 0.7.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.js CHANGED
@@ -7964,7 +7964,9 @@ function parseGantt(content, palette) {
7964
7964
  criticalPath: false,
7965
7965
  dependencies: false,
7966
7966
  sort: "default",
7967
- defaultSwimlaneGroup: null
7967
+ defaultSwimlaneGroup: null,
7968
+ optionLineNumbers: {},
7969
+ holidaysLineNumber: null
7968
7970
  },
7969
7971
  diagnostics,
7970
7972
  error: null
@@ -8149,6 +8151,7 @@ function parseGantt(content, palette) {
8149
8151
  inHolidaysBlock = true;
8150
8152
  holidaysBlockIndent = indent;
8151
8153
  inHeaderBlock = false;
8154
+ result.options.holidaysLineNumber = lineNumber;
8152
8155
  continue;
8153
8156
  }
8154
8157
  const tagMatch = matchTagBlockHeading(line10);
@@ -8175,7 +8178,8 @@ function parseGantt(content, palette) {
8175
8178
  startDate: eraMatch[1],
8176
8179
  endDate: eraMatch[2],
8177
8180
  label: eraExtracted.label,
8178
- color: eraExtracted.color || null
8181
+ color: eraExtracted.color || null,
8182
+ lineNumber
8179
8183
  });
8180
8184
  inHeaderBlock = false;
8181
8185
  continue;
@@ -8197,6 +8201,7 @@ function parseGantt(content, palette) {
8197
8201
  if (optMatch && isKnownOption(optMatch[1].toLowerCase())) {
8198
8202
  const key = optMatch[1].toLowerCase();
8199
8203
  const value = optMatch[2].trim();
8204
+ result.options.optionLineNumbers[key] = lineNumber;
8200
8205
  switch (key) {
8201
8206
  case "start":
8202
8207
  result.options.start = value;
@@ -16109,7 +16114,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
16109
16114
  }
16110
16115
  const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
16111
16116
  const LABEL_CHAR_W = 7;
16112
- const LABEL_PAD = 8;
16117
+ const LABEL_PAD2 = 8;
16113
16118
  const LABEL_H = 16;
16114
16119
  const PERP_OFFSET = 10;
16115
16120
  const labelPositions = [];
@@ -16118,7 +16123,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
16118
16123
  if (!edge.label || edge.points.length < 2) continue;
16119
16124
  const midIdx = Math.floor(edge.points.length / 2);
16120
16125
  const midPt = edge.points[midIdx];
16121
- const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD;
16126
+ const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
16122
16127
  const prev = edge.points[Math.max(0, midIdx - 1)];
16123
16128
  const next = edge.points[Math.min(edge.points.length - 1, midIdx + 1)];
16124
16129
  const dx = next.x - prev.x;
@@ -19361,8 +19366,46 @@ __export(renderer_exports9, {
19361
19366
  });
19362
19367
  import * as d3Scale from "d3-scale";
19363
19368
  import * as d3Selection10 from "d3-selection";
19369
+ function computeBarLabel(label, x1, barWidth, innerWidth, textColor) {
19370
+ const textWidth = label.length * CHAR_W;
19371
+ const x2 = x1 + barWidth;
19372
+ if (textWidth < barWidth - LABEL_PAD) {
19373
+ return { x: x1 + 6, anchor: "start", fill: textColor, text: label };
19374
+ }
19375
+ if (x2 + LABEL_GAP + textWidth <= innerWidth) {
19376
+ return { x: x2 + LABEL_GAP, anchor: "start", fill: textColor, text: label };
19377
+ }
19378
+ if (x1 - LABEL_GAP - textWidth >= 0) {
19379
+ return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label };
19380
+ }
19381
+ const availWidth = x1 - LABEL_GAP;
19382
+ if (availWidth > CHAR_W * 3) {
19383
+ const maxChars = Math.floor(availWidth / CHAR_W) - 1;
19384
+ return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label.slice(0, maxChars) + "\u2026" };
19385
+ }
19386
+ return null;
19387
+ }
19388
+ function renderLabelBand(svg, y, leftMargin, color, palette, cssPrefix, dataAttr) {
19389
+ const bandX = 5;
19390
+ const bandW = leftMargin - 7;
19391
+ const bandY = y - BAR_H / 2;
19392
+ const clipId = `gantt-band-clip-${bandClipCounter++}`;
19393
+ svg.append("clipPath").attr("id", clipId).append("rect").attr("x", bandX).attr("y", bandY).attr("width", bandW).attr("height", BAR_H).attr("rx", BAND_RADIUS);
19394
+ const tint2 = svg.append("rect").attr("class", `gantt-${cssPrefix}-band-bg`).attr("x", bandX).attr("y", bandY).attr("width", bandW).attr("height", BAR_H).attr("rx", BAND_RADIUS).attr("fill", mix(color, palette.bg, 20)).style("pointer-events", "none");
19395
+ const accent = svg.append("rect").attr("class", `gantt-${cssPrefix}-band-accent`).attr("x", bandX).attr("y", bandY).attr("width", BAND_ACCENT_W).attr("height", BAR_H).attr("fill", color).attr("clip-path", `url(#${clipId})`).style("pointer-events", "none");
19396
+ if (dataAttr) {
19397
+ tint2.attr(dataAttr.key, dataAttr.value);
19398
+ accent.attr(dataAttr.key, dataAttr.value);
19399
+ }
19400
+ }
19401
+ function appendTaskIcon(textEl, label, isMilestone, iconColor, textColor) {
19402
+ const icon = isMilestone ? "\u25C6" : "\u25CF";
19403
+ textEl.append("tspan").attr("fill", iconColor).text(icon);
19404
+ textEl.append("tspan").attr("fill", textColor).text(" " + label);
19405
+ }
19364
19406
  function renderGantt(container, resolved, palette, isDark, options, exportDims) {
19365
19407
  container.innerHTML = "";
19408
+ bandClipCounter = 0;
19366
19409
  if (resolved.tasks.length === 0) return;
19367
19410
  const onClickItem = options?.onClickItem;
19368
19411
  const collapsedGroups = options?.collapsedGroups;
@@ -19381,10 +19424,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19381
19424
  const isTagMode = tagRows !== null;
19382
19425
  const allLabels = isTagMode ? [
19383
19426
  ...rows.filter((r) => r.type === "lane-header").map((r) => r.laneName),
19384
- ...rows.filter((r) => r.type === "task").map((r) => r.task.task.label)
19427
+ ...rows.filter((r) => r.type === "task").map((r) => "\u25CF " + r.task.task.label)
19385
19428
  ] : [
19386
- ...resolved.tasks.map((t) => t.task.label),
19387
- ...resolved.groups.map((g2) => " ".repeat(g2.depth) + g2.name)
19429
+ ...resolved.tasks.map((t) => "\u25CF " + t.task.label),
19430
+ ...resolved.groups.map((g2) => {
19431
+ const px = g2.depth <= 2 ? g2.depth * 14 : 2 * 14 + (g2.depth - 2) * 8;
19432
+ return " ".repeat(Math.ceil(px / 7)) + g2.name;
19433
+ })
19388
19434
  ];
19389
19435
  const maxLabelLen = Math.max(...allLabels.map((l) => l.length), 10);
19390
19436
  const leftMargin = Math.max(MIN_LEFT_MARGIN, maxLabelLen * 7 + 30);
@@ -19393,8 +19439,10 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19393
19439
  const titleHeight = title ? 50 : 20;
19394
19440
  const tagLegendReserve = resolved.tagGroups.length > 0 ? LEGEND_HEIGHT + 8 : 0;
19395
19441
  const topDateLabelReserve = 22;
19442
+ const hasOverheadLabels = resolved.markers.length > 0 || resolved.eras.length > 0;
19443
+ const markerLabelReserve = hasOverheadLabels ? 18 : 0;
19396
19444
  const CONTENT_TOP_PAD = 16;
19397
- const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve;
19445
+ const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve + markerLabelReserve;
19398
19446
  const contentH = isTagMode ? totalRows * (BAR_H + ROW_GAP) : totalRows * (BAR_H + ROW_GAP) + GROUP_GAP2 * resolved.groups.length;
19399
19447
  const innerHeight = CONTENT_TOP_PAD + contentH;
19400
19448
  const outerHeight = marginTop + innerHeight + BOTTOM_MARGIN;
@@ -19422,6 +19470,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19422
19470
  isDark,
19423
19471
  hasCriticalPath,
19424
19472
  criticalPathActive,
19473
+ resolved.options.optionLineNumbers,
19425
19474
  (groupName) => {
19426
19475
  currentActiveGroup = currentActiveGroup?.toLowerCase() === groupName.toLowerCase() ? null : groupName;
19427
19476
  if (onActiveGroupChange) onActiveGroupChange(currentActiveGroup);
@@ -19460,7 +19509,25 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19460
19509
  renderTimeScaleHorizontal(g, xScale, innerWidth, innerHeight, palette.text);
19461
19510
  renderWeekendBands(g, resolved, xScale, innerHeight, palette, isDark);
19462
19511
  renderHolidayBands(g, svg, resolved, xScale, innerHeight, palette, isDark, marginTop - 4, leftMargin, onClickItem);
19463
- renderErasAndMarkers(g, resolved, xScale, innerHeight, palette);
19512
+ renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette);
19513
+ let todayDate = null;
19514
+ let todayX = -1;
19515
+ const todayColor = palette.accent || "#e74c3c";
19516
+ const todayMarkerLineNum = resolved.options.optionLineNumbers["today-marker"];
19517
+ if (resolved.options.todayMarker !== "off") {
19518
+ if (resolved.options.todayMarker === "on") {
19519
+ todayDate = /* @__PURE__ */ new Date();
19520
+ } else {
19521
+ todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
19522
+ }
19523
+ todayX = xScale(dateToFractionalYear(todayDate));
19524
+ if (todayX >= 0 && todayX <= innerWidth) {
19525
+ const todayLine = g.append("line").attr("class", "gantt-today").attr("x1", todayX).attr("y1", 0).attr("x2", todayX).attr("y2", innerHeight + 10).attr("stroke", todayColor).attr("stroke-width", 2).attr("stroke-dasharray", "6 4").attr("opacity", 0.7).attr("pointer-events", "none");
19526
+ if (todayMarkerLineNum) todayLine.attr("data-line-number", String(todayMarkerLineNum));
19527
+ const todayLabel = g.append("text").attr("class", "gantt-today").attr("x", todayX).attr("y", innerHeight + 24).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", todayColor).attr("opacity", 0.7).attr("pointer-events", "none").text("Today");
19528
+ if (todayMarkerLineNum) todayLabel.attr("data-line-number", String(todayMarkerLineNum));
19529
+ }
19530
+ }
19464
19531
  const taskPositions = /* @__PURE__ */ new Map();
19465
19532
  const groupPositions = /* @__PURE__ */ new Map();
19466
19533
  const lanePositions = /* @__PURE__ */ new Map();
@@ -19496,6 +19563,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19496
19563
  laneBarWidth = Math.max(lx2 - lx1, 2);
19497
19564
  }
19498
19565
  lanePositions.set(row.laneName, { x1: lx1, x2: lx1 + laneBarWidth, y: yOffset + BAR_H / 2 });
19566
+ renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, laneColor, palette, "lane", { key: "data-lane", value: row.laneName });
19499
19567
  const labelG = svg.append("g").attr("class", "gantt-lane-header").attr(`data-tag-${row.tagKey}`, row.laneName.toLowerCase()).attr("data-lane", row.laneName).style("cursor", onToggleLane ? "pointer" : "default").on("click", () => {
19500
19568
  if (onToggleLane) onToggleLane(row.laneName);
19501
19569
  }).on("mouseenter", () => {
@@ -19521,7 +19589,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19521
19589
  });
19522
19590
  laneBandG.append("rect").attr("class", "gantt-lane-band").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", barFill).attr("stroke", laneColor).attr("stroke-width", 2);
19523
19591
  if (row.aggregateProgress !== null && row.aggregateProgress > 0) {
19524
- laneBandG.append("rect").attr("class", "gantt-lane-progress").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth * Math.min(row.aggregateProgress / 100, 1)).attr("height", BAR_H).attr("rx", 4).attr("fill", laneColor).attr("opacity", 0.5).attr("pointer-events", "none");
19592
+ laneBandG.append("rect").attr("class", "gantt-lane-progress").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth * Math.min(row.aggregateProgress / 100, 1)).attr("height", BAR_H).attr("fill", laneColor).attr("opacity", 0.5).attr("pointer-events", "none");
19525
19593
  }
19526
19594
  }
19527
19595
  yOffset += BAR_H + ROW_GAP;
@@ -19532,6 +19600,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19532
19600
  const toggleIcon = isCollapsed ? "\u25BA" : "\u25BC";
19533
19601
  const tagColor = resolveTagColor(group.metadata, resolved.tagGroups, currentActiveGroup, true);
19534
19602
  const groupColor = tagColor && tagColor !== "#999999" ? tagColor : group.color || palette.textMuted;
19603
+ renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, groupColor, palette, "group", { key: "data-group", value: group.name });
19535
19604
  const labelG = svg.append("g").attr("class", "gantt-group-label").attr("data-group", group.name).attr("data-line-number", String(group.lineNumber)).style("cursor", onToggleGroup ? "pointer" : "default").on("click", () => {
19536
19605
  if (onToggleGroup) onToggleGroup(group.name);
19537
19606
  }).on("mouseenter", () => {
@@ -19541,7 +19610,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19541
19610
  resetHighlight(g, svg);
19542
19611
  hideGanttDateIndicators(g);
19543
19612
  });
19544
- const labelX = 10 + group.depth * 14;
19613
+ const groupIndent = group.depth <= 2 ? group.depth * 14 : 2 * 14 + (group.depth - 2) * 8;
19614
+ const labelX = 10 + groupIndent;
19545
19615
  labelG.append("text").attr("x", labelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("font-weight", "bold").attr("fill", palette.text).text(toggleIcon + " " + group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : ""));
19546
19616
  const gStart = dateToFractionalYear(group.startDate);
19547
19617
  const gEnd = dateToFractionalYear(group.endDate);
@@ -19559,7 +19629,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19559
19629
  });
19560
19630
  summaryG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", barWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", mix(groupColor, palette.bg, 30)).attr("stroke", groupColor).attr("stroke-width", 2);
19561
19631
  if (group.progress !== null && group.progress > 0) {
19562
- summaryG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", barWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("rx", 4).attr("fill", groupColor).attr("opacity", 0.5);
19632
+ summaryG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", barWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("fill", groupColor).attr("opacity", 0.5);
19633
+ }
19634
+ const summaryLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
19635
+ const summaryPlacement = computeBarLabel(summaryLabel, gx1, barWidth, innerWidth, palette.text);
19636
+ if (summaryPlacement) {
19637
+ summaryG.append("text").attr("x", summaryPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("font-weight", "bold").attr("text-anchor", summaryPlacement.anchor).attr("fill", summaryPlacement.fill).attr("pointer-events", "none").text(summaryPlacement.text);
19563
19638
  }
19564
19639
  groupPositions.set(group.name, { x1: gx1, x2: gx1 + barWidth, y: yOffset + BAR_H / 2 });
19565
19640
  } else {
@@ -19574,7 +19649,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19574
19649
  });
19575
19650
  groupBarG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", groupBarWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", bandFill).attr("stroke", groupColor).attr("stroke-width", 2);
19576
19651
  if (group.progress !== null && group.progress > 0) {
19577
- groupBarG.append("rect").attr("class", "gantt-group-progress").attr("x", gx1).attr("y", yOffset).attr("width", groupBarWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("rx", 4).attr("fill", groupColor).attr("opacity", 0.5);
19652
+ groupBarG.append("rect").attr("class", "gantt-group-progress").attr("x", gx1).attr("y", yOffset).attr("width", groupBarWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("fill", groupColor).attr("opacity", 0.5);
19653
+ }
19654
+ const expandedLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
19655
+ const expandedPlacement = computeBarLabel(expandedLabel, gx1, groupBarWidth, innerWidth, palette.text);
19656
+ if (expandedPlacement) {
19657
+ groupBarG.append("text").attr("x", expandedPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("font-weight", "bold").attr("text-anchor", expandedPlacement.anchor).attr("fill", expandedPlacement.fill).attr("pointer-events", "none").text(expandedPlacement.text);
19578
19658
  }
19579
19659
  }
19580
19660
  }
@@ -19582,9 +19662,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19582
19662
  } else if (row.type === "task") {
19583
19663
  const rt = row.task;
19584
19664
  const task = rt.task;
19585
- const taskLabelX = isTagMode ? 20 : 6 + rt.groupPath.length * 14;
19665
+ const barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
19666
+ const depth = rt.groupPath.length;
19667
+ const indent = depth <= 2 ? depth * 14 : 2 * 14 + (depth - 2) * 8;
19668
+ const taskLabelX = isTagMode ? 20 : 6 + indent;
19586
19669
  const topGroup = rt.groupPath.length > 0 ? rt.groupPath[0] : null;
19587
- const taskLabel = svg.append("text").attr("class", "gantt-task-label").attr("x", taskLabelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("fill", palette.text).attr("data-line-number", String(task.lineNumber)).attr("data-task-id", task.id).attr("data-group", topGroup).style("cursor", onClickItem ? "pointer" : "default").text(task.label).on("click", () => {
19670
+ const taskLabel = svg.append("text").attr("class", "gantt-task-label").attr("x", taskLabelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("fill", palette.text).attr("data-line-number", String(task.lineNumber)).attr("data-task-id", task.id).attr("data-group", topGroup).style("cursor", onClickItem ? "pointer" : "default").on("click", () => {
19588
19671
  if (onClickItem) onClickItem(task.lineNumber);
19589
19672
  }).on("mouseenter", () => {
19590
19673
  if (rt.isMilestone) {
@@ -19595,13 +19678,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19595
19678
  }).on("mouseleave", () => {
19596
19679
  resetHighlight(g, svg);
19597
19680
  });
19681
+ appendTaskIcon(taskLabel, task.label, rt.isMilestone, barColor, palette.text);
19598
19682
  for (const [key, value] of Object.entries(rt.effectiveMetadata)) {
19599
19683
  taskLabel.attr(`data-tag-${key}`, value.toLowerCase());
19600
19684
  }
19601
19685
  if (rt.isCriticalPath) {
19602
19686
  taskLabel.attr("data-critical-path", "true");
19603
19687
  }
19604
- let barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
19605
19688
  if (rt.isMilestone) {
19606
19689
  const mx = xScale(dateToFractionalYear(rt.startDate));
19607
19690
  const my = yOffset + BAR_H / 2;
@@ -19679,32 +19762,40 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19679
19762
  progGrad.append("stop").attr("offset", "100%").attr("stop-color", barColor).attr("stop-opacity", 0);
19680
19763
  progressFill = `url(#${progGradId})`;
19681
19764
  }
19682
- taskG.append("rect").attr("class", "gantt-progress").attr("x", x1).attr("y", yOffset).attr("width", progressWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", progressFill).attr("opacity", 0.5);
19765
+ taskG.append("rect").attr("class", "gantt-progress").attr("x", x1).attr("y", yOffset).attr("width", progressWidth).attr("height", BAR_H).attr("fill", progressFill).attr("opacity", 0.5);
19683
19766
  }
19684
19767
  if (rt.isCriticalPath) {
19685
19768
  taskG.attr("data-critical-path", "true");
19686
19769
  }
19687
- const textWidth = task.label.length * 6.5;
19688
- if (textWidth < barWidth - 8) {
19689
- taskG.append("text").attr("x", x1 + 6).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("fill", palette.text).attr("pointer-events", "none").text(task.label);
19770
+ const labelPlacement = computeBarLabel(task.label, x1, barWidth, innerWidth, palette.text);
19771
+ if (labelPlacement) {
19772
+ taskG.append("text").attr("x", labelPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("text-anchor", labelPlacement.anchor).attr("fill", labelPlacement.fill).attr("pointer-events", "none").text(labelPlacement.text);
19690
19773
  }
19691
19774
  taskPositions.set(task.id, { x1, x2: x1 + barWidth, y: yOffset + BAR_H / 2 });
19692
19775
  }
19693
19776
  yOffset += BAR_H + ROW_GAP;
19694
19777
  }
19695
19778
  }
19696
- if (resolved.options.todayMarker !== "off") {
19697
- let todayDate;
19698
- if (resolved.options.todayMarker === "on") {
19699
- todayDate = /* @__PURE__ */ new Date();
19700
- } else {
19701
- todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
19702
- }
19703
- const todayX = xScale(dateToFractionalYear(todayDate));
19704
- if (todayX >= 0 && todayX <= innerWidth) {
19705
- g.append("line").attr("class", "gantt-today").attr("x1", todayX).attr("y1", 0).attr("x2", todayX).attr("y2", innerHeight + 10).attr("stroke", palette.accent || "#e74c3c").attr("stroke-width", 2).attr("stroke-dasharray", "6 4").attr("opacity", 0.7);
19706
- g.append("text").attr("class", "gantt-today").attr("x", todayX + 4).attr("y", innerHeight + 24).attr("text-anchor", "start").attr("font-size", "10px").attr("fill", palette.accent || "#e74c3c").attr("opacity", 0.7).text("Today");
19707
- }
19779
+ if (todayDate && todayX >= 0 && todayX <= innerWidth) {
19780
+ const todayHoverG = g.append("g").attr("class", "gantt-today-hover").style("cursor", "pointer");
19781
+ todayHoverG.append("rect").attr("x", todayX - 10).attr("y", -6).attr("width", 20).attr("height", innerHeight + 16).attr("fill", "transparent").attr("pointer-events", "all");
19782
+ const todayDateObj = todayDate;
19783
+ todayHoverG.on("mouseenter", () => {
19784
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
19785
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
19786
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
19787
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
19788
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
19789
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
19790
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
19791
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
19792
+ g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
19793
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
19794
+ showGanttDateIndicators(g, xScale, todayDateObj, null, innerHeight, todayColor);
19795
+ }).on("mouseleave", () => {
19796
+ resetHighlight(g, svg);
19797
+ hideGanttDateIndicators(g);
19798
+ });
19708
19799
  }
19709
19800
  if (resolved.options.dependencies) {
19710
19801
  renderDependencyArrows(g, resolved, taskPositions, groupPositions, collapsedGroups, palette, isDark, isTagMode, lanePositions, collapsedLanes, taskLaneMap);
@@ -19821,10 +19912,10 @@ function renderDependencyArrows(g, resolved, taskPositions, groupPositions, coll
19821
19912
  const path = `M ${sx} ${sy} C ${sx + cpOffset} ${sy}, ${tx - cpOffset} ${ty}, ${tx} ${ty}`;
19822
19913
  const arrowColor = mix(palette.text, palette.bg, 50);
19823
19914
  const isCpArrow = rt.isCriticalPath && targetTask.isCriticalPath;
19824
- g.append("path").attr("class", "gantt-dep-arrow").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-critical-path", isCpArrow ? "true" : null).attr("d", path).attr("fill", "none").attr("stroke", arrowColor).attr("stroke-width", 1.5).attr("opacity", 0.5);
19915
+ g.append("path").attr("class", "gantt-dep-arrow").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-line-number", String(dep.lineNumber)).attr("data-critical-path", isCpArrow ? "true" : null).attr("d", path).attr("fill", "none").attr("stroke", arrowColor).attr("stroke-width", 1.5).attr("opacity", 0.5);
19825
19916
  const headSize = 5;
19826
19917
  const angle = 0;
19827
- g.append("polygon").attr("class", "gantt-dep-arrowhead").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-critical-path", isCpArrow ? "true" : null).attr("points", arrowheadPoints(tx, ty, headSize, angle)).attr("fill", arrowColor).attr("opacity", 0.5);
19918
+ g.append("polygon").attr("class", "gantt-dep-arrowhead").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-line-number", String(dep.lineNumber)).attr("data-critical-path", isCpArrow ? "true" : null).attr("points", arrowheadPoints(tx, ty, headSize, angle)).attr("fill", arrowColor).attr("opacity", 0.5);
19828
19919
  }
19829
19920
  }
19830
19921
  }
@@ -19845,7 +19936,9 @@ function applyCriticalPathHighlight(svg, chartG) {
19845
19936
  el.attr("opacity", el.attr("data-critical-path") === "true" ? 1 : FADE_OPACITY);
19846
19937
  });
19847
19938
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
19939
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
19848
19940
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
19941
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
19849
19942
  chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
19850
19943
  chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").each(function() {
19851
19944
  const el = d3Selection10.select(this);
@@ -19857,7 +19950,9 @@ function resetHighlightAll(svg, chartG) {
19857
19950
  chartG.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
19858
19951
  svg.selectAll(".gantt-task-label").attr("opacity", 1);
19859
19952
  svg.selectAll(".gantt-group-label").attr("opacity", 1);
19953
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
19860
19954
  svg.selectAll(".gantt-lane-header").attr("opacity", 1);
19955
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
19861
19956
  chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", 1);
19862
19957
  chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
19863
19958
  }
@@ -19873,7 +19968,7 @@ function drawSwimlaneIcon(parent, x, y, isActive, palette) {
19873
19968
  }
19874
19969
  return iconG;
19875
19970
  }
19876
- function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
19971
+ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
19877
19972
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
19878
19973
  let visibleGroups;
19879
19974
  if (activeGroupName) {
@@ -19934,7 +20029,8 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
19934
20029
  if (visibleGroups.length > 0) totalW += LEGEND_GROUP_GAP;
19935
20030
  totalW += cpPillW;
19936
20031
  }
19937
- const legendX = chartLeftMargin + (chartInnerWidth - totalW) / 2;
20032
+ const containerWidth = chartLeftMargin + chartInnerWidth + RIGHT_MARGIN;
20033
+ const legendX = (containerWidth - totalW) / 2;
19938
20034
  const legendRow = svg.append("g").attr("class", "gantt-tag-legend-container").attr("transform", `translate(${legendX}, ${legendY})`);
19939
20035
  let cursorX = 0;
19940
20036
  for (let i = 0; i < visibleGroups.length; i++) {
@@ -19946,7 +20042,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
19946
20042
  const pillW = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD + iconReserve;
19947
20043
  const pillH = isActive ? LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2 : LEGEND_HEIGHT;
19948
20044
  const groupW = groupWidths[i];
19949
- const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-tag-legend-group").attr("data-tag-group", group.name).style("cursor", "pointer").on("click", () => {
20045
+ const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-tag-legend-group").attr("data-tag-group", group.name).attr("data-line-number", String(group.lineNumber)).style("cursor", "pointer").on("click", () => {
19950
20046
  if (onToggle) onToggle(group.name);
19951
20047
  });
19952
20048
  if (isActive) {
@@ -19980,7 +20076,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
19980
20076
  let ex = pillXOff + pillW + LEGEND_CAPSULE_PAD + 4;
19981
20077
  for (const entry of entries) {
19982
20078
  const entryValue = entry.value.toLowerCase();
19983
- const entryG = gEl.append("g").attr("class", "gantt-legend-entry").style("cursor", "pointer");
20079
+ const entryG = gEl.append("g").attr("class", "gantt-legend-entry").attr("data-line-number", String(entry.lineNumber)).style("cursor", "pointer");
19984
20080
  entryG.append("circle").attr("cx", ex + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
19985
20081
  entryG.append("text").attr("x", ex + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 2).attr("text-anchor", "start").attr("font-size", `${LEGEND_ENTRY_FONT_SIZE}px`).attr("fill", palette.textMuted).text(entry.value);
19986
20082
  entryG.on("mouseenter", () => {
@@ -20016,9 +20112,11 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
20016
20112
  cursorX += groupW + LEGEND_GROUP_GAP;
20017
20113
  }
20018
20114
  if (hasCriticalPath) {
20115
+ const cpLineNum = optionLineNumbers["critical-path"];
20019
20116
  const cpG = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-legend-critical-path").style("cursor", "pointer").on("click", () => {
20020
20117
  if (onToggleCriticalPath) onToggleCriticalPath();
20021
20118
  });
20119
+ if (cpLineNum) cpG.attr("data-line-number", String(cpLineNum));
20022
20120
  cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", criticalPathActive ? palette.bg : groupBg);
20023
20121
  if (criticalPathActive) {
20024
20122
  cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
@@ -20036,7 +20134,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
20036
20134
  });
20037
20135
  }
20038
20136
  }
20039
- function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20137
+ function renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette) {
20040
20138
  for (let i = 0; i < resolved.eras.length; i++) {
20041
20139
  const era = resolved.eras[i];
20042
20140
  const color = era.color || ERA_COLORS[i % ERA_COLORS.length];
@@ -20047,13 +20145,23 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20047
20145
  const hoverEraOpacity = 0.16;
20048
20146
  const eraStartDate = parseDateStringToDate(era.startDate);
20049
20147
  const eraEndDate = parseDateStringToDate(era.endDate);
20050
- const eraG = g.append("g").attr("class", "gantt-era-group");
20148
+ const eraG = g.append("g").attr("class", "gantt-era-group").attr("data-line-number", String(era.lineNumber));
20051
20149
  const eraRect = eraG.append("rect").attr("class", "gantt-era").attr("x", sx).attr("y", 0).attr("width", ex - sx).attr("height", innerHeight).attr("fill", color).attr("opacity", baseEraOpacity);
20052
- eraG.append("text").attr("class", "gantt-era-label").attr("x", (sx + ex) / 2).attr("y", 12).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", color).attr("opacity", 0.7).attr("pointer-events", "none").text(era.label);
20150
+ eraG.append("text").attr("class", "gantt-era-label").attr("x", (sx + ex) / 2).attr("y", -24).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", color).attr("opacity", 0.7).style("cursor", "pointer").text(era.label);
20053
20151
  eraG.on("mouseenter", () => {
20152
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
20153
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
20154
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20155
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20156
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
20157
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20158
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20159
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20160
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20054
20161
  eraRect.attr("opacity", hoverEraOpacity);
20055
20162
  showGanttDateIndicators(g, xScale, eraStartDate, eraEndDate, innerHeight, color);
20056
20163
  }).on("mouseleave", () => {
20164
+ resetHighlight(g, svg);
20057
20165
  eraRect.attr("opacity", baseEraOpacity);
20058
20166
  hideGanttDateIndicators(g);
20059
20167
  });
@@ -20065,22 +20173,31 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20065
20173
  const diamondSize = 5;
20066
20174
  const labelY = -24;
20067
20175
  const diamondY = labelY + 14;
20068
- const markerG = g.append("g").attr("class", "gantt-marker-group").style("cursor", "pointer");
20176
+ const markerG = g.append("g").attr("class", "gantt-marker-group").attr("data-line-number", String(marker.lineNumber)).style("cursor", "pointer");
20069
20177
  markerG.append("rect").attr("x", mx - 40).attr("y", labelY - 12).attr("width", 80).attr("height", innerHeight - labelY + 12).attr("fill", "transparent").attr("pointer-events", "all");
20070
20178
  markerG.append("text").attr("class", "gantt-marker-label").attr("x", mx).attr("y", labelY).attr("text-anchor", "middle").attr("font-size", "11px").attr("font-weight", "600").attr("fill", color).text(marker.label);
20071
20179
  markerG.append("path").attr("d", `M${mx},${diamondY - diamondSize} l${diamondSize},${diamondSize} l-${diamondSize},${diamondSize} l-${diamondSize},-${diamondSize} Z`).attr("fill", color).attr("opacity", 0.9);
20072
20180
  markerG.append("line").attr("class", "gantt-marker").attr("x1", mx).attr("y1", diamondY + diamondSize).attr("x2", mx).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "6 4").attr("opacity", 0.5);
20073
20181
  const markerLine = markerG.select(".gantt-marker");
20074
- const markerLabel = markerG.select(".gantt-marker-label");
20075
20182
  const markerDiamond = markerG.select("path");
20076
20183
  markerG.on("mouseenter", () => {
20077
- markerLine.attr("opacity", 0);
20078
- markerLabel.attr("opacity", 0);
20184
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
20185
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
20186
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20187
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20188
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
20189
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20190
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20191
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20192
+ g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
20193
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20194
+ markerG.attr("opacity", 1);
20195
+ markerLine.attr("opacity", 0.8);
20079
20196
  markerDiamond.attr("opacity", 0);
20080
- showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color);
20197
+ showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color, { skipStartLine: true });
20081
20198
  }).on("mouseleave", () => {
20199
+ resetHighlight(g, svg);
20082
20200
  markerLine.attr("opacity", 0.5);
20083
- markerLabel.attr("opacity", 1);
20084
20201
  markerDiamond.attr("opacity", 0.9);
20085
20202
  hideGanttDateIndicators(g);
20086
20203
  });
@@ -20094,11 +20211,7 @@ function parseDateStringToDate(s) {
20094
20211
  return new Date(year, month, day);
20095
20212
  }
20096
20213
  function parseDateToFractionalYear(s) {
20097
- const parts = s.split("-").map((p) => parseInt(p, 10));
20098
- const year = parts[0];
20099
- const month = parts.length >= 2 ? parts[1] : 1;
20100
- const day = parts.length >= 3 ? parts[2] : 1;
20101
- return year + (month - 1) / 12 + (day - 1) / 365;
20214
+ return dateToFractionalYear(parseDateStringToDate(s));
20102
20215
  }
20103
20216
  function highlightDeps(g, svg, taskId, resolved) {
20104
20217
  const related = /* @__PURE__ */ new Set([taskId]);
@@ -20132,6 +20245,7 @@ function highlightDeps(g, svg, taskId, resolved) {
20132
20245
  const isRelated = from && related.has(from) || to && related.has(to);
20133
20246
  el.attr("opacity", isRelated ? 0.5 : FADE_OPACITY);
20134
20247
  });
20248
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20135
20249
  }
20136
20250
  function highlightGroup(g, svg, groupName) {
20137
20251
  g.selectAll(".gantt-task").each(function() {
@@ -20154,7 +20268,12 @@ function highlightGroup(g, svg, groupName) {
20154
20268
  const el = d3Selection10.select(this);
20155
20269
  el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
20156
20270
  });
20271
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").each(function() {
20272
+ const el = d3Selection10.select(this);
20273
+ el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
20274
+ });
20157
20275
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20276
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20158
20277
  g.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
20159
20278
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20160
20279
  }
@@ -20181,8 +20300,13 @@ function highlightLane(g, svg, tagKey, laneName) {
20181
20300
  const el = d3Selection10.select(this);
20182
20301
  el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
20183
20302
  });
20303
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").each(function() {
20304
+ const el = d3Selection10.select(this);
20305
+ el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
20306
+ });
20184
20307
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20185
20308
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20309
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20186
20310
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20187
20311
  }
20188
20312
  function highlightTask(g, svg, taskId) {
@@ -20197,7 +20321,9 @@ function highlightTask(g, svg, taskId) {
20197
20321
  });
20198
20322
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20199
20323
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20324
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20200
20325
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20326
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20201
20327
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20202
20328
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20203
20329
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
@@ -20214,7 +20340,9 @@ function highlightMilestone(g, svg, taskId) {
20214
20340
  });
20215
20341
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20216
20342
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20343
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20217
20344
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20345
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20218
20346
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20219
20347
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20220
20348
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
@@ -20233,11 +20361,14 @@ function resetHighlight(g, svg) {
20233
20361
  g.selectAll(".gantt-task, .gantt-milestone").attr("opacity", 1);
20234
20362
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
20235
20363
  svg.selectAll(".gantt-group-label").attr("opacity", 1);
20364
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
20236
20365
  svg.selectAll(".gantt-task-label").attr("opacity", 1);
20237
20366
  svg.selectAll(".gantt-lane-header").attr("opacity", 1);
20367
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
20238
20368
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", 1);
20239
20369
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
20240
20370
  g.selectAll(".gantt-marker-group").attr("opacity", 1);
20371
+ g.selectAll(".gantt-era-group").attr("opacity", 1);
20241
20372
  }
20242
20373
  function buildRowList(resolved, collapsedGroups) {
20243
20374
  const rows = [];
@@ -20391,15 +20522,18 @@ function diamondPoints(cx, cy, size) {
20391
20522
  function formatGanttDate(d) {
20392
20523
  return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
20393
20524
  }
20394
- function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color) {
20525
+ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color, options) {
20395
20526
  g.selectAll(".gantt-scale-tick").attr("opacity", 0.05);
20396
20527
  g.selectAll(".gantt-today").attr("opacity", 0.05);
20528
+ const hg = g.append("g").attr("class", "gantt-hover-date").attr("pointer-events", "none");
20397
20529
  const tickLen = 6;
20398
20530
  const startPos = xScale(dateToFractionalYear(startDate));
20399
20531
  const startLabel = formatGanttDate(startDate);
20400
- g.append("line").attr("class", "gantt-hover-date").attr("x1", startPos).attr("y1", -tickLen).attr("x2", startPos).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4").attr("opacity", 0.6);
20401
- g.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", -tickLen - 4).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
20402
- g.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
20532
+ if (!options?.skipStartLine) {
20533
+ hg.append("line").attr("class", "gantt-hover-date").attr("x1", startPos).attr("y1", -tickLen).attr("x2", startPos).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4").attr("opacity", 0.6);
20534
+ }
20535
+ hg.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", -tickLen - 4).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
20536
+ hg.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
20403
20537
  if (endDate && endDate.getTime() !== startDate.getTime()) {
20404
20538
  const endPos = xScale(dateToFractionalYear(endDate));
20405
20539
  const endLabel = formatGanttDate(endDate);
@@ -20416,15 +20550,15 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
20416
20550
  startAnchor = "middle";
20417
20551
  endAnchor = "middle";
20418
20552
  }
20419
- g.append("line").attr("class", "gantt-hover-date").attr("x1", endPos).attr("y1", -tickLen).attr("x2", endPos).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4").attr("opacity", 0.6);
20420
- g.selectAll("text.gantt-hover-date").each(function() {
20553
+ hg.append("line").attr("class", "gantt-hover-date").attr("x1", endPos).attr("y1", -tickLen).attr("x2", endPos).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4").attr("opacity", 0.6);
20554
+ hg.selectAll("text.gantt-hover-date").each(function() {
20421
20555
  const el = d3Selection10.select(this);
20422
20556
  if (el.text() === startLabel) {
20423
20557
  el.attr("x", startLabelX).attr("text-anchor", startAnchor);
20424
20558
  }
20425
20559
  });
20426
- g.append("text").attr("class", "gantt-hover-date").attr("x", endLabelX).attr("y", -tickLen - 4).attr("text-anchor", endAnchor).attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(endLabel);
20427
- g.append("text").attr("class", "gantt-hover-date").attr("x", endLabelX).attr("y", innerHeight + tickLen + 12).attr("text-anchor", endAnchor).attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(endLabel);
20560
+ hg.append("text").attr("class", "gantt-hover-date").attr("x", endLabelX).attr("y", -tickLen - 4).attr("text-anchor", endAnchor).attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(endLabel);
20561
+ hg.append("text").attr("class", "gantt-hover-date").attr("x", endLabelX).attr("y", innerHeight + tickLen + 12).attr("text-anchor", endAnchor).attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(endLabel);
20428
20562
  }
20429
20563
  }
20430
20564
  function hideGanttDateIndicators(g) {
@@ -20469,7 +20603,7 @@ function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor)
20469
20603
  g.append("text").attr("class", "gantt-scale-tick").attr("x", tick.pos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", textColor).attr("opacity", opacity).text(tick.label);
20470
20604
  }
20471
20605
  }
20472
- var BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, JS_DAY_TO_WEEKDAY2, ERA_COLORS, FADE_OPACITY, MONTH_ABBR;
20606
+ var BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, CHAR_W, LABEL_PAD, LABEL_GAP, BAND_ACCENT_W, BAND_RADIUS, bandClipCounter, JS_DAY_TO_WEEKDAY2, ERA_COLORS, FADE_OPACITY, MONTH_ABBR;
20473
20607
  var init_renderer9 = __esm({
20474
20608
  "src/gantt/renderer.ts"() {
20475
20609
  "use strict";
@@ -20486,6 +20620,12 @@ var init_renderer9 = __esm({
20486
20620
  MIN_LEFT_MARGIN = 120;
20487
20621
  BOTTOM_MARGIN = 40;
20488
20622
  RIGHT_MARGIN = 20;
20623
+ CHAR_W = 6.5;
20624
+ LABEL_PAD = 8;
20625
+ LABEL_GAP = 5;
20626
+ BAND_ACCENT_W = 4;
20627
+ BAND_RADIUS = 4;
20628
+ bandClipCounter = 0;
20489
20629
  JS_DAY_TO_WEEKDAY2 = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
20490
20630
  ERA_COLORS = ["#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#b48ead"];
20491
20631
  FADE_OPACITY = 0.1;
@@ -20588,14 +20728,14 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
20588
20728
  nodePositionMap.set(node.id, node);
20589
20729
  }
20590
20730
  const LABEL_CHAR_W = 7;
20591
- const LABEL_PAD = 8;
20731
+ const LABEL_PAD2 = 8;
20592
20732
  const LABEL_H = 16;
20593
20733
  const PERP_OFFSET = 10;
20594
20734
  const labelPositions = [];
20595
20735
  for (let ei = 0; ei < layout.edges.length; ei++) {
20596
20736
  const edge = layout.edges[ei];
20597
20737
  if (!edge.label) continue;
20598
- const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD;
20738
+ const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
20599
20739
  let lx, ly;
20600
20740
  if (edge.source === edge.target) {
20601
20741
  const node = nodePositionMap.get(edge.source);
@@ -25098,12 +25238,12 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
25098
25238
  };
25099
25239
  const LABEL_MAX_FONT = 48;
25100
25240
  const LABEL_MIN_FONT = 14;
25101
- const LABEL_PAD = 40;
25241
+ const LABEL_PAD2 = 40;
25102
25242
  const CHAR_WIDTH_RATIO3 = 0.6;
25103
25243
  const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
25104
25244
  const quadrantLabelLayout = (text, qw2, qh2) => {
25105
- const availW = qw2 - LABEL_PAD;
25106
- const availH = qh2 - LABEL_PAD;
25245
+ const availW = qw2 - LABEL_PAD2;
25246
+ const availH = qh2 - LABEL_PAD2;
25107
25247
  const words = text.split(/\s+/);
25108
25248
  if (estTextWidth(text, LABEL_MAX_FONT) <= availW) {
25109
25249
  const fs = Math.min(LABEL_MAX_FONT, availH);