@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.cjs CHANGED
@@ -7986,7 +7986,9 @@ function parseGantt(content, palette) {
7986
7986
  criticalPath: false,
7987
7987
  dependencies: false,
7988
7988
  sort: "default",
7989
- defaultSwimlaneGroup: null
7989
+ defaultSwimlaneGroup: null,
7990
+ optionLineNumbers: {},
7991
+ holidaysLineNumber: null
7990
7992
  },
7991
7993
  diagnostics,
7992
7994
  error: null
@@ -8171,6 +8173,7 @@ function parseGantt(content, palette) {
8171
8173
  inHolidaysBlock = true;
8172
8174
  holidaysBlockIndent = indent;
8173
8175
  inHeaderBlock = false;
8176
+ result.options.holidaysLineNumber = lineNumber;
8174
8177
  continue;
8175
8178
  }
8176
8179
  const tagMatch = matchTagBlockHeading(line10);
@@ -8197,7 +8200,8 @@ function parseGantt(content, palette) {
8197
8200
  startDate: eraMatch[1],
8198
8201
  endDate: eraMatch[2],
8199
8202
  label: eraExtracted.label,
8200
- color: eraExtracted.color || null
8203
+ color: eraExtracted.color || null,
8204
+ lineNumber
8201
8205
  });
8202
8206
  inHeaderBlock = false;
8203
8207
  continue;
