@diagrammo/dgmo 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +165 -165
- package/dist/index.cjs +231 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +231 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/d3.ts +2 -0
- package/src/gantt/parser.ts +5 -0
- package/src/gantt/renderer.ts +353 -87
- package/src/gantt/types.ts +4 -0
- package/src/initiative-status/renderer.ts +41 -9
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;
|
|
@@ -13184,6 +13189,9 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, opti
|
|
|
13184
13189
|
const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
|
|
13185
13190
|
const groupW = isActive ? lg.width : pillW;
|
|
13186
13191
|
const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "is-legend-group").attr("data-legend-group", lg.key).style("cursor", "pointer");
|
|
13192
|
+
if (!isActive) {
|
|
13193
|
+
gEl.attr("data-export-ignore", "true");
|
|
13194
|
+
}
|
|
13187
13195
|
if (isActive) {
|
|
13188
13196
|
gEl.append("rect").attr("width", groupW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
13189
13197
|
}
|
|
@@ -13196,17 +13204,32 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, opti
|
|
|
13196
13204
|
gEl.append("text").attr("x", pillXOff + pillW / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).text(lg.name);
|
|
13197
13205
|
if (isActive) {
|
|
13198
13206
|
const hiddenSet = !lg.isStatus ? hiddenTagValues?.get(lg.key) : void 0;
|
|
13199
|
-
|
|
13207
|
+
const entryStartX = pillXOff + pillW + 4;
|
|
13208
|
+
const entryData = [];
|
|
13209
|
+
let estimatedX = entryStartX;
|
|
13200
13210
|
for (const entry of lg.entries) {
|
|
13201
13211
|
const isHidden = hiddenSet?.has(entry.value) ?? false;
|
|
13202
|
-
const
|
|
13212
|
+
const estimatedTextW = entry.label.length * LEGEND_ENTRY_FONT_W;
|
|
13213
|
+
const entryG = gEl.append("g").attr("data-legend-entry", entry.value).attr("transform", `translate(${estimatedX}, 0)`).style("cursor", "pointer");
|
|
13214
|
+
const entryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
13215
|
+
entryG.append("rect").attr("x", -2).attr("y", 0).attr("width", entryW + 4).attr("height", LEGEND_HEIGHT).attr("fill", "transparent");
|
|
13203
13216
|
if (isHidden) {
|
|
13204
|
-
entryG.append("circle").attr("cx",
|
|
13217
|
+
entryG.append("circle").attr("cx", LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", "none").attr("stroke", entry.color).attr("stroke-width", 1.2).attr("opacity", 0.5);
|
|
13205
13218
|
} else {
|
|
13206
|
-
entryG.append("circle").attr("cx",
|
|
13219
|
+
entryG.append("circle").attr("cx", LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
13207
13220
|
}
|
|
13208
|
-
entryG.append("text").attr("x",
|
|
13209
|
-
|
|
13221
|
+
const textEl = entryG.append("text").attr("x", LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).attr("font-family", FONT_FAMILY).attr("opacity", isHidden ? 0.4 : 1).attr("text-decoration", isHidden ? "line-through" : "none").text(entry.label);
|
|
13222
|
+
entryData.push({ g: entryG, textEl: textEl.node(), estimatedW: estimatedTextW });
|
|
13223
|
+
estimatedX += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
13224
|
+
}
|
|
13225
|
+
let reflowX = entryStartX;
|
|
13226
|
+
for (const ed of entryData) {
|
|
13227
|
+
const measuredW = ed.textEl.getComputedTextLength?.() ?? 0;
|
|
13228
|
+
const textW = measuredW > 0 ? measuredW : ed.estimatedW;
|
|
13229
|
+
ed.g.attr("transform", `translate(${reflowX}, 0)`);
|
|
13230
|
+
const actualEntryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + textW + LEGEND_ENTRY_TRAIL;
|
|
13231
|
+
ed.g.select("rect").attr("width", actualEntryW + 4);
|
|
13232
|
+
reflowX += actualEntryW;
|
|
13210
13233
|
}
|
|
13211
13234
|
}
|
|
13212
13235
|
cursorX += groupW + LEGEND_GROUP_GAP;
|
|
@@ -16129,7 +16152,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
16129
16152
|
}
|
|
16130
16153
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
16131
16154
|
const LABEL_CHAR_W = 7;
|
|
16132
|
-
const
|
|
16155
|
+
const LABEL_PAD2 = 8;
|
|
16133
16156
|
const LABEL_H = 16;
|
|
16134
16157
|
const PERP_OFFSET = 10;
|
|
16135
16158
|
const labelPositions = [];
|
|
@@ -16138,7 +16161,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
16138
16161
|
if (!edge.label || edge.points.length < 2) continue;
|
|
16139
16162
|
const midIdx = Math.floor(edge.points.length / 2);
|
|
16140
16163
|
const midPt = edge.points[midIdx];
|
|
16141
|
-
const bgW = edge.label.length * LABEL_CHAR_W +
|
|
16164
|
+
const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
|
|
16142
16165
|
const prev = edge.points[Math.max(0, midIdx - 1)];
|
|
16143
16166
|
const next = edge.points[Math.min(edge.points.length - 1, midIdx + 1)];
|
|
16144
16167
|
const dx = next.x - prev.x;
|
|
@@ -19381,8 +19404,46 @@ __export(renderer_exports9, {
|
|
|
19381
19404
|
buildTagLaneRowList: () => buildTagLaneRowList,
|
|
19382
19405
|
renderGantt: () => renderGantt
|
|
19383
19406
|
});
|
|
19407
|
+
function computeBarLabel(label, x1, barWidth, innerWidth, textColor) {
|
|
19408
|
+
const textWidth = label.length * CHAR_W;
|
|
19409
|
+
const x2 = x1 + barWidth;
|
|
19410
|
+
if (textWidth < barWidth - LABEL_PAD) {
|
|
19411
|
+
return { x: x1 + 6, anchor: "start", fill: textColor, text: label };
|
|
19412
|
+
}
|
|
19413
|
+
if (x2 + LABEL_GAP + textWidth <= innerWidth) {
|
|
19414
|
+
return { x: x2 + LABEL_GAP, anchor: "start", fill: textColor, text: label };
|
|
19415
|
+
}
|
|
19416
|
+
if (x1 - LABEL_GAP - textWidth >= 0) {
|
|
19417
|
+
return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label };
|
|
19418
|
+
}
|
|
19419
|
+
const availWidth = x1 - LABEL_GAP;
|
|
19420
|
+
if (availWidth > CHAR_W * 3) {
|
|
19421
|
+
const maxChars = Math.floor(availWidth / CHAR_W) - 1;
|
|
19422
|
+
return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label.slice(0, maxChars) + "\u2026" };
|
|
19423
|
+
}
|
|
19424
|
+
return null;
|
|
19425
|
+
}
|
|
19426
|
+
function renderLabelBand(svg, y, leftMargin, color, palette, cssPrefix, dataAttr) {
|
|
19427
|
+
const bandX = 5;
|
|
19428
|
+
const bandW = leftMargin - 7;
|
|
19429
|
+
const bandY = y - BAR_H / 2;
|
|
19430
|
+
const clipId = `gantt-band-clip-${bandClipCounter++}`;
|
|
19431
|
+
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);
|
|
19432
|
+
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");
|
|
19433
|
+
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");
|
|
19434
|
+
if (dataAttr) {
|
|
19435
|
+
tint2.attr(dataAttr.key, dataAttr.value);
|
|
19436
|
+
accent.attr(dataAttr.key, dataAttr.value);
|
|
19437
|
+
}
|
|
19438
|
+
}
|
|
19439
|
+
function appendTaskIcon(textEl, label, isMilestone, iconColor, textColor) {
|
|
19440
|
+
const icon = isMilestone ? "\u25C6" : "\u25CF";
|
|
19441
|
+
textEl.append("tspan").attr("fill", iconColor).text(icon);
|
|
19442
|
+
textEl.append("tspan").attr("fill", textColor).text(" " + label);
|
|
19443
|
+
}
|
|
19384
19444
|
function renderGantt(container, resolved, palette, isDark, options, exportDims) {
|
|
19385
19445
|
container.innerHTML = "";
|
|
19446
|
+
bandClipCounter = 0;
|
|
19386
19447
|
if (resolved.tasks.length === 0) return;
|
|
19387
19448
|
const onClickItem = options?.onClickItem;
|
|
19388
19449
|
const collapsedGroups = options?.collapsedGroups;
|
|
@@ -19401,10 +19462,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19401
19462
|
const isTagMode = tagRows !== null;
|
|
19402
19463
|
const allLabels = isTagMode ? [
|
|
19403
19464
|
...rows.filter((r) => r.type === "lane-header").map((r) => r.laneName),
|
|
19404
|
-
...rows.filter((r) => r.type === "task").map((r) => r.task.task.label)
|
|
19465
|
+
...rows.filter((r) => r.type === "task").map((r) => "\u25CF " + r.task.task.label)
|
|
19405
19466
|
] : [
|
|
19406
|
-
...resolved.tasks.map((t) => t.task.label),
|
|
19407
|
-
...resolved.groups.map((g2) =>
|
|
19467
|
+
...resolved.tasks.map((t) => "\u25CF " + t.task.label),
|
|
19468
|
+
...resolved.groups.map((g2) => {
|
|
19469
|
+
const px = g2.depth <= 2 ? g2.depth * 14 : 2 * 14 + (g2.depth - 2) * 8;
|
|
19470
|
+
return " ".repeat(Math.ceil(px / 7)) + g2.name;
|
|
19471
|
+
})
|
|
19408
19472
|
];
|
|
19409
19473
|
const maxLabelLen = Math.max(...allLabels.map((l) => l.length), 10);
|
|
19410
19474
|
const leftMargin = Math.max(MIN_LEFT_MARGIN, maxLabelLen * 7 + 30);
|
|
@@ -19413,8 +19477,10 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19413
19477
|
const titleHeight = title ? 50 : 20;
|
|
19414
19478
|
const tagLegendReserve = resolved.tagGroups.length > 0 ? LEGEND_HEIGHT + 8 : 0;
|
|
19415
19479
|
const topDateLabelReserve = 22;
|
|
19480
|
+
const hasOverheadLabels = resolved.markers.length > 0 || resolved.eras.length > 0;
|
|
19481
|
+
const markerLabelReserve = hasOverheadLabels ? 18 : 0;
|
|
19416
19482
|
const CONTENT_TOP_PAD = 16;
|
|
19417
|
-
const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve;
|
|
19483
|
+
const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve + markerLabelReserve;
|
|
19418
19484
|
const contentH = isTagMode ? totalRows * (BAR_H + ROW_GAP) : totalRows * (BAR_H + ROW_GAP) + GROUP_GAP2 * resolved.groups.length;
|
|
19419
19485
|
const innerHeight = CONTENT_TOP_PAD + contentH;
|
|
19420
19486
|
const outerHeight = marginTop + innerHeight + BOTTOM_MARGIN;
|
|
@@ -19442,6 +19508,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19442
19508
|
isDark,
|
|
19443
19509
|
hasCriticalPath,
|
|
19444
19510
|
criticalPathActive,
|
|
19511
|
+
resolved.options.optionLineNumbers,
|
|
19445
19512
|
(groupName) => {
|
|
19446
19513
|
currentActiveGroup = currentActiveGroup?.toLowerCase() === groupName.toLowerCase() ? null : groupName;
|
|
19447
19514
|
if (onActiveGroupChange) onActiveGroupChange(currentActiveGroup);
|
|
@@ -19480,7 +19547,25 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19480
19547
|
renderTimeScaleHorizontal(g, xScale, innerWidth, innerHeight, palette.text);
|
|
19481
19548
|
renderWeekendBands(g, resolved, xScale, innerHeight, palette, isDark);
|
|
19482
19549
|
renderHolidayBands(g, svg, resolved, xScale, innerHeight, palette, isDark, marginTop - 4, leftMargin, onClickItem);
|
|
19483
|
-
renderErasAndMarkers(g, resolved, xScale, innerHeight, palette);
|
|
19550
|
+
renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette);
|
|
19551
|
+
let todayDate = null;
|
|
19552
|
+
let todayX = -1;
|
|
19553
|
+
const todayColor = palette.accent || "#e74c3c";
|
|
19554
|
+
const todayMarkerLineNum = resolved.options.optionLineNumbers["today-marker"];
|
|
19555
|
+
if (resolved.options.todayMarker !== "off") {
|
|
19556
|
+
if (resolved.options.todayMarker === "on") {
|
|
19557
|
+
todayDate = /* @__PURE__ */ new Date();
|
|
19558
|
+
} else {
|
|
19559
|
+
todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
|
|
19560
|
+
}
|
|
19561
|
+
todayX = xScale(dateToFractionalYear(todayDate));
|
|
19562
|
+
if (todayX >= 0 && todayX <= innerWidth) {
|
|
19563
|
+
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");
|
|
19564
|
+
if (todayMarkerLineNum) todayLine.attr("data-line-number", String(todayMarkerLineNum));
|
|
19565
|
+
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");
|
|
19566
|
+
if (todayMarkerLineNum) todayLabel.attr("data-line-number", String(todayMarkerLineNum));
|
|
19567
|
+
}
|
|
19568
|
+
}
|
|
19484
19569
|
const taskPositions = /* @__PURE__ */ new Map();
|
|
19485
19570
|
const groupPositions = /* @__PURE__ */ new Map();
|
|
19486
19571
|
const lanePositions = /* @__PURE__ */ new Map();
|
|
@@ -19516,6 +19601,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19516
19601
|
laneBarWidth = Math.max(lx2 - lx1, 2);
|
|
19517
19602
|
}
|
|
19518
19603
|
lanePositions.set(row.laneName, { x1: lx1, x2: lx1 + laneBarWidth, y: yOffset + BAR_H / 2 });
|
|
19604
|
+
renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, laneColor, palette, "lane", { key: "data-lane", value: row.laneName });
|
|
19519
19605
|
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
19606
|
if (onToggleLane) onToggleLane(row.laneName);
|
|
19521
19607
|
}).on("mouseenter", () => {
|
|
@@ -19541,7 +19627,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19541
19627
|
});
|
|
19542
19628
|
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
19629
|
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("
|
|
19630
|
+
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
19631
|
}
|
|
19546
19632
|
}
|
|
19547
19633
|
yOffset += BAR_H + ROW_GAP;
|
|
@@ -19552,6 +19638,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19552
19638
|
const toggleIcon = isCollapsed ? "\u25BA" : "\u25BC";
|
|
19553
19639
|
const tagColor = resolveTagColor(group.metadata, resolved.tagGroups, currentActiveGroup, true);
|
|
19554
19640
|
const groupColor = tagColor && tagColor !== "#999999" ? tagColor : group.color || palette.textMuted;
|
|
19641
|
+
renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, groupColor, palette, "group", { key: "data-group", value: group.name });
|
|
19555
19642
|
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
19643
|
if (onToggleGroup) onToggleGroup(group.name);
|
|
19557
19644
|
}).on("mouseenter", () => {
|
|
@@ -19561,7 +19648,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19561
19648
|
resetHighlight(g, svg);
|
|
19562
19649
|
hideGanttDateIndicators(g);
|
|
19563
19650
|
});
|
|
19564
|
-
const
|
|
19651
|
+
const groupIndent = group.depth <= 2 ? group.depth * 14 : 2 * 14 + (group.depth - 2) * 8;
|
|
19652
|
+
const labelX = 10 + groupIndent;
|
|
19565
19653
|
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
19654
|
const gStart = dateToFractionalYear(group.startDate);
|
|
19567
19655
|
const gEnd = dateToFractionalYear(group.endDate);
|
|
@@ -19579,7 +19667,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19579
19667
|
});
|
|
19580
19668
|
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
19669
|
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("
|
|
19670
|
+
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);
|
|
19671
|
+
}
|
|
19672
|
+
const summaryLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
|
|
19673
|
+
const summaryPlacement = computeBarLabel(summaryLabel, gx1, barWidth, innerWidth, palette.text);
|
|
19674
|
+
if (summaryPlacement) {
|
|
19675
|
+
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
19676
|
}
|
|
19584
19677
|
groupPositions.set(group.name, { x1: gx1, x2: gx1 + barWidth, y: yOffset + BAR_H / 2 });
|
|
19585
19678
|
} else {
|
|
@@ -19594,7 +19687,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19594
19687
|
});
|
|
19595
19688
|
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
19689
|
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("
|
|
19690
|
+
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);
|
|
19691
|
+
}
|
|
19692
|
+
const expandedLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
|
|
19693
|
+
const expandedPlacement = computeBarLabel(expandedLabel, gx1, groupBarWidth, innerWidth, palette.text);
|
|
19694
|
+
if (expandedPlacement) {
|
|
19695
|
+
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
19696
|
}
|
|
19599
19697
|
}
|
|
19600
19698
|
}
|
|
@@ -19602,9 +19700,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19602
19700
|
} else if (row.type === "task") {
|
|
19603
19701
|
const rt = row.task;
|
|
19604
19702
|
const task = rt.task;
|
|
19605
|
-
const
|
|
19703
|
+
const barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
|
|
19704
|
+
const depth = rt.groupPath.length;
|
|
19705
|
+
const indent = depth <= 2 ? depth * 14 : 2 * 14 + (depth - 2) * 8;
|
|
19706
|
+
const taskLabelX = isTagMode ? 20 : 6 + indent;
|
|
19606
19707
|
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").
|
|
19708
|
+
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
19709
|
if (onClickItem) onClickItem(task.lineNumber);
|
|
19609
19710
|
}).on("mouseenter", () => {
|
|
19610
19711
|
if (rt.isMilestone) {
|
|
@@ -19615,13 +19716,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19615
19716
|
}).on("mouseleave", () => {
|
|
19616
19717
|
resetHighlight(g, svg);
|
|
19617
19718
|
});
|
|
19719
|
+
appendTaskIcon(taskLabel, task.label, rt.isMilestone, barColor, palette.text);
|
|
19618
19720
|
for (const [key, value] of Object.entries(rt.effectiveMetadata)) {
|
|
19619
19721
|
taskLabel.attr(`data-tag-${key}`, value.toLowerCase());
|
|
19620
19722
|
}
|
|
19621
19723
|
if (rt.isCriticalPath) {
|
|
19622
19724
|
taskLabel.attr("data-critical-path", "true");
|
|
19623
19725
|
}
|
|
19624
|
-
let barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
|
|
19625
19726
|
if (rt.isMilestone) {
|
|
19626
19727
|
const mx = xScale(dateToFractionalYear(rt.startDate));
|
|
19627
19728
|
const my = yOffset + BAR_H / 2;
|
|
@@ -19699,32 +19800,40 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19699
19800
|
progGrad.append("stop").attr("offset", "100%").attr("stop-color", barColor).attr("stop-opacity", 0);
|
|
19700
19801
|
progressFill = `url(#${progGradId})`;
|
|
19701
19802
|
}
|
|
19702
|
-
taskG.append("rect").attr("class", "gantt-progress").attr("x", x1).attr("y", yOffset).attr("width", progressWidth).attr("height", BAR_H).attr("
|
|
19803
|
+
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
19804
|
}
|
|
19704
19805
|
if (rt.isCriticalPath) {
|
|
19705
19806
|
taskG.attr("data-critical-path", "true");
|
|
19706
19807
|
}
|
|
19707
|
-
const
|
|
19708
|
-
if (
|
|
19709
|
-
taskG.append("text").attr("x",
|
|
19808
|
+
const labelPlacement = computeBarLabel(task.label, x1, barWidth, innerWidth, palette.text);
|
|
19809
|
+
if (labelPlacement) {
|
|
19810
|
+
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
19811
|
}
|
|
19711
19812
|
taskPositions.set(task.id, { x1, x2: x1 + barWidth, y: yOffset + BAR_H / 2 });
|
|
19712
19813
|
}
|
|
19713
19814
|
yOffset += BAR_H + ROW_GAP;
|
|
19714
19815
|
}
|
|
19715
19816
|
}
|
|
19716
|
-
if (
|
|
19717
|
-
|
|
19718
|
-
|
|
19719
|
-
|
|
19720
|
-
|
|
19721
|
-
|
|
19722
|
-
|
|
19723
|
-
|
|
19724
|
-
|
|
19725
|
-
|
|
19726
|
-
|
|
19727
|
-
|
|
19817
|
+
if (todayDate && todayX >= 0 && todayX <= innerWidth) {
|
|
19818
|
+
const todayHoverG = g.append("g").attr("class", "gantt-today-hover").style("cursor", "pointer");
|
|
19819
|
+
todayHoverG.append("rect").attr("x", todayX - 10).attr("y", -6).attr("width", 20).attr("height", innerHeight + 16).attr("fill", "transparent").attr("pointer-events", "all");
|
|
19820
|
+
const todayDateObj = todayDate;
|
|
19821
|
+
todayHoverG.on("mouseenter", () => {
|
|
19822
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
19823
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
19824
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
19825
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
19826
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
19827
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
19828
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
19829
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
19830
|
+
g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
|
|
19831
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
19832
|
+
showGanttDateIndicators(g, xScale, todayDateObj, null, innerHeight, todayColor);
|
|
19833
|
+
}).on("mouseleave", () => {
|
|
19834
|
+
resetHighlight(g, svg);
|
|
19835
|
+
hideGanttDateIndicators(g);
|
|
19836
|
+
});
|
|
19728
19837
|
}
|
|
19729
19838
|
if (resolved.options.dependencies) {
|
|
19730
19839
|
renderDependencyArrows(g, resolved, taskPositions, groupPositions, collapsedGroups, palette, isDark, isTagMode, lanePositions, collapsedLanes, taskLaneMap);
|
|
@@ -19841,10 +19950,10 @@ function renderDependencyArrows(g, resolved, taskPositions, groupPositions, coll
|
|
|
19841
19950
|
const path = `M ${sx} ${sy} C ${sx + cpOffset} ${sy}, ${tx - cpOffset} ${ty}, ${tx} ${ty}`;
|
|
19842
19951
|
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
19843
19952
|
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);
|
|
19953
|
+
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
19954
|
const headSize = 5;
|
|
19846
19955
|
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);
|
|
19956
|
+
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
19957
|
}
|
|
19849
19958
|
}
|
|
19850
19959
|
}
|
|
@@ -19865,7 +19974,9 @@ function applyCriticalPathHighlight(svg, chartG) {
|
|
|
19865
19974
|
el.attr("opacity", el.attr("data-critical-path") === "true" ? 1 : FADE_OPACITY);
|
|
19866
19975
|
});
|
|
19867
19976
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
19977
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
19868
19978
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
19979
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
19869
19980
|
chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
|
|
19870
19981
|
chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").each(function() {
|
|
19871
19982
|
const el = d3Selection10.select(this);
|
|
@@ -19877,7 +19988,9 @@ function resetHighlightAll(svg, chartG) {
|
|
|
19877
19988
|
chartG.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
|
|
19878
19989
|
svg.selectAll(".gantt-task-label").attr("opacity", 1);
|
|
19879
19990
|
svg.selectAll(".gantt-group-label").attr("opacity", 1);
|
|
19991
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
|
|
19880
19992
|
svg.selectAll(".gantt-lane-header").attr("opacity", 1);
|
|
19993
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
|
|
19881
19994
|
chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", 1);
|
|
19882
19995
|
chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
|
|
19883
19996
|
}
|
|
@@ -19893,7 +20006,7 @@ function drawSwimlaneIcon(parent, x, y, isActive, palette) {
|
|
|
19893
20006
|
}
|
|
19894
20007
|
return iconG;
|
|
19895
20008
|
}
|
|
19896
|
-
function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
|
|
20009
|
+
function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
|
|
19897
20010
|
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
19898
20011
|
let visibleGroups;
|
|
19899
20012
|
if (activeGroupName) {
|
|
@@ -19954,7 +20067,8 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
19954
20067
|
if (visibleGroups.length > 0) totalW += LEGEND_GROUP_GAP;
|
|
19955
20068
|
totalW += cpPillW;
|
|
19956
20069
|
}
|
|
19957
|
-
const
|
|
20070
|
+
const containerWidth = chartLeftMargin + chartInnerWidth + RIGHT_MARGIN;
|
|
20071
|
+
const legendX = (containerWidth - totalW) / 2;
|
|
19958
20072
|
const legendRow = svg.append("g").attr("class", "gantt-tag-legend-container").attr("transform", `translate(${legendX}, ${legendY})`);
|
|
19959
20073
|
let cursorX = 0;
|
|
19960
20074
|
for (let i = 0; i < visibleGroups.length; i++) {
|
|
@@ -19966,7 +20080,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
19966
20080
|
const pillW = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD + iconReserve;
|
|
19967
20081
|
const pillH = isActive ? LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2 : LEGEND_HEIGHT;
|
|
19968
20082
|
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", () => {
|
|
20083
|
+
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
20084
|
if (onToggle) onToggle(group.name);
|
|
19971
20085
|
});
|
|
19972
20086
|
if (isActive) {
|
|
@@ -20000,7 +20114,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
20000
20114
|
let ex = pillXOff + pillW + LEGEND_CAPSULE_PAD + 4;
|
|
20001
20115
|
for (const entry of entries) {
|
|
20002
20116
|
const entryValue = entry.value.toLowerCase();
|
|
20003
|
-
const entryG = gEl.append("g").attr("class", "gantt-legend-entry").style("cursor", "pointer");
|
|
20117
|
+
const entryG = gEl.append("g").attr("class", "gantt-legend-entry").attr("data-line-number", String(entry.lineNumber)).style("cursor", "pointer");
|
|
20004
20118
|
entryG.append("circle").attr("cx", ex + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
20005
20119
|
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
20120
|
entryG.on("mouseenter", () => {
|
|
@@ -20036,9 +20150,11 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
20036
20150
|
cursorX += groupW + LEGEND_GROUP_GAP;
|
|
20037
20151
|
}
|
|
20038
20152
|
if (hasCriticalPath) {
|
|
20153
|
+
const cpLineNum = optionLineNumbers["critical-path"];
|
|
20039
20154
|
const cpG = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-legend-critical-path").style("cursor", "pointer").on("click", () => {
|
|
20040
20155
|
if (onToggleCriticalPath) onToggleCriticalPath();
|
|
20041
20156
|
});
|
|
20157
|
+
if (cpLineNum) cpG.attr("data-line-number", String(cpLineNum));
|
|
20042
20158
|
cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", criticalPathActive ? palette.bg : groupBg);
|
|
20043
20159
|
if (criticalPathActive) {
|
|
20044
20160
|
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 +20172,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
20056
20172
|
});
|
|
20057
20173
|
}
|
|
20058
20174
|
}
|
|
20059
|
-
function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
20175
|
+
function renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette) {
|
|
20060
20176
|
for (let i = 0; i < resolved.eras.length; i++) {
|
|
20061
20177
|
const era = resolved.eras[i];
|
|
20062
20178
|
const color = era.color || ERA_COLORS[i % ERA_COLORS.length];
|
|
@@ -20067,13 +20183,23 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
|
20067
20183
|
const hoverEraOpacity = 0.16;
|
|
20068
20184
|
const eraStartDate = parseDateStringToDate(era.startDate);
|
|
20069
20185
|
const eraEndDate = parseDateStringToDate(era.endDate);
|
|
20070
|
-
const eraG = g.append("g").attr("class", "gantt-era-group");
|
|
20186
|
+
const eraG = g.append("g").attr("class", "gantt-era-group").attr("data-line-number", String(era.lineNumber));
|
|
20071
20187
|
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",
|
|
20188
|
+
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
20189
|
eraG.on("mouseenter", () => {
|
|
20190
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
20191
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
20192
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20193
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20194
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
20195
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20196
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20197
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20198
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20074
20199
|
eraRect.attr("opacity", hoverEraOpacity);
|
|
20075
20200
|
showGanttDateIndicators(g, xScale, eraStartDate, eraEndDate, innerHeight, color);
|
|
20076
20201
|
}).on("mouseleave", () => {
|
|
20202
|
+
resetHighlight(g, svg);
|
|
20077
20203
|
eraRect.attr("opacity", baseEraOpacity);
|
|
20078
20204
|
hideGanttDateIndicators(g);
|
|
20079
20205
|
});
|
|
@@ -20085,22 +20211,31 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
|
20085
20211
|
const diamondSize = 5;
|
|
20086
20212
|
const labelY = -24;
|
|
20087
20213
|
const diamondY = labelY + 14;
|
|
20088
|
-
const markerG = g.append("g").attr("class", "gantt-marker-group").style("cursor", "pointer");
|
|
20214
|
+
const markerG = g.append("g").attr("class", "gantt-marker-group").attr("data-line-number", String(marker.lineNumber)).style("cursor", "pointer");
|
|
20089
20215
|
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
20216
|
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
20217
|
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
20218
|
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
20219
|
const markerLine = markerG.select(".gantt-marker");
|
|
20094
|
-
const markerLabel = markerG.select(".gantt-marker-label");
|
|
20095
20220
|
const markerDiamond = markerG.select("path");
|
|
20096
20221
|
markerG.on("mouseenter", () => {
|
|
20097
|
-
|
|
20098
|
-
|
|
20222
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
20223
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
20224
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20225
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20226
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
20227
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20228
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20229
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20230
|
+
g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
|
|
20231
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20232
|
+
markerG.attr("opacity", 1);
|
|
20233
|
+
markerLine.attr("opacity", 0.8);
|
|
20099
20234
|
markerDiamond.attr("opacity", 0);
|
|
20100
|
-
showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color);
|
|
20235
|
+
showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color, { skipStartLine: true });
|
|
20101
20236
|
}).on("mouseleave", () => {
|
|
20237
|
+
resetHighlight(g, svg);
|
|
20102
20238
|
markerLine.attr("opacity", 0.5);
|
|
20103
|
-
markerLabel.attr("opacity", 1);
|
|
20104
20239
|
markerDiamond.attr("opacity", 0.9);
|
|
20105
20240
|
hideGanttDateIndicators(g);
|
|
20106
20241
|
});
|
|
@@ -20114,11 +20249,7 @@ function parseDateStringToDate(s) {
|
|
|
20114
20249
|
return new Date(year, month, day);
|
|
20115
20250
|
}
|
|
20116
20251
|
function parseDateToFractionalYear(s) {
|
|
20117
|
-
|
|
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;
|
|
20252
|
+
return dateToFractionalYear(parseDateStringToDate(s));
|
|
20122
20253
|
}
|
|
20123
20254
|
function highlightDeps(g, svg, taskId, resolved) {
|
|
20124
20255
|
const related = /* @__PURE__ */ new Set([taskId]);
|
|
@@ -20152,6 +20283,7 @@ function highlightDeps(g, svg, taskId, resolved) {
|
|
|
20152
20283
|
const isRelated = from && related.has(from) || to && related.has(to);
|
|
20153
20284
|
el.attr("opacity", isRelated ? 0.5 : FADE_OPACITY);
|
|
20154
20285
|
});
|
|
20286
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20155
20287
|
}
|
|
20156
20288
|
function highlightGroup(g, svg, groupName) {
|
|
20157
20289
|
g.selectAll(".gantt-task").each(function() {
|
|
@@ -20174,7 +20306,12 @@ function highlightGroup(g, svg, groupName) {
|
|
|
20174
20306
|
const el = d3Selection10.select(this);
|
|
20175
20307
|
el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
|
|
20176
20308
|
});
|
|
20309
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").each(function() {
|
|
20310
|
+
const el = d3Selection10.select(this);
|
|
20311
|
+
el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
|
|
20312
|
+
});
|
|
20177
20313
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20314
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20178
20315
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
|
|
20179
20316
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20180
20317
|
}
|
|
@@ -20201,8 +20338,13 @@ function highlightLane(g, svg, tagKey, laneName) {
|
|
|
20201
20338
|
const el = d3Selection10.select(this);
|
|
20202
20339
|
el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
|
|
20203
20340
|
});
|
|
20341
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").each(function() {
|
|
20342
|
+
const el = d3Selection10.select(this);
|
|
20343
|
+
el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
|
|
20344
|
+
});
|
|
20204
20345
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20205
20346
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20347
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20206
20348
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20207
20349
|
}
|
|
20208
20350
|
function highlightTask(g, svg, taskId) {
|
|
@@ -20217,7 +20359,9 @@ function highlightTask(g, svg, taskId) {
|
|
|
20217
20359
|
});
|
|
20218
20360
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20219
20361
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20362
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20220
20363
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20364
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20221
20365
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20222
20366
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20223
20367
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
@@ -20234,7 +20378,9 @@ function highlightMilestone(g, svg, taskId) {
|
|
|
20234
20378
|
});
|
|
20235
20379
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20236
20380
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20381
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20237
20382
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20383
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20238
20384
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20239
20385
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20240
20386
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
@@ -20253,11 +20399,14 @@ function resetHighlight(g, svg) {
|
|
|
20253
20399
|
g.selectAll(".gantt-task, .gantt-milestone").attr("opacity", 1);
|
|
20254
20400
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
|
|
20255
20401
|
svg.selectAll(".gantt-group-label").attr("opacity", 1);
|
|
20402
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
|
|
20256
20403
|
svg.selectAll(".gantt-task-label").attr("opacity", 1);
|
|
20257
20404
|
svg.selectAll(".gantt-lane-header").attr("opacity", 1);
|
|
20405
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
|
|
20258
20406
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", 1);
|
|
20259
20407
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
|
|
20260
20408
|
g.selectAll(".gantt-marker-group").attr("opacity", 1);
|
|
20409
|
+
g.selectAll(".gantt-era-group").attr("opacity", 1);
|
|
20261
20410
|
}
|
|
20262
20411
|
function buildRowList(resolved, collapsedGroups) {
|
|
20263
20412
|
const rows = [];
|
|
@@ -20411,15 +20560,18 @@ function diamondPoints(cx, cy, size) {
|
|
|
20411
20560
|
function formatGanttDate(d) {
|
|
20412
20561
|
return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
|
|
20413
20562
|
}
|
|
20414
|
-
function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color) {
|
|
20563
|
+
function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color, options) {
|
|
20415
20564
|
g.selectAll(".gantt-scale-tick").attr("opacity", 0.05);
|
|
20416
20565
|
g.selectAll(".gantt-today").attr("opacity", 0.05);
|
|
20566
|
+
const hg = g.append("g").attr("class", "gantt-hover-date").attr("pointer-events", "none");
|
|
20417
20567
|
const tickLen = 6;
|
|
20418
20568
|
const startPos = xScale(dateToFractionalYear(startDate));
|
|
20419
20569
|
const startLabel = formatGanttDate(startDate);
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20570
|
+
if (!options?.skipStartLine) {
|
|
20571
|
+
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);
|
|
20572
|
+
}
|
|
20573
|
+
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);
|
|
20574
|
+
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
20575
|
if (endDate && endDate.getTime() !== startDate.getTime()) {
|
|
20424
20576
|
const endPos = xScale(dateToFractionalYear(endDate));
|
|
20425
20577
|
const endLabel = formatGanttDate(endDate);
|
|
@@ -20436,15 +20588,15 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
|
|
|
20436
20588
|
startAnchor = "middle";
|
|
20437
20589
|
endAnchor = "middle";
|
|
20438
20590
|
}
|
|
20439
|
-
|
|
20440
|
-
|
|
20591
|
+
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);
|
|
20592
|
+
hg.selectAll("text.gantt-hover-date").each(function() {
|
|
20441
20593
|
const el = d3Selection10.select(this);
|
|
20442
20594
|
if (el.text() === startLabel) {
|
|
20443
20595
|
el.attr("x", startLabelX).attr("text-anchor", startAnchor);
|
|
20444
20596
|
}
|
|
20445
20597
|
});
|
|
20446
|
-
|
|
20447
|
-
|
|
20598
|
+
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);
|
|
20599
|
+
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
20600
|
}
|
|
20449
20601
|
}
|
|
20450
20602
|
function hideGanttDateIndicators(g) {
|
|
@@ -20489,7 +20641,7 @@ function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor)
|
|
|
20489
20641
|
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
20642
|
}
|
|
20491
20643
|
}
|
|
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;
|
|
20644
|
+
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
20645
|
var init_renderer9 = __esm({
|
|
20494
20646
|
"src/gantt/renderer.ts"() {
|
|
20495
20647
|
"use strict";
|
|
@@ -20508,6 +20660,12 @@ var init_renderer9 = __esm({
|
|
|
20508
20660
|
MIN_LEFT_MARGIN = 120;
|
|
20509
20661
|
BOTTOM_MARGIN = 40;
|
|
20510
20662
|
RIGHT_MARGIN = 20;
|
|
20663
|
+
CHAR_W = 6.5;
|
|
20664
|
+
LABEL_PAD = 8;
|
|
20665
|
+
LABEL_GAP = 5;
|
|
20666
|
+
BAND_ACCENT_W = 4;
|
|
20667
|
+
BAND_RADIUS = 4;
|
|
20668
|
+
bandClipCounter = 0;
|
|
20511
20669
|
JS_DAY_TO_WEEKDAY2 = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
20512
20670
|
ERA_COLORS = ["#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#b48ead"];
|
|
20513
20671
|
FADE_OPACITY = 0.1;
|
|
@@ -20608,14 +20766,14 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
20608
20766
|
nodePositionMap.set(node.id, node);
|
|
20609
20767
|
}
|
|
20610
20768
|
const LABEL_CHAR_W = 7;
|
|
20611
|
-
const
|
|
20769
|
+
const LABEL_PAD2 = 8;
|
|
20612
20770
|
const LABEL_H = 16;
|
|
20613
20771
|
const PERP_OFFSET = 10;
|
|
20614
20772
|
const labelPositions = [];
|
|
20615
20773
|
for (let ei = 0; ei < layout.edges.length; ei++) {
|
|
20616
20774
|
const edge = layout.edges[ei];
|
|
20617
20775
|
if (!edge.label) continue;
|
|
20618
|
-
const bgW = edge.label.length * LABEL_CHAR_W +
|
|
20776
|
+
const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
|
|
20619
20777
|
let lx, ly;
|
|
20620
20778
|
if (edge.source === edge.target) {
|
|
20621
20779
|
const node = nodePositionMap.get(edge.source);
|
|
@@ -25115,12 +25273,12 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
25115
25273
|
};
|
|
25116
25274
|
const LABEL_MAX_FONT = 48;
|
|
25117
25275
|
const LABEL_MIN_FONT = 14;
|
|
25118
|
-
const
|
|
25276
|
+
const LABEL_PAD2 = 40;
|
|
25119
25277
|
const CHAR_WIDTH_RATIO3 = 0.6;
|
|
25120
25278
|
const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
|
|
25121
25279
|
const quadrantLabelLayout = (text, qw2, qh2) => {
|
|
25122
|
-
const availW = qw2 -
|
|
25123
|
-
const availH = qh2 -
|
|
25280
|
+
const availW = qw2 - LABEL_PAD2;
|
|
25281
|
+
const availH = qh2 - LABEL_PAD2;
|
|
25124
25282
|
const words = text.split(/\s+/);
|
|
25125
25283
|
if (estTextWidth(text, LABEL_MAX_FONT) <= availW) {
|
|
25126
25284
|
const fs = Math.min(LABEL_MAX_FONT, availH);
|
|
@@ -25314,6 +25472,7 @@ function finalizeSvgExport(container, theme, palette, options) {
|
|
|
25314
25472
|
}
|
|
25315
25473
|
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
25316
25474
|
svgEl.style.fontFamily = FONT_FAMILY;
|
|
25475
|
+
svgEl.querySelectorAll("[data-export-ignore]").forEach((el) => el.remove());
|
|
25317
25476
|
const svgHtml = svgEl.outerHTML;
|
|
25318
25477
|
document.body.removeChild(container);
|
|
25319
25478
|
if (options?.branding !== false) {
|