@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/src/gantt/types.ts
CHANGED
|
@@ -93,6 +93,7 @@ export interface GanttEra {
|
|
|
93
93
|
endDate: string;
|
|
94
94
|
label: string;
|
|
95
95
|
color: string | null;
|
|
96
|
+
lineNumber: number;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
export interface GanttMarker {
|
|
@@ -114,6 +115,9 @@ export interface GanttOptions {
|
|
|
114
115
|
dependencies: boolean;
|
|
115
116
|
sort: 'default' | 'tag';
|
|
116
117
|
defaultSwimlaneGroup: string | null; // tag group name from `sort: tag:Team`
|
|
118
|
+
/** Line numbers for option/block keywords — maps key to source line */
|
|
119
|
+
optionLineNumbers: Record<string, number>;
|
|
120
|
+
holidaysLineNumber: number | null;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
// ── Parsed Result ───────────────────────────────────────────
|
|
@@ -674,6 +674,11 @@ export function renderInitiativeStatus(
|
|
|
674
674
|
.attr('data-legend-group', lg.key)
|
|
675
675
|
.style('cursor', 'pointer');
|
|
676
676
|
|
|
677
|
+
// Mark inactive pills so exports can hide them
|
|
678
|
+
if (!isActive) {
|
|
679
|
+
gEl.attr('data-export-ignore', 'true');
|
|
680
|
+
}
|
|
681
|
+
|
|
677
682
|
if (isActive) {
|
|
678
683
|
// Outer capsule background
|
|
679
684
|
gEl.append('rect')
|
|
@@ -724,18 +729,33 @@ export function renderInitiativeStatus(
|
|
|
724
729
|
// Determine which values are hidden for this group
|
|
725
730
|
const hiddenSet = !lg.isStatus ? hiddenTagValues?.get(lg.key) : undefined;
|
|
726
731
|
|
|
727
|
-
|
|
732
|
+
// Render each entry in its own <g> with local coordinates,
|
|
733
|
+
// positioned via transform so we can reflow after measuring.
|
|
734
|
+
const entryStartX = pillXOff + pillW + 4;
|
|
735
|
+
const entryData: { g: d3Selection.Selection<SVGGElement, unknown, null, undefined>; textEl: SVGTextElement; estimatedW: number }[] = [];
|
|
736
|
+
let estimatedX = entryStartX;
|
|
737
|
+
|
|
728
738
|
for (const entry of lg.entries) {
|
|
729
739
|
const isHidden = hiddenSet?.has(entry.value) ?? false;
|
|
740
|
+
const estimatedTextW = entry.label.length * LEGEND_ENTRY_FONT_W;
|
|
730
741
|
|
|
731
742
|
const entryG = gEl.append('g')
|
|
732
743
|
.attr('data-legend-entry', entry.value)
|
|
733
|
-
.
|
|
744
|
+
.attr('transform', `translate(${estimatedX}, 0)`)
|
|
745
|
+
.style('cursor', 'pointer');
|
|
746
|
+
|
|
747
|
+
// Transparent hit-area rect
|
|
748
|
+
const entryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
749
|
+
entryG.append('rect')
|
|
750
|
+
.attr('x', -2)
|
|
751
|
+
.attr('y', 0)
|
|
752
|
+
.attr('width', entryW + 4)
|
|
753
|
+
.attr('height', LEGEND_HEIGHT)
|
|
754
|
+
.attr('fill', 'transparent');
|
|
734
755
|
|
|
735
756
|
if (isHidden) {
|
|
736
|
-
// Hidden: hollow ring + dimmed text (strikethrough-like)
|
|
737
757
|
entryG.append('circle')
|
|
738
|
-
.attr('cx',
|
|
758
|
+
.attr('cx', LEGEND_DOT_R)
|
|
739
759
|
.attr('cy', LEGEND_HEIGHT / 2)
|
|
740
760
|
.attr('r', LEGEND_DOT_R)
|
|
741
761
|
.attr('fill', 'none')
|
|
@@ -743,16 +763,15 @@ export function renderInitiativeStatus(
|
|
|
743
763
|
.attr('stroke-width', 1.2)
|
|
744
764
|
.attr('opacity', 0.5);
|
|
745
765
|
} else {
|
|
746
|
-
// Visible: solid dot
|
|
747
766
|
entryG.append('circle')
|
|
748
|
-
.attr('cx',
|
|
767
|
+
.attr('cx', LEGEND_DOT_R)
|
|
749
768
|
.attr('cy', LEGEND_HEIGHT / 2)
|
|
750
769
|
.attr('r', LEGEND_DOT_R)
|
|
751
770
|
.attr('fill', entry.color);
|
|
752
771
|
}
|
|
753
772
|
|
|
754
|
-
entryG.append('text')
|
|
755
|
-
.attr('x',
|
|
773
|
+
const textEl = entryG.append('text')
|
|
774
|
+
.attr('x', LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP)
|
|
756
775
|
.attr('y', LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1)
|
|
757
776
|
.attr('font-size', LEGEND_ENTRY_FONT_SIZE)
|
|
758
777
|
.attr('fill', palette.textMuted)
|
|
@@ -761,7 +780,20 @@ export function renderInitiativeStatus(
|
|
|
761
780
|
.attr('text-decoration', isHidden ? 'line-through' : 'none')
|
|
762
781
|
.text(entry.label);
|
|
763
782
|
|
|
764
|
-
|
|
783
|
+
entryData.push({ g: entryG, textEl: textEl.node()!, estimatedW: estimatedTextW });
|
|
784
|
+
estimatedX += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + estimatedTextW + LEGEND_ENTRY_TRAIL;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Reflow using measured text widths for even spacing
|
|
788
|
+
let reflowX = entryStartX;
|
|
789
|
+
for (const ed of entryData) {
|
|
790
|
+
const measuredW = ed.textEl.getComputedTextLength?.() ?? 0;
|
|
791
|
+
const textW = measuredW > 0 ? measuredW : ed.estimatedW;
|
|
792
|
+
ed.g.attr('transform', `translate(${reflowX}, 0)`);
|
|
793
|
+
// Update hit-area rect width to match actual width
|
|
794
|
+
const actualEntryW = LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + textW + LEGEND_ENTRY_TRAIL;
|
|
795
|
+
ed.g.select('rect').attr('width', actualEntryW + 4);
|
|
796
|
+
reflowX += actualEntryW;
|
|
765
797
|
}
|
|
766
798
|
}
|
|
767
799
|
|