@@ -8219,6 +8223,7 @@ function parseGantt(content, palette) {
8219
8223
  if (optMatch && isKnownOption(optMatch[1].toLowerCase())) {
8220
8224
  const key = optMatch[1].toLowerCase();
8221
8225
  const value = optMatch[2].trim();
8226
+ result.options.optionLineNumbers[key] = lineNumber;
8222
8227
  switch (key) {
8223
8228
  case "start":
8224
8229
  result.options.start = value;
@@ -16129,7 +16134,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
16129
16134
  }
16130
16135
  const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
16131
16136
  const LABEL_CHAR_W = 7;
16132
- const LABEL_PAD = 8;
16137
+ const LABEL_PAD2 = 8;
16133
16138
  const LABEL_H = 16;
16134
16139
  const PERP_OFFSET = 10;
16135
16140
  const labelPositions = [];
@@ -16138,7 +16143,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
16138
16143
  if (!edge.label || edge.points.length < 2) continue;
16139
16144
  const midIdx = Math.floor(edge.points.length / 2);
16140
16145
  const midPt = edge.points[midIdx];
16141
- const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD;
16146
+ const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
16142
16147
  const prev = edge.points[Math.max(0, midIdx - 1)];
16143
16148
  const next = edge.points[Math.min(edge.points.length - 1, midIdx + 1)];
16144
16149
  const dx = next.x - prev.x;
@@ -19381,8 +19386,46 @@ __export(renderer_exports9, {
19381
19386
  buildTagLaneRowList: () => buildTagLaneRowList,
19382
19387
  renderGantt: () => renderGantt
19383
19388
  });
19389
+ function computeBarLabel(label, x1, barWidth, innerWidth, textColor) {
19390
+ const textWidth = label.length * CHAR_W;
19391
+ const x2 = x1 + barWidth;
19392
+ if (textWidth < barWidth - LABEL_PAD) {
19393
+ return { x: x1 + 6, anchor: "start", fill: textColor, text: label };
19394
+ }
19395
+ if (x2 + LABEL_GAP + textWidth <= innerWidth) {
19396
+ return { x: x2 + LABEL_GAP, anchor: "start", fill: textColor, text: label };
19397
+ }
19398
+ if (x1 - LABEL_GAP - textWidth >= 0) {
19399
+ return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label };
19400
+ }
19401
+ const availWidth = x1 - LABEL_GAP;
19402
+ if (availWidth > CHAR_W * 3) {
19403
+ const maxChars = Math.floor(availWidth / CHAR_W) - 1;
19404
+ return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label.slice(0, maxChars) + "\u2026" };
19405
+ }
19406
+ return null;
19407
+ }
19408
+ function renderLabelBand(svg, y, leftMargin, color, palette, cssPrefix, dataAttr) {
19409
+ const bandX = 5;
19410
+ const bandW = leftMargin - 7;
19411
+ const bandY = y - BAR_H / 2;
19412
+ const clipId = `gantt-band-clip-${bandClipCounter++}`;
19413
+ 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);
19414
+ 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");
19415
+ 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");
19416
+ if (dataAttr) {
19417
+ tint2.attr(dataAttr.key, dataAttr.value);
19418
+ accent.attr(dataAttr.key, dataAttr.value);
19419
+ }
19420
+ }
19421
+ function appendTaskIcon(textEl, label, isMilestone, iconColor, textColor) {
19422
+ const icon = isMilestone ? "\u25C6" : "\u25CF";
19423
+ textEl.append("tspan").attr("fill", iconColor).text(icon);
19424
+ textEl.append("tspan").attr("fill", textColor).text(" " + label);
19425
+ }
19384
19426
  function renderGantt(container, resolved, palette, isDark, options, exportDims) {
19385
19427
  container.innerHTML = "";
19428
+ bandClipCounter = 0;
19386
19429
  if (resolved.tasks.length === 0) return;
19387
19430
  const onClickItem = options?.onClickItem;
19388
19431
  const collapsedGroups = options?.collapsedGroups;
@@ -19401,10 +19444,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19401
19444
  const isTagMode = tagRows !== null;
19402
19445
  const allLabels = isTagMode ? [
19403
19446
  ...rows.filter((r) => r.type === "lane-header").map((r) => r.laneName),
19404
- ...rows.filter((r) => r.type === "task").map((r) => r.task.task.label)
19447
+ ...rows.filter((r) => r.type === "task").map((r) => "\u25CF " + r.task.task.label)
19405
19448
  ] : [
19406
- ...resolved.tasks.map((t) => t.task.label),
19407
- ...resolved.groups.map((g2) => " ".repeat(g2.depth) + g2.name)
19449
+ ...resolved.tasks.map((t) => "\u25CF " + t.task.label),
19450
+ ...resolved.groups.map((g2) => {
19451
+ const px = g2.depth <= 2 ? g2.depth * 14 : 2 * 14 + (g2.depth - 2) * 8;
19452
+ return " ".repeat(Math.ceil(px / 7)) + g2.name;
19453
+ })
19408
19454
  ];
19409
19455
  const maxLabelLen = Math.max(...allLabels.map((l) => l.length), 10);
19410
19456
  const leftMargin = Math.max(MIN_LEFT_MARGIN, maxLabelLen * 7 + 30);
@@ -19413,8 +19459,10 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19413
19459
  const titleHeight = title ? 50 : 20;
19414
19460
  const tagLegendReserve = resolved.tagGroups.length > 0 ? LEGEND_HEIGHT + 8 : 0;
19415
19461
  const topDateLabelReserve = 22;
19462
+ const hasOverheadLabels = resolved.markers.length > 0 || resolved.eras.length > 0;
19463
+ const markerLabelReserve = hasOverheadLabels ? 18 : 0;
19416
19464
  const CONTENT_TOP_PAD = 16;
19417
- const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve;
19465
+ const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve + markerLabelReserve;
19418
19466
  const contentH = isTagMode ? totalRows * (BAR_H + ROW_GAP) : totalRows * (BAR_H + ROW_GAP) + GROUP_GAP2 * resolved.groups.length;
19419
19467
  const innerHeight = CONTENT_TOP_PAD + contentH;
19420
19468
  const outerHeight = marginTop + innerHeight + BOTTOM_MARGIN;
@@ -19442,6 +19490,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19442
19490
  isDark,
19443
19491
  hasCriticalPath,
19444
19492
  criticalPathActive,
19493
+ resolved.options.optionLineNumbers,
19445
19494
  (groupName) => {
19446
19495
  currentActiveGroup = currentActiveGroup?.toLowerCase() === groupName.toLowerCase() ? null : groupName;
19447
19496
  if (onActiveGroupChange) onActiveGroupChange(currentActiveGroup);
@@ -19480,7 +19529,25 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19480
19529
  renderTimeScaleHorizontal(g, xScale, innerWidth, innerHeight, palette.text);
19481
19530
  renderWeekendBands(g, resolved, xScale, innerHeight, palette, isDark);
19482
19531
  renderHolidayBands(g, svg, resolved, xScale, innerHeight, palette, isDark, marginTop - 4, leftMargin, onClickItem);
19483
- renderErasAndMarkers(g, resolved, xScale, innerHeight, palette);
19532
+ renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette);
19533
+ let todayDate = null;
19534
+ let todayX = -1;
19535
+ const todayColor = palette.accent || "#e74c3c";
19536
+ const todayMarkerLineNum = resolved.options.optionLineNumbers["today-marker"];
19537
+ if (resolved.options.todayMarker !== "off") {
19538
+ if (resolved.options.todayMarker === "on") {
19539
+ todayDate = /* @__PURE__ */ new Date();
19540
+ } else {
19541
+ todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
19542
+ }
19543
+ todayX = xScale(dateToFractionalYear(todayDate));
19544
+ if (todayX >= 0 && todayX <= innerWidth) {
19545
+ 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");
19546
+ if (todayMarkerLineNum) todayLine.attr("data-line-number", String(todayMarkerLineNum));
19547
+ 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");
19548
+ if (todayMarkerLineNum) todayLabel.attr("data-line-number", String(todayMarkerLineNum));
19549
+ }
19550
+ }
19484
19551
  const taskPositions = /* @__PURE__ */ new Map();
19485
19552
  const groupPositions = /* @__PURE__ */ new Map();
19486
19553
  const lanePositions = /* @__PURE__ */ new Map();
@@ -19516,6 +19583,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19516
19583
  laneBarWidth = Math.max(lx2 - lx1, 2);
19517
19584
  }
