@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.js
CHANGED
|
@@ -7964,7 +7964,9 @@ function parseGantt(content, palette) {
|
|
|
7964
7964
|
criticalPath: false,
|
|
7965
7965
|
dependencies: false,
|
|
7966
7966
|
sort: "default",
|
|
7967
|
-
defaultSwimlaneGroup: null
|
|
7967
|
+
defaultSwimlaneGroup: null,
|
|
7968
|
+
optionLineNumbers: {},
|
|
7969
|
+
holidaysLineNumber: null
|
|
7968
7970
|
},
|
|
7969
7971
|
diagnostics,
|
|
7970
7972
|
error: null
|
|
@@ -8149,6 +8151,7 @@ function parseGantt(content, palette) {
|
|
|
8149
8151
|
inHolidaysBlock = true;
|
|
8150
8152
|
holidaysBlockIndent = indent;
|
|
8151
8153
|
inHeaderBlock = false;
|
|
8154
|
+
result.options.holidaysLineNumber = lineNumber;
|
|
8152
8155
|
continue;
|
|
8153
8156
|
}
|
|
8154
8157
|
const tagMatch = matchTagBlockHeading(line10);
|
|
@@ -8175,7 +8178,8 @@ function parseGantt(content, palette) {
|
|
|
8175
8178
|
startDate: eraMatch[1],
|
|
8176
8179
|
endDate: eraMatch[2],
|
|
8177
8180
|
label: eraExtracted.label,
|
|
8178
|
-
color: eraExtracted.color || null
|
|
8181
|
+
color: eraExtracted.color || null,
|
|
8182
|
+
lineNumber
|
|
8179
8183
|
});
|
|
8180
8184
|
inHeaderBlock = false;
|
|
8181
8185
|
continue;
|
|
@@ -8197,6 +8201,7 @@ function parseGantt(content, palette) {
|
|
|
8197
8201
|
if (optMatch && isKnownOption(optMatch[1].toLowerCase())) {
|
|
8198
8202
|
const key = optMatch[1].toLowerCase();
|
|
8199
8203
|
const value = optMatch[2].trim();
|
|
8204
|
+
result.options.optionLineNumbers[key] = lineNumber;
|
|
8200
8205
|
switch (key) {
|
|
8201
8206
|
case "start":
|
|
8202
8207
|
result.options.start = value;
|
|
@@ -13164,6 +13169,9 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, opti
|
|
|
13164
13169
|
const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
|
|
13165
13170
|
const groupW = isActive ? lg.width : pillW;
|
|
13166
13171
|
const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "is-legend-group").attr("data-legend-group", lg.key).style("cursor", "pointer");
|
|
13172
|
+
if (!isActive) {
|
|
13173
|
+
gEl.attr("data-export-ignore", "true");
|
|
13174
|
+
}
|
|
13167
13175
|
if (isActive) {
|
|
13168
13176
|
gEl.append("rect").attr("width", groupW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
13169
13177
|
}
|
|
@@ -13176,17 +13184,32 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, opti
|
|
|
13176
13184
|
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);
|
|
13177
13185
|
if (isActive) {
|
|
13178
13186
|
const hiddenSet = !lg.isStatus ? hiddenTagValues?.get(lg.key) : void 0;
|
|
13179
|
-
|
|
13187
|
+
const entryStartX = pillXOff + pillW + 4;
|
|
13188
|
+
const entryData = [];
|
|
13189
|
+
let estimatedX = entryStartX;
|
|
13180
13190
|
for (const entry of lg.entries) {
|
|
13181
13191
|
const isHidden = hiddenSet?.has(entry.value) ?? false;
|
|
13182
|
-
const
|
|
13192
|
+
const estimatedTextW = entry.label.length * LEGEND_ENTRY_FONT_W;
|
|
13193
|
+
const entryG = gEl.append("g").attr("data-legend-entry", entry.value).attr("transform", `translate(${estimatedX}, 0)`).style("cursor", "pointer");
|
|
13194
|
+
const entryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
13195
|
+
entryG.append("rect").attr("x", -2).attr("y", 0).attr("width", entryW + 4).attr("height", LEGEND_HEIGHT).attr("fill", "transparent");
|
|
13183
13196
|
if (isHidden) {
|
|
13184
|
-
entryG.append("circle").attr("cx",
|
|
13197
|
+
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);
|
|
13185
13198
|
} else {
|
|
13186
|
-
entryG.append("circle").attr("cx",
|
|
13199
|
+
entryG.append("circle").attr("cx", LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
13187
13200
|
}
|
|
13188
|
-
entryG.append("text").attr("x",
|
|
13189
|
-
|
|
13201
|
+
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);
|
|
13202
|
+
entryData.push({ g: entryG, textEl: textEl.node(), estimatedW: estimatedTextW });
|
|
13203
|
+
estimatedX += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
13204
|
+
}
|
|
13205
|
+
let reflowX = entryStartX;
|
|
13206
|
+
for (const ed of entryData) {
|
|
13207
|
+
const measuredW = ed.textEl.getComputedTextLength?.() ?? 0;
|
|
13208
|
+
const textW = measuredW > 0 ? measuredW : ed.estimatedW;
|
|
13209
|
+
ed.g.attr("transform", `translate(${reflowX}, 0)`);
|
|
13210
|
+
const actualEntryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + textW + LEGEND_ENTRY_TRAIL;
|
|
13211
|
+
ed.g.select("rect").attr("width", actualEntryW + 4);
|
|
13212
|
+
reflowX += actualEntryW;
|
|
13190
13213
|
}
|
|
13191
13214
|
}
|
|
13192
13215
|
cursorX += groupW + LEGEND_GROUP_GAP;
|
|
@@ -16109,7 +16132,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
16109
16132
|
}
|
|
16110
16133
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
16111
16134
|
const LABEL_CHAR_W = 7;
|
|
16112
|
-
const
|
|
16135
|
+
const LABEL_PAD2 = 8;
|
|
16113
16136
|
const LABEL_H = 16;
|
|
16114
16137
|
const PERP_OFFSET = 10;
|
|
16115
16138
|
const labelPositions = [];
|
|
@@ -16118,7 +16141,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
16118
16141
|
if (!edge.label || edge.points.length < 2) continue;
|
|
16119
16142
|
const midIdx = Math.floor(edge.points.length / 2);
|
|
16120
16143
|
const midPt = edge.points[midIdx];
|
|
16121
|
-
const bgW = edge.label.length * LABEL_CHAR_W +
|
|
16144
|
+
const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
|
|
16122
16145
|
const prev = edge.points[Math.max(0, midIdx - 1)];
|
|
16123
16146
|
const next = edge.points[Math.min(edge.points.length - 1, midIdx + 1)];
|
|
16124
16147
|
const dx = next.x - prev.x;
|
|
@@ -19361,8 +19384,46 @@ __export(renderer_exports9, {
|
|
|
19361
19384
|
});
|
|
19362
19385
|
import * as d3Scale from "d3-scale";
|
|
19363
19386
|
import * as d3Selection10 from "d3-selection";
|
|
19387
|
+
function computeBarLabel(label, x1, barWidth, innerWidth, textColor) {
|
|
19388
|
+
const textWidth = label.length * CHAR_W;
|
|
19389
|
+
const x2 = x1 + barWidth;
|
|
19390
|
+
if (textWidth < barWidth - LABEL_PAD) {
|
|
19391
|
+
return { x: x1 + 6, anchor: "start", fill: textColor, text: label };
|
|
19392
|
+
}
|
|
19393
|
+
if (x2 + LABEL_GAP + textWidth <= innerWidth) {
|
|
19394
|
+
return { x: x2 + LABEL_GAP, anchor: "start", fill: textColor, text: label };
|
|
19395
|
+
}
|
|
19396
|
+
if (x1 - LABEL_GAP - textWidth >= 0) {
|
|
19397
|
+
return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label };
|
|
19398
|
+
}
|
|
19399
|
+
const availWidth = x1 - LABEL_GAP;
|
|
19400
|
+
if (availWidth > CHAR_W * 3) {
|
|
19401
|
+
const maxChars = Math.floor(availWidth / CHAR_W) - 1;
|
|
19402
|
+
return { x: x1 - LABEL_GAP, anchor: "end", fill: textColor, text: label.slice(0, maxChars) + "\u2026" };
|
|
19403
|
+
}
|
|
19404
|
+
return null;
|
|
19405
|
+
}
|
|
19406
|
+
function renderLabelBand(svg, y, leftMargin, color, palette, cssPrefix, dataAttr) {
|
|
19407
|
+
const bandX = 5;
|
|
19408
|
+
const bandW = leftMargin - 7;
|
|
19409
|
+
const bandY = y - BAR_H / 2;
|
|
19410
|
+
const clipId = `gantt-band-clip-${bandClipCounter++}`;
|
|
19411
|
+
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);
|
|
19412
|
+
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");
|
|
19413
|
+
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");
|
|
19414
|
+
if (dataAttr) {
|
|
19415
|
+
tint2.attr(dataAttr.key, dataAttr.value);
|
|
19416
|
+
accent.attr(dataAttr.key, dataAttr.value);
|
|
19417
|
+
}
|
|
19418
|
+
}
|
|
19419
|
+
function appendTaskIcon(textEl, label, isMilestone, iconColor, textColor) {
|
|
19420
|
+
const icon = isMilestone ? "\u25C6" : "\u25CF";
|
|
19421
|
+
textEl.append("tspan").attr("fill", iconColor).text(icon);
|
|
19422
|
+
textEl.append("tspan").attr("fill", textColor).text(" " + label);
|
|
19423
|
+
}
|
|
19364
19424
|
function renderGantt(container, resolved, palette, isDark, options, exportDims) {
|
|
19365
19425
|
container.innerHTML = "";
|
|
19426
|
+
bandClipCounter = 0;
|
|
19366
19427
|
if (resolved.tasks.length === 0) return;
|
|
19367
19428
|
const onClickItem = options?.onClickItem;
|
|
19368
19429
|
const collapsedGroups = options?.collapsedGroups;
|
|
@@ -19381,10 +19442,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19381
19442
|
const isTagMode = tagRows !== null;
|
|
19382
19443
|
const allLabels = isTagMode ? [
|
|
19383
19444
|
...rows.filter((r) => r.type === "lane-header").map((r) => r.laneName),
|
|
19384
|
-
...rows.filter((r) => r.type === "task").map((r) => r.task.task.label)
|
|
19445
|
+
...rows.filter((r) => r.type === "task").map((r) => "\u25CF " + r.task.task.label)
|
|
19385
19446
|
] : [
|
|
19386
|
-
...resolved.tasks.map((t) => t.task.label),
|
|
19387
|
-
...resolved.groups.map((g2) =>
|
|
19447
|
+
...resolved.tasks.map((t) => "\u25CF " + t.task.label),
|
|
19448
|
+
...resolved.groups.map((g2) => {
|
|
19449
|
+
const px = g2.depth <= 2 ? g2.depth * 14 : 2 * 14 + (g2.depth - 2) * 8;
|
|
19450
|
+
return " ".repeat(Math.ceil(px / 7)) + g2.name;
|
|
19451
|
+
})
|
|
19388
19452
|
];
|
|
19389
19453
|
const maxLabelLen = Math.max(...allLabels.map((l) => l.length), 10);
|
|
19390
19454
|
const leftMargin = Math.max(MIN_LEFT_MARGIN, maxLabelLen * 7 + 30);
|
|
@@ -19393,8 +19457,10 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19393
19457
|
const titleHeight = title ? 50 : 20;
|
|
19394
19458
|
const tagLegendReserve = resolved.tagGroups.length > 0 ? LEGEND_HEIGHT + 8 : 0;
|
|
19395
19459
|
const topDateLabelReserve = 22;
|
|
19460
|
+
const hasOverheadLabels = resolved.markers.length > 0 || resolved.eras.length > 0;
|
|
19461
|
+
const markerLabelReserve = hasOverheadLabels ? 18 : 0;
|
|
19396
19462
|
const CONTENT_TOP_PAD = 16;
|
|
19397
|
-
const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve;
|
|
19463
|
+
const marginTop = titleHeight + tagLegendReserve + topDateLabelReserve + markerLabelReserve;
|
|
19398
19464
|
const contentH = isTagMode ? totalRows * (BAR_H + ROW_GAP) : totalRows * (BAR_H + ROW_GAP) + GROUP_GAP2 * resolved.groups.length;
|
|
19399
19465
|
const innerHeight = CONTENT_TOP_PAD + contentH;
|
|
19400
19466
|
const outerHeight = marginTop + innerHeight + BOTTOM_MARGIN;
|
|
@@ -19422,6 +19488,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19422
19488
|
isDark,
|
|
19423
19489
|
hasCriticalPath,
|
|
19424
19490
|
criticalPathActive,
|
|
19491
|
+
resolved.options.optionLineNumbers,
|
|
19425
19492
|
(groupName) => {
|
|
19426
19493
|
currentActiveGroup = currentActiveGroup?.toLowerCase() === groupName.toLowerCase() ? null : groupName;
|
|
19427
19494
|
if (onActiveGroupChange) onActiveGroupChange(currentActiveGroup);
|
|
@@ -19460,7 +19527,25 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19460
19527
|
renderTimeScaleHorizontal(g, xScale, innerWidth, innerHeight, palette.text);
|
|
19461
19528
|
renderWeekendBands(g, resolved, xScale, innerHeight, palette, isDark);
|
|
19462
19529
|
renderHolidayBands(g, svg, resolved, xScale, innerHeight, palette, isDark, marginTop - 4, leftMargin, onClickItem);
|
|
19463
|
-
renderErasAndMarkers(g, resolved, xScale, innerHeight, palette);
|
|
19530
|
+
renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette);
|
|
19531
|
+
let todayDate = null;
|
|
19532
|
+
let todayX = -1;
|
|
19533
|
+
const todayColor = palette.accent || "#e74c3c";
|
|
19534
|
+
const todayMarkerLineNum = resolved.options.optionLineNumbers["today-marker"];
|
|
19535
|
+
if (resolved.options.todayMarker !== "off") {
|
|
19536
|
+
if (resolved.options.todayMarker === "on") {
|
|
19537
|
+
todayDate = /* @__PURE__ */ new Date();
|
|
19538
|
+
} else {
|
|
19539
|
+
todayDate = /* @__PURE__ */ new Date(resolved.options.todayMarker + "T00:00:00");
|
|
19540
|
+
}
|
|
19541
|
+
todayX = xScale(dateToFractionalYear(todayDate));
|
|
19542
|
+
if (todayX >= 0 && todayX <= innerWidth) {
|
|
19543
|
+
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");
|
|
19544
|
+
if (todayMarkerLineNum) todayLine.attr("data-line-number", String(todayMarkerLineNum));
|
|
19545
|
+
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");
|
|
19546
|
+
if (todayMarkerLineNum) todayLabel.attr("data-line-number", String(todayMarkerLineNum));
|
|
19547
|
+
}
|
|
19548
|
+
}
|
|
19464
19549
|
const taskPositions = /* @__PURE__ */ new Map();
|
|
19465
19550
|
const groupPositions = /* @__PURE__ */ new Map();
|
|
19466
19551
|
const lanePositions = /* @__PURE__ */ new Map();
|
|
@@ -19496,6 +19581,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19496
19581
|
laneBarWidth = Math.max(lx2 - lx1, 2);
|
|
19497
19582
|
}
|
|
19498
19583
|
lanePositions.set(row.laneName, { x1: lx1, x2: lx1 + laneBarWidth, y: yOffset + BAR_H / 2 });
|
|
19584
|
+
renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, laneColor, palette, "lane", { key: "data-lane", value: row.laneName });
|
|
19499
19585
|
const labelG = svg.append("g").attr("class", "gantt-lane-header").attr(`data-tag-${row.tagKey}`, row.laneName.toLowerCase()).attr("data-lane", row.laneName).style("cursor", onToggleLane ? "pointer" : "default").on("click", () => {
|
|
19500
19586
|
if (onToggleLane) onToggleLane(row.laneName);
|
|
19501
19587
|
}).on("mouseenter", () => {
|
|
@@ -19521,7 +19607,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19521
19607
|
});
|
|
19522
19608
|
laneBandG.append("rect").attr("class", "gantt-lane-band").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", barFill).attr("stroke", laneColor).attr("stroke-width", 2);
|
|
19523
19609
|
if (row.aggregateProgress !== null && row.aggregateProgress > 0) {
|
|
19524
|
-
laneBandG.append("rect").attr("class", "gantt-lane-progress").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth * Math.min(row.aggregateProgress / 100, 1)).attr("height", BAR_H).attr("
|
|
19610
|
+
laneBandG.append("rect").attr("class", "gantt-lane-progress").attr("x", lx1).attr("y", yOffset).attr("width", laneBarWidth * Math.min(row.aggregateProgress / 100, 1)).attr("height", BAR_H).attr("fill", laneColor).attr("opacity", 0.5).attr("pointer-events", "none");
|
|
19525
19611
|
}
|
|
19526
19612
|
}
|
|
19527
19613
|
yOffset += BAR_H + ROW_GAP;
|
|
@@ -19532,6 +19618,7 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19532
19618
|
const toggleIcon = isCollapsed ? "\u25BA" : "\u25BC";
|
|
19533
19619
|
const tagColor = resolveTagColor(group.metadata, resolved.tagGroups, currentActiveGroup, true);
|
|
19534
19620
|
const groupColor = tagColor && tagColor !== "#999999" ? tagColor : group.color || palette.textMuted;
|
|
19621
|
+
renderLabelBand(svg, marginTop + yOffset + BAR_H / 2, leftMargin, groupColor, palette, "group", { key: "data-group", value: group.name });
|
|
19535
19622
|
const labelG = svg.append("g").attr("class", "gantt-group-label").attr("data-group", group.name).attr("data-line-number", String(group.lineNumber)).style("cursor", onToggleGroup ? "pointer" : "default").on("click", () => {
|
|
19536
19623
|
if (onToggleGroup) onToggleGroup(group.name);
|
|
19537
19624
|
}).on("mouseenter", () => {
|
|
@@ -19541,7 +19628,8 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19541
19628
|
resetHighlight(g, svg);
|
|
19542
19629
|
hideGanttDateIndicators(g);
|
|
19543
19630
|
});
|
|
19544
|
-
const
|
|
19631
|
+
const groupIndent = group.depth <= 2 ? group.depth * 14 : 2 * 14 + (group.depth - 2) * 8;
|
|
19632
|
+
const labelX = 10 + groupIndent;
|
|
19545
19633
|
labelG.append("text").attr("x", labelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("font-weight", "bold").attr("fill", palette.text).text(toggleIcon + " " + group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : ""));
|
|
19546
19634
|
const gStart = dateToFractionalYear(group.startDate);
|
|
19547
19635
|
const gEnd = dateToFractionalYear(group.endDate);
|
|
@@ -19559,7 +19647,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19559
19647
|
});
|
|
19560
19648
|
summaryG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", barWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", mix(groupColor, palette.bg, 30)).attr("stroke", groupColor).attr("stroke-width", 2);
|
|
19561
19649
|
if (group.progress !== null && group.progress > 0) {
|
|
19562
|
-
summaryG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", barWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("
|
|
19650
|
+
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);
|
|
19651
|
+
}
|
|
19652
|
+
const summaryLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
|
|
19653
|
+
const summaryPlacement = computeBarLabel(summaryLabel, gx1, barWidth, innerWidth, palette.text);
|
|
19654
|
+
if (summaryPlacement) {
|
|
19655
|
+
summaryG.append("text").attr("x", summaryPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("font-weight", "bold").attr("text-anchor", summaryPlacement.anchor).attr("fill", summaryPlacement.fill).attr("pointer-events", "none").text(summaryPlacement.text);
|
|
19563
19656
|
}
|
|
19564
19657
|
groupPositions.set(group.name, { x1: gx1, x2: gx1 + barWidth, y: yOffset + BAR_H / 2 });
|
|
19565
19658
|
} else {
|
|
@@ -19574,7 +19667,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19574
19667
|
});
|
|
19575
19668
|
groupBarG.append("rect").attr("x", gx1).attr("y", yOffset).attr("width", groupBarWidth).attr("height", BAR_H).attr("rx", 4).attr("fill", bandFill).attr("stroke", groupColor).attr("stroke-width", 2);
|
|
19576
19669
|
if (group.progress !== null && group.progress > 0) {
|
|
19577
|
-
groupBarG.append("rect").attr("class", "gantt-group-progress").attr("x", gx1).attr("y", yOffset).attr("width", groupBarWidth * Math.min(group.progress / 100, 1)).attr("height", BAR_H).attr("
|
|
19670
|
+
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);
|
|
19671
|
+
}
|
|
19672
|
+
const expandedLabel = group.name + (group.progress !== null ? ` ${Math.round(group.progress)}%` : "");
|
|
19673
|
+
const expandedPlacement = computeBarLabel(expandedLabel, gx1, groupBarWidth, innerWidth, palette.text);
|
|
19674
|
+
if (expandedPlacement) {
|
|
19675
|
+
groupBarG.append("text").attr("x", expandedPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("font-weight", "bold").attr("text-anchor", expandedPlacement.anchor).attr("fill", expandedPlacement.fill).attr("pointer-events", "none").text(expandedPlacement.text);
|
|
19578
19676
|
}
|
|
19579
19677
|
}
|
|
19580
19678
|
}
|
|
@@ -19582,9 +19680,12 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19582
19680
|
} else if (row.type === "task") {
|
|
19583
19681
|
const rt = row.task;
|
|
19584
19682
|
const task = rt.task;
|
|
19585
|
-
const
|
|
19683
|
+
const barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
|
|
19684
|
+
const depth = rt.groupPath.length;
|
|
19685
|
+
const indent = depth <= 2 ? depth * 14 : 2 * 14 + (depth - 2) * 8;
|
|
19686
|
+
const taskLabelX = isTagMode ? 20 : 6 + indent;
|
|
19586
19687
|
const topGroup = rt.groupPath.length > 0 ? rt.groupPath[0] : null;
|
|
19587
|
-
const taskLabel = svg.append("text").attr("class", "gantt-task-label").attr("x", taskLabelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("fill", palette.text).attr("data-line-number", String(task.lineNumber)).attr("data-task-id", task.id).attr("data-group", topGroup).style("cursor", onClickItem ? "pointer" : "default").
|
|
19688
|
+
const taskLabel = svg.append("text").attr("class", "gantt-task-label").attr("x", taskLabelX).attr("y", marginTop + yOffset + BAR_H / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("font-size", "11px").attr("fill", palette.text).attr("data-line-number", String(task.lineNumber)).attr("data-task-id", task.id).attr("data-group", topGroup).style("cursor", onClickItem ? "pointer" : "default").on("click", () => {
|
|
19588
19689
|
if (onClickItem) onClickItem(task.lineNumber);
|
|
19589
19690
|
}).on("mouseenter", () => {
|
|
19590
19691
|
if (rt.isMilestone) {
|
|
@@ -19595,13 +19696,13 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19595
19696
|
}).on("mouseleave", () => {
|
|
19596
19697
|
resetHighlight(g, svg);
|
|
19597
19698
|
});
|
|
19699
|
+
appendTaskIcon(taskLabel, task.label, rt.isMilestone, barColor, palette.text);
|
|
19598
19700
|
for (const [key, value] of Object.entries(rt.effectiveMetadata)) {
|
|
19599
19701
|
taskLabel.attr(`data-tag-${key}`, value.toLowerCase());
|
|
19600
19702
|
}
|
|
19601
19703
|
if (rt.isCriticalPath) {
|
|
19602
19704
|
taskLabel.attr("data-critical-path", "true");
|
|
19603
19705
|
}
|
|
19604
|
-
let barColor = resolveTaskColor(rt, currentActiveGroup, resolved, seriesColors2, palette);
|
|
19605
19706
|
if (rt.isMilestone) {
|
|
19606
19707
|
const mx = xScale(dateToFractionalYear(rt.startDate));
|
|
19607
19708
|
const my = yOffset + BAR_H / 2;
|
|
@@ -19679,32 +19780,40 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
|
|
|
19679
19780
|
progGrad.append("stop").attr("offset", "100%").attr("stop-color", barColor).attr("stop-opacity", 0);
|
|
19680
19781
|
progressFill = `url(#${progGradId})`;
|
|
19681
19782
|
}
|
|
19682
|
-
taskG.append("rect").attr("class", "gantt-progress").attr("x", x1).attr("y", yOffset).attr("width", progressWidth).attr("height", BAR_H).attr("
|
|
19783
|
+
taskG.append("rect").attr("class", "gantt-progress").attr("x", x1).attr("y", yOffset).attr("width", progressWidth).attr("height", BAR_H).attr("fill", progressFill).attr("opacity", 0.5);
|
|
19683
19784
|
}
|
|
19684
19785
|
if (rt.isCriticalPath) {
|
|
19685
19786
|
taskG.attr("data-critical-path", "true");
|
|
19686
19787
|
}
|
|
19687
|
-
const
|
|
19688
|
-
if (
|
|
19689
|
-
taskG.append("text").attr("x",
|
|
19788
|
+
const labelPlacement = computeBarLabel(task.label, x1, barWidth, innerWidth, palette.text);
|
|
19789
|
+
if (labelPlacement) {
|
|
19790
|
+
taskG.append("text").attr("x", labelPlacement.x).attr("y", yOffset + BAR_H / 2).attr("dy", "0.35em").attr("font-size", "10px").attr("text-anchor", labelPlacement.anchor).attr("fill", labelPlacement.fill).attr("pointer-events", "none").text(labelPlacement.text);
|
|
19690
19791
|
}
|
|
19691
19792
|
taskPositions.set(task.id, { x1, x2: x1 + barWidth, y: yOffset + BAR_H / 2 });
|
|
19692
19793
|
}
|
|
19693
19794
|
yOffset += BAR_H + ROW_GAP;
|
|
19694
19795
|
}
|
|
19695
19796
|
}
|
|
19696
|
-
if (
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19797
|
+
if (todayDate && todayX >= 0 && todayX <= innerWidth) {
|
|
19798
|
+
const todayHoverG = g.append("g").attr("class", "gantt-today-hover").style("cursor", "pointer");
|
|
19799
|
+
todayHoverG.append("rect").attr("x", todayX - 10).attr("y", -6).attr("width", 20).attr("height", innerHeight + 16).attr("fill", "transparent").attr("pointer-events", "all");
|
|
19800
|
+
const todayDateObj = todayDate;
|
|
19801
|
+
todayHoverG.on("mouseenter", () => {
|
|
19802
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
19803
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
19804
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
19805
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
19806
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
19807
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
19808
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
19809
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
19810
|
+
g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
|
|
19811
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
19812
|
+
showGanttDateIndicators(g, xScale, todayDateObj, null, innerHeight, todayColor);
|
|
19813
|
+
}).on("mouseleave", () => {
|
|
19814
|
+
resetHighlight(g, svg);
|
|
19815
|
+
hideGanttDateIndicators(g);
|
|
19816
|
+
});
|
|
19708
19817
|
}
|
|
19709
19818
|
if (resolved.options.dependencies) {
|
|
19710
19819
|
renderDependencyArrows(g, resolved, taskPositions, groupPositions, collapsedGroups, palette, isDark, isTagMode, lanePositions, collapsedLanes, taskLaneMap);
|
|
@@ -19821,10 +19930,10 @@ function renderDependencyArrows(g, resolved, taskPositions, groupPositions, coll
|
|
|
19821
19930
|
const path = `M ${sx} ${sy} C ${sx + cpOffset} ${sy}, ${tx - cpOffset} ${ty}, ${tx} ${ty}`;
|
|
19822
19931
|
const arrowColor = mix(palette.text, palette.bg, 50);
|
|
19823
19932
|
const isCpArrow = rt.isCriticalPath && targetTask.isCriticalPath;
|
|
19824
|
-
g.append("path").attr("class", "gantt-dep-arrow").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-critical-path", isCpArrow ? "true" : null).attr("d", path).attr("fill", "none").attr("stroke", arrowColor).attr("stroke-width", 1.5).attr("opacity", 0.5);
|
|
19933
|
+
g.append("path").attr("class", "gantt-dep-arrow").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-line-number", String(dep.lineNumber)).attr("data-critical-path", isCpArrow ? "true" : null).attr("d", path).attr("fill", "none").attr("stroke", arrowColor).attr("stroke-width", 1.5).attr("opacity", 0.5);
|
|
19825
19934
|
const headSize = 5;
|
|
19826
19935
|
const angle = 0;
|
|
19827
|
-
g.append("polygon").attr("class", "gantt-dep-arrowhead").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-critical-path", isCpArrow ? "true" : null).attr("points", arrowheadPoints(tx, ty, headSize, angle)).attr("fill", arrowColor).attr("opacity", 0.5);
|
|
19936
|
+
g.append("polygon").attr("class", "gantt-dep-arrowhead").attr("data-dep-from", rt.task.id).attr("data-dep-to", targetTask.task.id).attr("data-line-number", String(dep.lineNumber)).attr("data-critical-path", isCpArrow ? "true" : null).attr("points", arrowheadPoints(tx, ty, headSize, angle)).attr("fill", arrowColor).attr("opacity", 0.5);
|
|
19828
19937
|
}
|
|
19829
19938
|
}
|
|
19830
19939
|
}
|
|
@@ -19845,7 +19954,9 @@ function applyCriticalPathHighlight(svg, chartG) {
|
|
|
19845
19954
|
el.attr("opacity", el.attr("data-critical-path") === "true" ? 1 : FADE_OPACITY);
|
|
19846
19955
|
});
|
|
19847
19956
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
19957
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
19848
19958
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
19959
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
19849
19960
|
chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
|
|
19850
19961
|
chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").each(function() {
|
|
19851
19962
|
const el = d3Selection10.select(this);
|
|
@@ -19857,7 +19968,9 @@ function resetHighlightAll(svg, chartG) {
|
|
|
19857
19968
|
chartG.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
|
|
19858
19969
|
svg.selectAll(".gantt-task-label").attr("opacity", 1);
|
|
19859
19970
|
svg.selectAll(".gantt-group-label").attr("opacity", 1);
|
|
19971
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
|
|
19860
19972
|
svg.selectAll(".gantt-lane-header").attr("opacity", 1);
|
|
19973
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
|
|
19861
19974
|
chartG.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", 1);
|
|
19862
19975
|
chartG.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
|
|
19863
19976
|
}
|
|
@@ -19873,7 +19986,7 @@ function drawSwimlaneIcon(parent, x, y, isActive, palette) {
|
|
|
19873
19986
|
}
|
|
19874
19987
|
return iconG;
|
|
19875
19988
|
}
|
|
19876
|
-
function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
|
|
19989
|
+
function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleCriticalPath, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks) {
|
|
19877
19990
|
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
19878
19991
|
let visibleGroups;
|
|
19879
19992
|
if (activeGroupName) {
|
|
@@ -19934,7 +20047,8 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
19934
20047
|
if (visibleGroups.length > 0) totalW += LEGEND_GROUP_GAP;
|
|
19935
20048
|
totalW += cpPillW;
|
|
19936
20049
|
}
|
|
19937
|
-
const
|
|
20050
|
+
const containerWidth = chartLeftMargin + chartInnerWidth + RIGHT_MARGIN;
|
|
20051
|
+
const legendX = (containerWidth - totalW) / 2;
|
|
19938
20052
|
const legendRow = svg.append("g").attr("class", "gantt-tag-legend-container").attr("transform", `translate(${legendX}, ${legendY})`);
|
|
19939
20053
|
let cursorX = 0;
|
|
19940
20054
|
for (let i = 0; i < visibleGroups.length; i++) {
|
|
@@ -19946,7 +20060,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
19946
20060
|
const pillW = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD + iconReserve;
|
|
19947
20061
|
const pillH = isActive ? LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2 : LEGEND_HEIGHT;
|
|
19948
20062
|
const groupW = groupWidths[i];
|
|
19949
|
-
const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-tag-legend-group").attr("data-tag-group", group.name).style("cursor", "pointer").on("click", () => {
|
|
20063
|
+
const gEl = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-tag-legend-group").attr("data-tag-group", group.name).attr("data-line-number", String(group.lineNumber)).style("cursor", "pointer").on("click", () => {
|
|
19950
20064
|
if (onToggle) onToggle(group.name);
|
|
19951
20065
|
});
|
|
19952
20066
|
if (isActive) {
|
|
@@ -19980,7 +20094,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
19980
20094
|
let ex = pillXOff + pillW + LEGEND_CAPSULE_PAD + 4;
|
|
19981
20095
|
for (const entry of entries) {
|
|
19982
20096
|
const entryValue = entry.value.toLowerCase();
|
|
19983
|
-
const entryG = gEl.append("g").attr("class", "gantt-legend-entry").style("cursor", "pointer");
|
|
20097
|
+
const entryG = gEl.append("g").attr("class", "gantt-legend-entry").attr("data-line-number", String(entry.lineNumber)).style("cursor", "pointer");
|
|
19984
20098
|
entryG.append("circle").attr("cx", ex + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
|
|
19985
20099
|
entryG.append("text").attr("x", ex + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 2).attr("text-anchor", "start").attr("font-size", `${LEGEND_ENTRY_FONT_SIZE}px`).attr("fill", palette.textMuted).text(entry.value);
|
|
19986
20100
|
entryG.on("mouseenter", () => {
|
|
@@ -20016,9 +20130,11 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
20016
20130
|
cursorX += groupW + LEGEND_GROUP_GAP;
|
|
20017
20131
|
}
|
|
20018
20132
|
if (hasCriticalPath) {
|
|
20133
|
+
const cpLineNum = optionLineNumbers["critical-path"];
|
|
20019
20134
|
const cpG = legendRow.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "gantt-legend-critical-path").style("cursor", "pointer").on("click", () => {
|
|
20020
20135
|
if (onToggleCriticalPath) onToggleCriticalPath();
|
|
20021
20136
|
});
|
|
20137
|
+
if (cpLineNum) cpG.attr("data-line-number", String(cpLineNum));
|
|
20022
20138
|
cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", criticalPathActive ? palette.bg : groupBg);
|
|
20023
20139
|
if (criticalPathActive) {
|
|
20024
20140
|
cpG.append("rect").attr("width", cpPillW).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
|
|
@@ -20036,7 +20152,7 @@ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargi
|
|
|
20036
20152
|
});
|
|
20037
20153
|
}
|
|
20038
20154
|
}
|
|
20039
|
-
function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
20155
|
+
function renderErasAndMarkers(g, svg, resolved, xScale, innerHeight, palette) {
|
|
20040
20156
|
for (let i = 0; i < resolved.eras.length; i++) {
|
|
20041
20157
|
const era = resolved.eras[i];
|
|
20042
20158
|
const color = era.color || ERA_COLORS[i % ERA_COLORS.length];
|
|
@@ -20047,13 +20163,23 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
|
20047
20163
|
const hoverEraOpacity = 0.16;
|
|
20048
20164
|
const eraStartDate = parseDateStringToDate(era.startDate);
|
|
20049
20165
|
const eraEndDate = parseDateStringToDate(era.endDate);
|
|
20050
|
-
const eraG = g.append("g").attr("class", "gantt-era-group");
|
|
20166
|
+
const eraG = g.append("g").attr("class", "gantt-era-group").attr("data-line-number", String(era.lineNumber));
|
|
20051
20167
|
const eraRect = eraG.append("rect").attr("class", "gantt-era").attr("x", sx).attr("y", 0).attr("width", ex - sx).attr("height", innerHeight).attr("fill", color).attr("opacity", baseEraOpacity);
|
|
20052
|
-
eraG.append("text").attr("class", "gantt-era-label").attr("x", (sx + ex) / 2).attr("y",
|
|
20168
|
+
eraG.append("text").attr("class", "gantt-era-label").attr("x", (sx + ex) / 2).attr("y", -24).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", color).attr("opacity", 0.7).style("cursor", "pointer").text(era.label);
|
|
20053
20169
|
eraG.on("mouseenter", () => {
|
|
20170
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
20171
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
20172
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20173
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20174
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
20175
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20176
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20177
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20178
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20054
20179
|
eraRect.attr("opacity", hoverEraOpacity);
|
|
20055
20180
|
showGanttDateIndicators(g, xScale, eraStartDate, eraEndDate, innerHeight, color);
|
|
20056
20181
|
}).on("mouseleave", () => {
|
|
20182
|
+
resetHighlight(g, svg);
|
|
20057
20183
|
eraRect.attr("opacity", baseEraOpacity);
|
|
20058
20184
|
hideGanttDateIndicators(g);
|
|
20059
20185
|
});
|
|
@@ -20065,22 +20191,31 @@ function renderErasAndMarkers(g, resolved, xScale, innerHeight, palette) {
|
|
|
20065
20191
|
const diamondSize = 5;
|
|
20066
20192
|
const labelY = -24;
|
|
20067
20193
|
const diamondY = labelY + 14;
|
|
20068
|
-
const markerG = g.append("g").attr("class", "gantt-marker-group").style("cursor", "pointer");
|
|
20194
|
+
const markerG = g.append("g").attr("class", "gantt-marker-group").attr("data-line-number", String(marker.lineNumber)).style("cursor", "pointer");
|
|
20069
20195
|
markerG.append("rect").attr("x", mx - 40).attr("y", labelY - 12).attr("width", 80).attr("height", innerHeight - labelY + 12).attr("fill", "transparent").attr("pointer-events", "all");
|
|
20070
20196
|
markerG.append("text").attr("class", "gantt-marker-label").attr("x", mx).attr("y", labelY).attr("text-anchor", "middle").attr("font-size", "11px").attr("font-weight", "600").attr("fill", color).text(marker.label);
|
|
20071
20197
|
markerG.append("path").attr("d", `M${mx},${diamondY - diamondSize} l${diamondSize},${diamondSize} l-${diamondSize},${diamondSize} l-${diamondSize},-${diamondSize} Z`).attr("fill", color).attr("opacity", 0.9);
|
|
20072
20198
|
markerG.append("line").attr("class", "gantt-marker").attr("x1", mx).attr("y1", diamondY + diamondSize).attr("x2", mx).attr("y2", innerHeight).attr("stroke", color).attr("stroke-width", 1.5).attr("stroke-dasharray", "6 4").attr("opacity", 0.5);
|
|
20073
20199
|
const markerLine = markerG.select(".gantt-marker");
|
|
20074
|
-
const markerLabel = markerG.select(".gantt-marker-label");
|
|
20075
20200
|
const markerDiamond = markerG.select("path");
|
|
20076
20201
|
markerG.on("mouseenter", () => {
|
|
20077
|
-
|
|
20078
|
-
|
|
20202
|
+
g.selectAll(".gantt-task").attr("opacity", FADE_OPACITY);
|
|
20203
|
+
g.selectAll(".gantt-milestone").attr("opacity", FADE_OPACITY);
|
|
20204
|
+
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20205
|
+
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20206
|
+
svg.selectAll(".gantt-task-label").attr("opacity", FADE_OPACITY);
|
|
20207
|
+
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20208
|
+
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20209
|
+
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20210
|
+
g.selectAll(".gantt-era-group").attr("opacity", FADE_OPACITY);
|
|
20211
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20212
|
+
markerG.attr("opacity", 1);
|
|
20213
|
+
markerLine.attr("opacity", 0.8);
|
|
20079
20214
|
markerDiamond.attr("opacity", 0);
|
|
20080
|
-
showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color);
|
|
20215
|
+
showGanttDateIndicators(g, xScale, markerDate, null, innerHeight, color, { skipStartLine: true });
|
|
20081
20216
|
}).on("mouseleave", () => {
|
|
20217
|
+
resetHighlight(g, svg);
|
|
20082
20218
|
markerLine.attr("opacity", 0.5);
|
|
20083
|
-
markerLabel.attr("opacity", 1);
|
|
20084
20219
|
markerDiamond.attr("opacity", 0.9);
|
|
20085
20220
|
hideGanttDateIndicators(g);
|
|
20086
20221
|
});
|
|
@@ -20094,11 +20229,7 @@ function parseDateStringToDate(s) {
|
|
|
20094
20229
|
return new Date(year, month, day);
|
|
20095
20230
|
}
|
|
20096
20231
|
function parseDateToFractionalYear(s) {
|
|
20097
|
-
|
|
20098
|
-
const year = parts[0];
|
|
20099
|
-
const month = parts.length >= 2 ? parts[1] : 1;
|
|
20100
|
-
const day = parts.length >= 3 ? parts[2] : 1;
|
|
20101
|
-
return year + (month - 1) / 12 + (day - 1) / 365;
|
|
20232
|
+
return dateToFractionalYear(parseDateStringToDate(s));
|
|
20102
20233
|
}
|
|
20103
20234
|
function highlightDeps(g, svg, taskId, resolved) {
|
|
20104
20235
|
const related = /* @__PURE__ */ new Set([taskId]);
|
|
@@ -20132,6 +20263,7 @@ function highlightDeps(g, svg, taskId, resolved) {
|
|
|
20132
20263
|
const isRelated = from && related.has(from) || to && related.has(to);
|
|
20133
20264
|
el.attr("opacity", isRelated ? 0.5 : FADE_OPACITY);
|
|
20134
20265
|
});
|
|
20266
|
+
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20135
20267
|
}
|
|
20136
20268
|
function highlightGroup(g, svg, groupName) {
|
|
20137
20269
|
g.selectAll(".gantt-task").each(function() {
|
|
@@ -20154,7 +20286,12 @@ function highlightGroup(g, svg, groupName) {
|
|
|
20154
20286
|
const el = d3Selection10.select(this);
|
|
20155
20287
|
el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
|
|
20156
20288
|
});
|
|
20289
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").each(function() {
|
|
20290
|
+
const el = d3Selection10.select(this);
|
|
20291
|
+
el.attr("opacity", el.attr("data-group") === groupName ? 1 : FADE_OPACITY);
|
|
20292
|
+
});
|
|
20157
20293
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20294
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20158
20295
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent").attr("opacity", FADE_OPACITY);
|
|
20159
20296
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20160
20297
|
}
|
|
@@ -20181,8 +20318,13 @@ function highlightLane(g, svg, tagKey, laneName) {
|
|
|
20181
20318
|
const el = d3Selection10.select(this);
|
|
20182
20319
|
el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
|
|
20183
20320
|
});
|
|
20321
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").each(function() {
|
|
20322
|
+
const el = d3Selection10.select(this);
|
|
20323
|
+
el.attr("opacity", el.attr("data-lane") === laneName ? 1 : FADE_OPACITY);
|
|
20324
|
+
});
|
|
20184
20325
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20185
20326
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20327
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20186
20328
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
20187
20329
|
}
|
|
20188
20330
|
function highlightTask(g, svg, taskId) {
|
|
@@ -20197,7 +20339,9 @@ function highlightTask(g, svg, taskId) {
|
|
|
20197
20339
|
});
|
|
20198
20340
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20199
20341
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20342
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20200
20343
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20344
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20201
20345
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20202
20346
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20203
20347
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
@@ -20214,7 +20358,9 @@ function highlightMilestone(g, svg, taskId) {
|
|
|
20214
20358
|
});
|
|
20215
20359
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", FADE_OPACITY);
|
|
20216
20360
|
svg.selectAll(".gantt-group-label").attr("opacity", FADE_OPACITY);
|
|
20361
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", FADE_OPACITY);
|
|
20217
20362
|
svg.selectAll(".gantt-lane-header").attr("opacity", FADE_OPACITY);
|
|
20363
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", FADE_OPACITY);
|
|
20218
20364
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", FADE_OPACITY);
|
|
20219
20365
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", FADE_OPACITY);
|
|
20220
20366
|
g.selectAll(".gantt-marker-group").attr("opacity", FADE_OPACITY);
|
|
@@ -20233,11 +20379,14 @@ function resetHighlight(g, svg) {
|
|
|
20233
20379
|
g.selectAll(".gantt-task, .gantt-milestone").attr("opacity", 1);
|
|
20234
20380
|
g.selectAll(".gantt-group-bar, .gantt-group-summary").attr("opacity", 1);
|
|
20235
20381
|
svg.selectAll(".gantt-group-label").attr("opacity", 1);
|
|
20382
|
+
svg.selectAll(".gantt-group-band-bg, .gantt-group-band-accent").attr("opacity", 1);
|
|
20236
20383
|
svg.selectAll(".gantt-task-label").attr("opacity", 1);
|
|
20237
20384
|
svg.selectAll(".gantt-lane-header").attr("opacity", 1);
|
|
20385
|
+
svg.selectAll(".gantt-lane-band-bg, .gantt-lane-band-accent").attr("opacity", 1);
|
|
20238
20386
|
g.selectAll(".gantt-lane-band, .gantt-lane-accent, .gantt-lane-band-group").attr("opacity", 1);
|
|
20239
20387
|
g.selectAll(".gantt-dep-arrow, .gantt-dep-arrowhead").attr("opacity", 0.5);
|
|
20240
20388
|
g.selectAll(".gantt-marker-group").attr("opacity", 1);
|
|
20389
|
+
g.selectAll(".gantt-era-group").attr("opacity", 1);
|
|
20241
20390
|
}
|
|
20242
20391
|
function buildRowList(resolved, collapsedGroups) {
|
|
20243
20392
|
const rows = [];
|
|
@@ -20391,15 +20540,18 @@ function diamondPoints(cx, cy, size) {
|
|
|
20391
20540
|
function formatGanttDate(d) {
|
|
20392
20541
|
return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
|
|
20393
20542
|
}
|
|
20394
|
-
function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color) {
|
|
20543
|
+
function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, color, options) {
|
|
20395
20544
|
g.selectAll(".gantt-scale-tick").attr("opacity", 0.05);
|
|
20396
20545
|
g.selectAll(".gantt-today").attr("opacity", 0.05);
|
|
20546
|
+
const hg = g.append("g").attr("class", "gantt-hover-date").attr("pointer-events", "none");
|
|
20397
20547
|
const tickLen = 6;
|
|
20398
20548
|
const startPos = xScale(dateToFractionalYear(startDate));
|
|
20399
20549
|
const startLabel = formatGanttDate(startDate);
|
|
20400
|
-
|
|
20401
|
-
|
|
20402
|
-
|
|
20550
|
+
if (!options?.skipStartLine) {
|
|
20551
|
+
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);
|
|
20552
|
+
}
|
|
20553
|
+
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);
|
|
20554
|
+
hg.append("text").attr("class", "gantt-hover-date").attr("x", startPos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(startLabel);
|
|
20403
20555
|
if (endDate && endDate.getTime() !== startDate.getTime()) {
|
|
20404
20556
|
const endPos = xScale(dateToFractionalYear(endDate));
|
|
20405
20557
|
const endLabel = formatGanttDate(endDate);
|
|
@@ -20416,15 +20568,15 @@ function showGanttDateIndicators(g, xScale, startDate, endDate, innerHeight, col
|
|
|
20416
20568
|
startAnchor = "middle";
|
|
20417
20569
|
endAnchor = "middle";
|
|
20418
20570
|
}
|
|
20419
|
-
|
|
20420
|
-
|
|
20571
|
+
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);
|
|
20572
|
+
hg.selectAll("text.gantt-hover-date").each(function() {
|
|
20421
20573
|
const el = d3Selection10.select(this);
|
|
20422
20574
|
if (el.text() === startLabel) {
|
|
20423
20575
|
el.attr("x", startLabelX).attr("text-anchor", startAnchor);
|
|
20424
20576
|
}
|
|
20425
20577
|
});
|
|
20426
|
-
|
|
20427
|
-
|
|
20578
|
+
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);
|
|
20579
|
+
hg.append("text").attr("class", "gantt-hover-date").attr("x", endLabelX).attr("y", innerHeight + tickLen + 12).attr("text-anchor", endAnchor).attr("fill", color).attr("font-size", "10px").attr("font-weight", "600").text(endLabel);
|
|
20428
20580
|
}
|
|
20429
20581
|
}
|
|
20430
20582
|
function hideGanttDateIndicators(g) {
|
|
@@ -20469,7 +20621,7 @@ function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor)
|
|
|
20469
20621
|
g.append("text").attr("class", "gantt-scale-tick").attr("x", tick.pos).attr("y", innerHeight + tickLen + 12).attr("text-anchor", "middle").attr("font-size", "10px").attr("fill", textColor).attr("opacity", opacity).text(tick.label);
|
|
20470
20622
|
}
|
|
20471
20623
|
}
|
|
20472
|
-
var BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, JS_DAY_TO_WEEKDAY2, ERA_COLORS, FADE_OPACITY, MONTH_ABBR;
|
|
20624
|
+
var BAR_H, ROW_GAP, GROUP_GAP2, MILESTONE_SIZE, MIN_LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, CHAR_W, LABEL_PAD, LABEL_GAP, BAND_ACCENT_W, BAND_RADIUS, bandClipCounter, JS_DAY_TO_WEEKDAY2, ERA_COLORS, FADE_OPACITY, MONTH_ABBR;
|
|
20473
20625
|
var init_renderer9 = __esm({
|
|
20474
20626
|
"src/gantt/renderer.ts"() {
|
|
20475
20627
|
"use strict";
|
|
@@ -20486,6 +20638,12 @@ var init_renderer9 = __esm({
|
|
|
20486
20638
|
MIN_LEFT_MARGIN = 120;
|
|
20487
20639
|
BOTTOM_MARGIN = 40;
|
|
20488
20640
|
RIGHT_MARGIN = 20;
|
|
20641
|
+
CHAR_W = 6.5;
|
|
20642
|
+
LABEL_PAD = 8;
|
|
20643
|
+
LABEL_GAP = 5;
|
|
20644
|
+
BAND_ACCENT_W = 4;
|
|
20645
|
+
BAND_RADIUS = 4;
|
|
20646
|
+
bandClipCounter = 0;
|
|
20489
20647
|
JS_DAY_TO_WEEKDAY2 = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
20490
20648
|
ERA_COLORS = ["#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#b48ead"];
|
|
20491
20649
|
FADE_OPACITY = 0.1;
|
|
@@ -20588,14 +20746,14 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
20588
20746
|
nodePositionMap.set(node.id, node);
|
|
20589
20747
|
}
|
|
20590
20748
|
const LABEL_CHAR_W = 7;
|
|
20591
|
-
const
|
|
20749
|
+
const LABEL_PAD2 = 8;
|
|
20592
20750
|
const LABEL_H = 16;
|
|
20593
20751
|
const PERP_OFFSET = 10;
|
|
20594
20752
|
const labelPositions = [];
|
|
20595
20753
|
for (let ei = 0; ei < layout.edges.length; ei++) {
|
|
20596
20754
|
const edge = layout.edges[ei];
|
|
20597
20755
|
if (!edge.label) continue;
|
|
20598
|
-
const bgW = edge.label.length * LABEL_CHAR_W +
|
|
20756
|
+
const bgW = edge.label.length * LABEL_CHAR_W + LABEL_PAD2;
|
|
20599
20757
|
let lx, ly;
|
|
20600
20758
|
if (edge.source === edge.target) {
|
|
20601
20759
|
const node = nodePositionMap.get(edge.source);
|
|
@@ -25098,12 +25256,12 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
25098
25256
|
};
|
|
25099
25257
|
const LABEL_MAX_FONT = 48;
|
|
25100
25258
|
const LABEL_MIN_FONT = 14;
|
|
25101
|
-
const
|
|
25259
|
+
const LABEL_PAD2 = 40;
|
|
25102
25260
|
const CHAR_WIDTH_RATIO3 = 0.6;
|
|
25103
25261
|
const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
|
|
25104
25262
|
const quadrantLabelLayout = (text, qw2, qh2) => {
|
|
25105
|
-
const availW = qw2 -
|
|
25106
|
-
const availH = qh2 -
|
|
25263
|
+
const availW = qw2 - LABEL_PAD2;
|
|
25264
|
+
const availH = qh2 - LABEL_PAD2;
|
|
25107
25265
|
const words = text.split(/\s+/);
|
|
25108
25266
|
if (estTextWidth(text, LABEL_MAX_FONT) <= availW) {
|
|
25109
25267
|
const fs = Math.min(LABEL_MAX_FONT, availH);
|
|
@@ -25297,6 +25455,7 @@ function finalizeSvgExport(container, theme, palette, options) {
|
|
|
25297
25455
|
}
|
|
25298
25456
|
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
25299
25457
|
svgEl.style.fontFamily = FONT_FAMILY;
|
|
25458
|
+
svgEl.querySelectorAll("[data-export-ignore]").forEach((el) => el.remove());
|
|
25300
25459
|
const svgHtml = svgEl.outerHTML;
|
|
25301
25460
|
document.body.removeChild(container);
|
|
25302
25461
|
if (options?.branding !== false) {
|