19518
19585
  lanePositions.set(row.laneName, { x1: lx1, x2: lx1 + laneBarWidth, y: yOffset + BAR_H / 2 });
19586
+ renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, laneColor, palette, "lane", { key: "data-lane", value: row.laneName });
19519
19587
  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", () => {
19520
19588
  if (onToggleLane) onToggleLane(row.laneName);
19521
19589
  }).on("mouseenter", () => {
@@ -19541,7 +19609,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19541
19609
  });
19542
19610
  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);
19543
19611
  if (row.aggregateProgress !== null && row.aggregateProgress > 0) {
19544
- 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");
19612
+ 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");
19545
19613
  }
19546
19614
  }
19547
19615
  yOffset += BAR_H + ROW_GAP;
@@ -19552,6 +19620,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19552
19620
  const toggleIcon = isCollapsed ? "\u25BA" : "\u25BC";
19553
19621
  const tagColor = resolveTagColor(group.metadata, resolved.tagGroups, currentActiveGroup, true);
19554
19622
  const groupColor = tagColor && tagColor !== "#999999" ? tagColor : group.color || palette.textMuted;
19623
+ renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, groupColor, palette, "group", { key: "data-group", value: group.name });
19555
19624
  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", () => {
19556
19625
  if (onToggleGroup) onToggleGroup(group.name);
19557
19626
  }).on("mouseenter", () => {
@@ -19561,7 +19630,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19561
19630
  resetHighlight(g, svg);
19562
19631
  hideGanttDateIndicators(g);
19563
19632
  });
19564
- const labelX = 10 + group.depth * 14;
19633
+ const groupIndent = group.depth <= 2 ? group.depth * 14 : 2 * 14 + (group.depth - 2) * 8;
19634
+ const labelX = 10 + groupIndent;
19565
19635
  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)}%` : ""));
19566
19636
  const gStart = dateToFractionalYear(group.startDate);
19567
19637
  const gEnd = dateToFractionalYear(group.endDate);
@@ -19579,7 +19649,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19579
19649
  });
19580
19650
  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);
19581
19651
  if (group.progress !== null && group.progress > 0) {
19582
- 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);
19652
+ 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);
19653
+ }
19654
+ const summaryLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
19655
+ const summaryPlacement = computeBarLabel(summaryLabel, gx1, barWidth, innerWidth, palette.text);
19656
+ if (summaryPlacement) {
19657
+ 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);
19583
19658
  }
19584
19659
  groupPositions.set(group.name, { x1: gx1, x2: gx1 + barWidth, y: yOffset + BAR_H / 2 });
19585
19660
  } else {
@@ -19594,7 +19669,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19594
19669
  });
19595
19670
  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);
19596
19671
  if (group.progress !== null && group.progress > 0) {
19597
- 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);
19672
+ 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);
19673
+ }
19674
+ const expandedLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
19675
+ const expandedPlacement = computeBarLabel(expandedLabel, gx1, groupBarWidth, innerWidth, palette.text);
19676
+ if (expandedPlacement) {
19677
+ 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);
19598
19678
  }
19599
19679
  }
19600
19680
  }
@@ -19602,9 +19682,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19602
19682
  } else if (row.type === "task") {
19603
19683
  const rt = row.task;
19604
19684
  const task = rt.task;
19605
- const taskLabelX = isTagMode ? 20 : 6 + rt.groupPath.length * 14;
19685
+ const barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
19686
+ const depth = rt.groupPath.length;
19687
+ const indent = depth <= 2 ? depth * 14 : 2 * 14 + (depth - 2) * 8;
19688
+ const taskLabelX = isTagMode ? 20 : 6 + indent;
19606
19689
  const topGroup = rt.groupPath.length > 0 ? rt.groupPath[0] : null;
19607
- 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", () => {
19690
+ 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", () => {
19608
19691
  if (onClickItem) onClickItem(task.lineNumber);
19609
19692
  }).on("mouseenter", () => {
19610
19693
  if (rt.isMilestone) {
@@ -19615,13 +19698,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19615
19698
  }).on("mouseleave", () => {
19616
19699
  resetHighlight(g, svg);
19617
19700
  });
19701
+ appendTaskIcon(taskLabel, task.label, rt.isMilestone, barColor, palette.text);
19618
19702
  for (const [key, value] of Object.entries(rt.effectiveMetadata)) {
19619
19703
  taskLabel.attr(`data-tag-${key}`, value.toLowerCase());
19620
19704
  }
19621
19705
  if (rt.isCriticalPath) {
19622
19706
  taskLabel.attr("data-critical-path", "true");
19623
19707
  }
19624
- let barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
19625
19708
  if (rt.isMilestone) {
19626
19709
  const mx = xScale(dateToFractionalYear(rt.startDate));
19627
19710
  const my = yOffset + BAR_H / 2;
@@ -19699,32 +19782,40 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
19699
19782
  progGrad.append("stop").attr("offset", "100%").attr("stop-color", barColor).attr("stop-opacity", 0);
19700
19783
  progressFill = `url(#${progGradId})`;
19701
19784
  }
19702
- 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);
19785
+ 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);
19703
19786
  }
19704
19787
  if (rt.isCriticalPath) {
19705
19788
  taskG.attr("data-critical-path", "true");
19706
19789
  }
19707
- const textWidth = task.label.length * 6.5;
19708
- if (textWidth < barWidth - 8) {
19709
- 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);
19790
+ const labelPlacement = computeBarLabel(task.label, x1, barWidth, innerWidth, palette.text);
19791
+ if (labelPlacement) {
19792
+ 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);
19710
19793
  }
19711
19794
  taskPositions.set(task.id, { x1, x2: x1 + barWidth, y: yOffset + BAR_H / 2 });
19712
19795
  }
19713
19796
  yOffset += BAR_H + ROW_GAP;
19714
19797
  }
19715
19798
  }
19716
- if (resolved.options.todayMarker !== "off") {
19717
- let todayDate;
19718
- if (resolved.options.todayMarker === "on") {
19719
- todayDate = /* @__PURE__ */ new Date();
19720
- } else {
19721
- todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
19722
- }
19723
- const todayX = xScale(dateToFractionalYear(todayDate));
19724
- if (todayX >= 0 && todayX <= innerWidth) {
19725
- 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);
19726
- 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");
19727
- }
19799
+ if (todayDate && todayX >= 0 && todayX <= innerWidth) {
19800
+ const todayHoverG = g.append("g").attr("class", "gantt-today-hover").style("cursor", "pointer");
19801
+ todayHoverG.append("rect").attr("x", todayX - 10).attr("y", -6).attr("width", 20).attr("height", innerHeight + 16).attr("fill", "transparent").attr("pointer-events", "all");
19802
+ const todayDateObj = todayDate;
19803
+ todayHoverG.on("mouseenter", () => {
19804
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
19805
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
19806
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
19807
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
19808
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
19809
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
19810
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
19811
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
19812
+ g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
19813
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
19814
+ showGanttDateIndicators(g, xScale, todayDateObj, null, innerHeight, todayColor);
19815
+ }).on("mouseleave", () => {
19816
+ resetHighlight(g, svg);
19817
+ hideGanttDateIndicators(g);
19818
+ });
19728
19819
  }
19729
19820
  if (resolved.options.dependencies) {
19730
19821
  renderDependencyArrows(g, resolved, taskPositions, groupPositions, collapsedGroups, palette, isDark, isTagMode, lanePositions, collapsedLanes, taskLaneMap);
@@ -19841,10 +19932,10 @@ function renderDependencyArrows(g, resolved, taskPositions, groupPositions, coll
19841
19932
  const path = `M ${sx} ${sy} C ${sx + cpOffset} ${sy}, ${tx - cpOffset} ${ty}, ${tx} ${ty}`;
19842
19933
  const arrowColor = mix(palette.text, palette.bg, 50);
19843
19934
  const isCpArrow = rt.isCriticalPath && targetTask.isCriticalPath;
19844
- 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);
19935
+ 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);
19845
19936
  const headSize = 5;
19846
19937
  const angle = 0;
19847
- 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);
19938
+ 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);
19848
19939
  }
19849
19940
  }
19850
19941
  }
@@ -19865,7 +19956,9 @@ function applyCriticalPathHighlight(svg, chartG) {
19865
19956
  el.attr("opacity", el.attr("data-critical-path") === "true" ? 1 : FADE_OPACITY);
19866
19957
  });
19867
19958
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
19959
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
19868
19960
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
19961
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
19869
19962
  chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
19870
19963
  chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").each(function() {
19871
19964
  const el = d3Selection10.select(this);
@@ -19877,7 +19970,9 @@ function resetHighlightAll(svg, chartG) {
19877
19970
  chartG.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
19878
19971
  svg.selectAll(".gantt-task-label").attr("opacity", 1);
19879
19972
  svg.selectAll(".gantt-group-label").attr("opacity", 1);
19973
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
19880
19974
  svg.selectAll(".gantt-lane-header").attr("opacity", 1);
19975
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
19881
19976
  chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", 1);
19882
19977
  chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
19883
19978
  }
@@ -19893,7 +19988,7 @@ function drawSwimlaneIcon(parent, x, y, isActive, palette) {
19893
19988
  }
19894
19989
  return iconG;
19895
19990
  }
19896
- function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
19991
+ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
19897
19992
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
19898
19993
  let visibleGroups;
19899
19994
  if (activeGroupName) {
@@ -19954,7 +20049,8 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
19954
20049
  if (visibleGroups.length > 0) totalW += LEGEND_GROUP_GAP;
19955
20050
  totalW += cpPillW;
19956
20051
  }
19957
- const legendX = chartLeftMargin + (chartInnerWidth - totalW) / 2;
20052
+ const containerWidth = chartLeftMargin + chartInnerWidth + RIGHT_MARGIN;
20053
+ const legendX = (containerWidth - totalW) / 2;
19958
20054
  const legendRow = svg.append("g").attr("class", "gantt-tag-legend-container").attr("transform", `translate(${legendX}, ${legendY})`);
19959
20055
  let cursorX = 0;
19960
20056
  for (let i = 0; i < visibleGroups.length; i++) {
@@ -19966,7 +20062,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
19966
20062
  const pillW = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD + iconReserve;
19967
20063
  const pillH = isActive ? LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2 : LEGEND_HEIGHT;
19968
20064
  const groupW = groupWidths[i];
19969
- 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", () => {
20065
+ 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", () => {
19970
20066
  if (onToggle) onToggle(group.name);
19971
20067
  });
19972
20068
  if (isActive) {
@@ -20000,7 +20096,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
20000
20096
  let ex = pillXOff + pillW + LEGEND_CAPSULE_PAD + 4;
20001
20097
  for (const entry of entries) {
20002
20098
  const entryValue = entry.value.toLowerCase();
20003
- const entryG = gEl.append("g").attr("class", "gantt-legend-entry").style("cursor", "pointer");
20099
+ const entryG = gEl.append("g").attr("class", "gantt-legend-entry").attr("data-line-number", String(entry.lineNumber)).style("cursor", "pointer");
20004
20100
  entryG.append("circle").attr("cx", ex + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
20005
20101
  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);
20006
20102
  entryG.on("mouseenter", () => {
@@ -20036,9 +20132,11 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
20036
20132
  cursorX += groupW + LEGEND_GROUP_GAP;
20037
20133
  }
20038
20134
  if (hasCriticalPath) {
20135
+ const cpLineNum = optionLineNumbers["critical-path"];
20039
20136
  const cpG = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-legend-critical-path").style("cursor", "pointer").on("click", () => {
20040
20137
  if (onToggleCriticalPath) onToggleCriticalPath();
20041
20138
  });
20139
+ if (cpLineNum) cpG.attr("data-line-number", String(cpLineNum));
20042
20140
  cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", criticalPathActive ? palette.bg : groupBg);
20043
20141
  if (criticalPathActive) {
20044
20142
  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);
@@ -20056,7 +20154,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
20056
20154
  });
20057
20155
  }
20058
20156
  }
20059
- function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20157
+ function renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette) {
20060
20158
  for (let i = 0; i < resolved.eras.length; i++) {
20061
20159
  const era = resolved.eras[i];
20062
20160
  const color = era.color || ERA_COLORS[i % ERA_COLORS.length];
@@ -20067,13 +20165,23 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20067
20165
  const hoverEraOpacity = 0.16;
20068
20166
  const eraStartDate = parseDateStringToDate(era.startDate);
20069
20167
  const eraEndDate = parseDateStringToDate(era.endDate);
20070
- const eraG = g.append("g").attr("class", "gantt-era-group");
20168
+ const eraG = g.append("g").attr("class", "gantt-era-group").attr("data-line-number", String(era.lineNumber));
20071
20169
  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);
20072
- 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);
20170
+ 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);
20073
20171
  eraG.on("mouseenter", () => {
20172
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
20173
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
20174
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20175
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20176
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
20177
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20178
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20179
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20180
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20074
20181
  eraRect.attr("opacity", hoverEraOpacity);
20075
20182
  showGanttDateIndicators(g, xScale, eraStartDate, eraEndDate, innerHeight, color);
20076
20183
  }).on("mouseleave", () => {
20184
+ resetHighlight(g, svg);
20077
20185
  eraRect.attr("opacity", baseEraOpacity);
20078
20186
  hideGanttDateIndicators(g);
20079
20187
  });
@@ -20085,22 +20193,31 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
20085
20193
  const diamondSize = 5;
20086
20194
  const labelY = -24;
20087
20195
  const diamondY = labelY + 14;
20088
- const markerG = g.append("g").attr("class", "gantt-marker-group").style("cursor", "pointer");
20196
+ const markerG = g.append("g").attr("class", "gantt-marker-group").attr("data-line-number", String(marker.lineNumber)).style("cursor", "pointer");
20089
20197
  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");
20090
20198
  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);
20091
20199
  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);
20092
20200
  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);
20093
20201
  const markerLine = markerG.select(".gantt-marker");
20094
- const markerLabel = markerG.select(".gantt-marker-label");
20095
20202
  const markerDiamond = markerG.select("path");
20096
20203
  markerG.on("mouseenter", () => {
20097
- markerLine.attr("opacity", 0);
20098
- markerLabel.attr("opacity", 0);
20204
+ g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
20205
+ g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
20206
+ g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20207
+ svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20208
+ svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
20209
+ svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20210
+ g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20211
+ g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20212
+ g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
20213
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20214
+ markerG.attr("opacity", 1);
20215
+ markerLine.attr("opacity", 0.8);
20099
20216
  markerDiamond.attr("opacity", 0);
20100
- showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color);
20217
+ showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color, { skipStartLine: true });
20101
20218
  }).on("mouseleave", () => {
20219
+ resetHighlight(g, svg);
20102
20220
  markerLine.attr("opacity", 0.5);
20103
- markerLabel.attr("opacity", 1);
20104
20221
  markerDiamond.attr("opacity", 0.9);
20105
20222
  hideGanttDateIndicators(g);
20106
20223
  });
@@ -20114,11 +20231,7 @@ function parseDateStringToDate(s) {
20114
20231
  return new Date(year, month, day);
20115
20232
  }
20116
20233
  function parseDateToFractionalYear(s) {
20117
- const parts = s.split("-").map((p) => parseInt(p, 10));
20118
- const year = parts[0];
20119
- const month = parts.length >= 2 ? parts[1] : 1;
20120
- const day = parts.length >= 3 ? parts[2] : 1;
20121
- return year + (month - 1) / 12 + (day - 1) / 365;
20234
+ return dateToFractionalYear(parseDateStringToDate(s));
20122
20235
  }
20123
20236
  function highlightDeps(g, svg, taskId, resolved) {
20124
20237
  const related = /* @__PURE__ */ new Set([taskId]);
@@ -20152,6 +20265,7 @@ function highlightDeps(g, svg, taskId, resolved) {
20152
20265
  const isRelated = from && related.has(from) || to && related.has(to);
20153
20266
  el.attr("opacity", isRelated ? 0.5 : FADE_OPACITY);
20154
20267
  });
20268
+ g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20155
20269
  }
20156
20270
  function highlightGroup(g, svg, groupName) {
20157
20271
  g.selectAll(".gantt-task").each(function() {
@@ -20174,7 +20288,12 @@ function highlightGroup(g, svg, groupName) {
20174
20288
  const el = d3Selection10.select(this);
20175
20289
  el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
20176
20290
  });
20291
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").each(function() {
20292
+ const el = d3Selection10.select(this);
20293
+ el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
20294
+ });
20177
20295
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20296
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20178
20297
  g.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
20179
20298
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20180
20299
  }
@@ -20201,8 +20320,13 @@ function highlightLane(g, svg, tagKey, laneName) {
20201
20320
  const el = d3Selection10.select(this);
20202
20321
  el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
20203
20322
  });
20323
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").each(function() {
20324
+ const el = d3Selection10.select(this);
20325
+ el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
20326
+ });
20204
20327
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20205
20328
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20329
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20206
20330
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
20207
20331
  }
20208
20332
  function highlightTask(g, svg, taskId) {
@@ -20217,7 +20341,9 @@ function highlightTask(g, svg, taskId) {
20217
20341
  });
20218
20342
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20219
20343
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20344
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20220
20345
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20346
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20221
20347
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20222
20348
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20223
20349
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
@@ -20234,7 +20360,9 @@ function highlightMilestone(g, svg, taskId) {
20234
20360
  });
20235
20361
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
20236
20362
  svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
20363
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
20237
20364
  svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
20365
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
20238
20366
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
20239
20367
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
20240
20368
  g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
@@ -20253,11 +20381,14 @@ function resetHighlight(g, svg) {
20253
20381
  g.selectAll(".gantt-task, .gantt-milestone").attr("opacity", 1);
20254
20382
  g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
20255
20383
  svg.selectAll(".gantt-group-label").attr("opacity", 1);
20384
+ svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
20256
20385
  svg.selectAll(".gantt-task-label").attr("opacity", 1);
20257
20386
  svg.selectAll(".gantt-lane-header").attr("opacity", 1);
20387
+ svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
20258
20388
  g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", 1);
20259
20389
  g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
20260
20390
  g.selectAll(".gantt-marker-group").attr("opacity", 1);
20391
+ g.selectAll(".gantt-era-group").attr("opacity", 1);
20261
20392
  }
20262
20393
  function buildRowList(resolved, collapsedGroups) {
20263
20394
  const rows = [];
@@ -20411,15 +20542,18 @@ function diamondPoints(cx, cy, size) {
20411
20542
  function formatGanttDate(d) {
20412
20543
  return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
20413
20544
  }
20414
- function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color) {
20545
+ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color, options) {
20415
20546
  g.selectAll(".gantt-scale-tick").attr("opacity", 0.05);
20416
20547
  g.selectAll(".gantt-today").attr("opacity", 0.05);
20548
+ const hg = g.append("g").attr("class", "gantt-hover-date").attr("pointer-events", "none");
20417
20549
  const tickLen = 6;
20418
20550
  const startPos = xScale(dateToFractionalYear(startDate));
20419
20551
  const startLabel = formatGanttDate(startDate);
20420
- 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);
20421
- 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);
20422
- 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);
20552
+ if (!options?.skipStartLine) {
20553
+ 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);
20554
+ }
20555
+ 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);
20556
+ 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);
20423
20557
  if (endDate && endDate.getTime() !== startDate.getTime()) {
20424
20558
  const endPos = xScale(dateToFractionalYear(endDate));
20425
20559
  const endLabel = formatGanttDate(endDate);
@@ -20436,15 +20570,15 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
20436
20570
  startAnchor = "middle";
20437
20571
  endAnchor = "middle";
20438
20572
  }
20439
- 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);
20440
- g.selectAll("text.gantt-hover-date").each(function() {
20573
+ 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);
20574
+ hg.selectAll("text.gantt-hover-date").each(function() {
20441
20575
  const el = d3Selection10.select(this);
20442
20576
  if (el.text() === startLabel) {
20443
20577
  el.attr("x", startLabelX).attr("text-anchor", startAnchor);
20444
20578
  }
20445
20579
  });
20446
- 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);
20447
- 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);
20580
+ 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);
20581
+ 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);
20448
20582
  }
20449
20583
  }
20450
20584
  function hideGanttDateIndicators(g) {
@@ -20489,7 +20623,7 @@ function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor)
20489
20623
  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);
20490
20624
  }
20491
20625
  }
20492
- var d3Scale, d3Selection10, 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;
20626
+ var d3Scale, d3Selection10, 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;
20493
20627
  var init_renderer9 = __esm({
20494
20628
  "src/gantt/renderer.ts"() {
20495
20629
  "use strict";
@@ -20508,6 +20642,12 @@ var init_renderer9 = __esm({
20508
20642
  MIN_LEFT_MARGIN = 120;
20509
20643
  BOTTOM_MARGIN = 40;
20510
20644
  RIGHT_MARGIN = 20;
20645
+ CHAR_W = 6.5;
20646
+ LABEL_PAD = 8;
20647
+ LABEL_GAP = 5;
20648
+ BAND_ACCENT_W = 4;
20649
+ BAND_RADIUS = 4;
20650
+ bandClipCounter = 0;
20511
20651
  JS_DAY_TO_WEEKDAY2 = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
20512
20652
  ERA_COLORS = ["#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#b48ead"];
20513
20653
  FADE_OPACITY = 0.1;
@@ -20608,14 +20748,14 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
20608
20748
  nodePositionMap.set(node.id, node);
20609
20749
  }
20610
20750
  const LABEL_CHAR_W = 7;
20611
- const LABEL_PAD = 8;
20751
+ const LABEL_PAD2 = 8;
20612
20752
  const LABEL_H = 16;
20613
20753
  const PERP_OFFSET = 10;
20614
20754
  const labelPositions = [];
20615
20755
  for (let ei = 0; ei < layout.edges.length; ei++) {
20616
20756
  const edge = layout.edges[ei];
20617
20757
  if (!edge.label) continue;
20618
- const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD;
20758
+ const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
20619
20759
  let lx, ly;
20620
20760
  if (edge.source === edge.target) {
20621
20761
  const node = nodePositionMap.get(edge.source);
@@ -25115,12 +25255,12 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
25115
25255
  };
25116
25256
  const LABEL_MAX_FONT = 48;
25117
25257
  const LABEL_MIN_FONT = 14;
25118
- const LABEL_PAD = 40;
25258
+ const LABEL_PAD2 = 40;
25119
25259
  const CHAR_WIDTH_RATIO3 = 0.6;
25120
25260
  const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
25121
25261
  const quadrantLabelLayout = (text, qw2, qh2) => {
25122
- const availW = qw2 - LABEL_PAD;
25123
- const availH = qh2 - LABEL_PAD;
25262
+ const availW = qw2 - LABEL_PAD2;
25263
+ const availH = qh2 - LABEL_PAD2;
25124
25264
  const words = text.split(/\s+/);
25125
25265
  if (estTextWidth(text, LABEL_MAX_FONT) <= availW) {
25126
25266
  const fs = Math.min(LABEL_MAX_FONT, availH);