@diagrammo/dgmo 0.6.2 → 0.6.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/.claude/commands/dgmo.md +231 -13
- package/AGENTS.md +148 -0
- package/dist/cli.cjs +327 -153
- package/dist/index.cjs +305 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +303 -177
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/c4/layout.ts +0 -5
- package/src/c4/parser.ts +0 -16
- package/src/c4/renderer.ts +1 -5
- package/src/class/layout.ts +0 -1
- package/src/class/parser.ts +28 -0
- package/src/class/renderer.ts +5 -26
- package/src/cli.ts +563 -14
- package/src/completion.ts +58 -0
- package/src/d3.ts +58 -106
- package/src/dgmo-router.ts +0 -57
- package/src/echarts.ts +96 -55
- package/src/er/parser.ts +30 -1
- package/src/er/renderer.ts +1 -2
- package/src/graph/flowchart-parser.ts +27 -4
- package/src/graph/flowchart-renderer.ts +1 -2
- package/src/graph/state-parser.ts +0 -1
- package/src/graph/state-renderer.ts +1 -3
- package/src/index.ts +10 -0
- package/src/infra/compute.ts +0 -7
- package/src/infra/layout.ts +0 -2
- package/src/infra/parser.ts +46 -4
- package/src/infra/renderer.ts +1 -15
- package/src/initiative-status/renderer.ts +5 -25
- package/src/kanban/parser.ts +0 -2
- package/src/org/layout.ts +0 -4
- package/src/org/renderer.ts +7 -28
- package/src/sequence/parser.ts +14 -11
- package/src/sequence/renderer.ts +0 -2
- package/src/sequence/tag-resolution.ts +0 -1
- package/src/sitemap/layout.ts +1 -14
- package/src/sitemap/parser.ts +1 -2
- package/src/sitemap/renderer.ts +0 -3
- package/src/utils/arrows.ts +7 -7
- package/src/utils/export-container.ts +40 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagram symbol extraction API.
|
|
3
|
+
*
|
|
4
|
+
* Provides DiagramSymbols interface + extractDiagramSymbols() dispatch.
|
|
5
|
+
* Each diagram type registers its own extractor via registerExtractor().
|
|
6
|
+
* All built-in extractors are registered at module init below.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { extractSymbols as extractErSymbols } from './er/parser';
|
|
10
|
+
import { extractSymbols as extractFlowchartSymbols } from './graph/flowchart-parser';
|
|
11
|
+
import { extractSymbols as extractInfraSymbols } from './infra/parser';
|
|
12
|
+
import { extractSymbols as extractClassSymbols } from './class/parser';
|
|
13
|
+
|
|
14
|
+
// ChartType is just a string — alias here for documentation clarity.
|
|
15
|
+
export type ChartType = string;
|
|
16
|
+
|
|
17
|
+
export interface DiagramSymbols {
|
|
18
|
+
kind: ChartType;
|
|
19
|
+
entities: string[]; // table names, node IDs, class names, etc.
|
|
20
|
+
keywords: string[]; // diagram-specific reserved words
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ExtractFn = (docText: string) => DiagramSymbols;
|
|
24
|
+
|
|
25
|
+
const registry = new Map<ChartType, ExtractFn>();
|
|
26
|
+
|
|
27
|
+
export function registerExtractor(kind: ChartType, fn: ExtractFn): void {
|
|
28
|
+
registry.set(kind, fn);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Extract diagram symbols from document text.
|
|
33
|
+
* Returns null if the chart type is unknown or has no registered extractor.
|
|
34
|
+
*/
|
|
35
|
+
export function extractDiagramSymbols(docText: string): DiagramSymbols | null {
|
|
36
|
+
// Parse chartType from first `chart:` line — lightweight, no full parser.
|
|
37
|
+
let chartType: string | null = null;
|
|
38
|
+
for (const line of docText.split('\n')) {
|
|
39
|
+
const m = line.match(/^\s*chart\s*:\s*(.+)/i);
|
|
40
|
+
if (m) {
|
|
41
|
+
chartType = m[1]!.trim().toLowerCase();
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!chartType) return null;
|
|
46
|
+
const fn = registry.get(chartType);
|
|
47
|
+
if (!fn) return null;
|
|
48
|
+
return fn(docText);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================================
|
|
52
|
+
// Register built-in extractors
|
|
53
|
+
// ============================================================
|
|
54
|
+
|
|
55
|
+
registerExtractor('er', extractErSymbols);
|
|
56
|
+
registerExtractor('flowchart', extractFlowchartSymbols);
|
|
57
|
+
registerExtractor('infra', extractInfraSymbols);
|
|
58
|
+
registerExtractor('class', extractClassSymbols);
|
package/src/d3.ts
CHANGED
|
@@ -1861,7 +1861,6 @@ export function renderArcDiagram(
|
|
|
1861
1861
|
const positions = groupNodes.map((n) => yScale(n)!);
|
|
1862
1862
|
const minY = Math.min(...positions) - bandPad;
|
|
1863
1863
|
const maxY = Math.max(...positions) + bandPad;
|
|
1864
|
-
const bandColor = group.color ?? mutedColor;
|
|
1865
1864
|
|
|
1866
1865
|
g.append('rect')
|
|
1867
1866
|
.attr('class', 'arc-group-band')
|
|
@@ -1996,7 +1995,6 @@ export function renderArcDiagram(
|
|
|
1996
1995
|
const positions = groupNodes.map((n) => xScale(n)!);
|
|
1997
1996
|
const minX = Math.min(...positions) - bandPad;
|
|
1998
1997
|
const maxX = Math.max(...positions) + bandPad;
|
|
1999
|
-
const bandColor = group.color ?? mutedColor;
|
|
2000
1998
|
|
|
2001
1999
|
g.append('rect')
|
|
2002
2000
|
.attr('class', 'arc-group-band')
|
|
@@ -2864,6 +2862,7 @@ export function renderTimeline(
|
|
|
2864
2862
|
const textColor = palette.text;
|
|
2865
2863
|
const mutedColor = palette.border;
|
|
2866
2864
|
const bgColor = palette.bg;
|
|
2865
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
2867
2866
|
const colors = getSeriesColors(palette);
|
|
2868
2867
|
|
|
2869
2868
|
// Assign colors to groups
|
|
@@ -3254,7 +3253,7 @@ export function renderTimeline(
|
|
|
3254
3253
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
3255
3254
|
const rectH = Math.max(y2 - y, 4);
|
|
3256
3255
|
|
|
3257
|
-
let fill: string = evColor;
|
|
3256
|
+
let fill: string = mix(evColor, bg, 30);
|
|
3258
3257
|
if (ev.uncertain) {
|
|
3259
3258
|
const gradientId = `uncertain-vg-${ev.lineNumber}`;
|
|
3260
3259
|
const defs =
|
|
@@ -3276,7 +3275,7 @@ export function renderTimeline(
|
|
|
3276
3275
|
.enter()
|
|
3277
3276
|
.append('stop')
|
|
3278
3277
|
.attr('offset', (d) => d.offset)
|
|
3279
|
-
.attr('stop-color', laneColor)
|
|
3278
|
+
.attr('stop-color', mix(laneColor, bg, 30))
|
|
3280
3279
|
.attr('stop-opacity', (d) => d.opacity);
|
|
3281
3280
|
fill = `url(#${gradientId})`;
|
|
3282
3281
|
}
|
|
@@ -3288,7 +3287,9 @@ export function renderTimeline(
|
|
|
3288
3287
|
.attr('width', 12)
|
|
3289
3288
|
.attr('height', rectH)
|
|
3290
3289
|
.attr('rx', 4)
|
|
3291
|
-
.attr('fill', fill)
|
|
3290
|
+
.attr('fill', fill)
|
|
3291
|
+
.attr('stroke', evColor)
|
|
3292
|
+
.attr('stroke-width', 2);
|
|
3292
3293
|
evG
|
|
3293
3294
|
.append('text')
|
|
3294
3295
|
.attr('x', laneCenter + 14)
|
|
@@ -3303,9 +3304,9 @@ export function renderTimeline(
|
|
|
3303
3304
|
.attr('cx', laneCenter)
|
|
3304
3305
|
.attr('cy', y)
|
|
3305
3306
|
.attr('r', 4)
|
|
3306
|
-
.attr('fill', evColor)
|
|
3307
|
-
.attr('stroke',
|
|
3308
|
-
.attr('stroke-width',
|
|
3307
|
+
.attr('fill', mix(evColor, bg, 30))
|
|
3308
|
+
.attr('stroke', evColor)
|
|
3309
|
+
.attr('stroke-width', 2);
|
|
3309
3310
|
evG
|
|
3310
3311
|
.append('text')
|
|
3311
3312
|
.attr('x', laneCenter + 10)
|
|
@@ -3472,7 +3473,7 @@ export function renderTimeline(
|
|
|
3472
3473
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
3473
3474
|
const rectH = Math.max(y2 - y, 4);
|
|
3474
3475
|
|
|
3475
|
-
let fill: string = color;
|
|
3476
|
+
let fill: string = mix(color, bg, 30);
|
|
3476
3477
|
if (ev.uncertain) {
|
|
3477
3478
|
const gradientId = `uncertain-v-${ev.lineNumber}`;
|
|
3478
3479
|
const defs =
|
|
@@ -3494,7 +3495,7 @@ export function renderTimeline(
|
|
|
3494
3495
|
.enter()
|
|
3495
3496
|
.append('stop')
|
|
3496
3497
|
.attr('offset', (d) => d.offset)
|
|
3497
|
-
.attr('stop-color', color)
|
|
3498
|
+
.attr('stop-color', mix(color, bg, 30))
|
|
3498
3499
|
.attr('stop-opacity', (d) => d.opacity);
|
|
3499
3500
|
fill = `url(#${gradientId})`;
|
|
3500
3501
|
}
|
|
@@ -3506,7 +3507,9 @@ export function renderTimeline(
|
|
|
3506
3507
|
.attr('width', 12)
|
|
3507
3508
|
.attr('height', rectH)
|
|
3508
3509
|
.attr('rx', 4)
|
|
3509
|
-
.attr('fill', fill)
|
|
3510
|
+
.attr('fill', fill)
|
|
3511
|
+
.attr('stroke', color)
|
|
3512
|
+
.attr('stroke-width', 2);
|
|
3510
3513
|
evG
|
|
3511
3514
|
.append('text')
|
|
3512
3515
|
.attr('x', axisX + 16)
|
|
@@ -3521,9 +3524,9 @@ export function renderTimeline(
|
|
|
3521
3524
|
.attr('cx', axisX)
|
|
3522
3525
|
.attr('cy', y)
|
|
3523
3526
|
.attr('r', 4)
|
|
3524
|
-
.attr('fill', color)
|
|
3525
|
-
.attr('stroke',
|
|
3526
|
-
.attr('stroke-width',
|
|
3527
|
+
.attr('fill', mix(color, bg, 30))
|
|
3528
|
+
.attr('stroke', color)
|
|
3529
|
+
.attr('stroke-width', 2);
|
|
3527
3530
|
evG
|
|
3528
3531
|
.append('text')
|
|
3529
3532
|
.attr('x', axisX + 16)
|
|
@@ -3781,7 +3784,7 @@ export function renderTimeline(
|
|
|
3781
3784
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
3782
3785
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
3783
3786
|
|
|
3784
|
-
let fill: string = evColor;
|
|
3787
|
+
let fill: string = mix(evColor, bg, 30);
|
|
3785
3788
|
if (ev.uncertain) {
|
|
3786
3789
|
// Create gradient for uncertain end - fades last 20%
|
|
3787
3790
|
const gradientId = `uncertain-${ev.lineNumber}`;
|
|
@@ -3803,7 +3806,7 @@ export function renderTimeline(
|
|
|
3803
3806
|
.enter()
|
|
3804
3807
|
.append('stop')
|
|
3805
3808
|
.attr('offset', (d) => d.offset)
|
|
3806
|
-
.attr('stop-color', evColor)
|
|
3809
|
+
.attr('stop-color', mix(evColor, bg, 30))
|
|
3807
3810
|
.attr('stop-opacity', (d) => d.opacity);
|
|
3808
3811
|
fill = `url(#${gradientId})`;
|
|
3809
3812
|
}
|
|
@@ -3815,17 +3818,19 @@ export function renderTimeline(
|
|
|
3815
3818
|
.attr('width', rectW)
|
|
3816
3819
|
.attr('height', BAR_H)
|
|
3817
3820
|
.attr('rx', 4)
|
|
3818
|
-
.attr('fill', fill)
|
|
3821
|
+
.attr('fill', fill)
|
|
3822
|
+
.attr('stroke', evColor)
|
|
3823
|
+
.attr('stroke-width', 2);
|
|
3819
3824
|
|
|
3820
3825
|
if (labelFitsInside) {
|
|
3821
|
-
// Text inside bar -
|
|
3826
|
+
// Text inside bar - use textColor for readability on muted fill
|
|
3822
3827
|
evG
|
|
3823
3828
|
.append('text')
|
|
3824
3829
|
.attr('x', x + 8)
|
|
3825
3830
|
.attr('y', y)
|
|
3826
3831
|
.attr('dy', '0.35em')
|
|
3827
3832
|
.attr('text-anchor', 'start')
|
|
3828
|
-
.attr('fill',
|
|
3833
|
+
.attr('fill', textColor)
|
|
3829
3834
|
.attr('font-size', '14px')
|
|
3830
3835
|
.attr('font-weight', '700')
|
|
3831
3836
|
.text(ev.label);
|
|
@@ -3856,9 +3861,9 @@ export function renderTimeline(
|
|
|
3856
3861
|
.attr('cx', x)
|
|
3857
3862
|
.attr('cy', y)
|
|
3858
3863
|
.attr('r', 5)
|
|
3859
|
-
.attr('fill', evColor)
|
|
3860
|
-
.attr('stroke',
|
|
3861
|
-
.attr('stroke-width',
|
|
3864
|
+
.attr('fill', mix(evColor, bg, 30))
|
|
3865
|
+
.attr('stroke', evColor)
|
|
3866
|
+
.attr('stroke-width', 2);
|
|
3862
3867
|
evG
|
|
3863
3868
|
.append('text')
|
|
3864
3869
|
.attr('x', flipLeft ? x - 10 : x + 10)
|
|
@@ -4041,7 +4046,7 @@ export function renderTimeline(
|
|
|
4041
4046
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
4042
4047
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
4043
4048
|
|
|
4044
|
-
let fill: string = color;
|
|
4049
|
+
let fill: string = mix(color, bg, 30);
|
|
4045
4050
|
if (ev.uncertain) {
|
|
4046
4051
|
// Create gradient for uncertain end - fades last 20%
|
|
4047
4052
|
const gradientId = `uncertain-ts-${ev.lineNumber}`;
|
|
@@ -4063,7 +4068,7 @@ export function renderTimeline(
|
|
|
4063
4068
|
.enter()
|
|
4064
4069
|
.append('stop')
|
|
4065
4070
|
.attr('offset', (d) => d.offset)
|
|
4066
|
-
.attr('stop-color', color)
|
|
4071
|
+
.attr('stop-color', mix(color, bg, 30))
|
|
4067
4072
|
.attr('stop-opacity', (d) => d.opacity);
|
|
4068
4073
|
fill = `url(#${gradientId})`;
|
|
4069
4074
|
}
|
|
@@ -4075,17 +4080,19 @@ export function renderTimeline(
|
|
|
4075
4080
|
.attr('width', rectW)
|
|
4076
4081
|
.attr('height', BAR_H)
|
|
4077
4082
|
.attr('rx', 4)
|
|
4078
|
-
.attr('fill', fill)
|
|
4083
|
+
.attr('fill', fill)
|
|
4084
|
+
.attr('stroke', color)
|
|
4085
|
+
.attr('stroke-width', 2);
|
|
4079
4086
|
|
|
4080
4087
|
if (labelFitsInside) {
|
|
4081
|
-
// Text inside bar -
|
|
4088
|
+
// Text inside bar - use textColor for readability on muted fill
|
|
4082
4089
|
evG
|
|
4083
4090
|
.append('text')
|
|
4084
4091
|
.attr('x', x + 8)
|
|
4085
4092
|
.attr('y', y)
|
|
4086
4093
|
.attr('dy', '0.35em')
|
|
4087
4094
|
.attr('text-anchor', 'start')
|
|
4088
|
-
.attr('fill',
|
|
4095
|
+
.attr('fill', textColor)
|
|
4089
4096
|
.attr('font-size', '14px')
|
|
4090
4097
|
.attr('font-weight', '700')
|
|
4091
4098
|
.text(ev.label);
|
|
@@ -4116,9 +4123,9 @@ export function renderTimeline(
|
|
|
4116
4123
|
.attr('cx', x)
|
|
4117
4124
|
.attr('cy', y)
|
|
4118
4125
|
.attr('r', 5)
|
|
4119
|
-
.attr('fill', color)
|
|
4120
|
-
.attr('stroke',
|
|
4121
|
-
.attr('stroke-width',
|
|
4126
|
+
.attr('fill', mix(color, bg, 30))
|
|
4127
|
+
.attr('stroke', color)
|
|
4128
|
+
.attr('stroke-width', 2);
|
|
4122
4129
|
evG
|
|
4123
4130
|
.append('text')
|
|
4124
4131
|
.attr('x', flipLeft ? x - 10 : x + 10)
|
|
@@ -4438,8 +4445,8 @@ export function renderTimeline(
|
|
|
4438
4445
|
color = ev.group && groupColorMap.has(ev.group)
|
|
4439
4446
|
? groupColorMap.get(ev.group)! : textColor;
|
|
4440
4447
|
}
|
|
4441
|
-
el.selectAll('rect').attr('fill', color);
|
|
4442
|
-
el.selectAll('circle:not(.tl-event-point-outline)').attr('fill', color);
|
|
4448
|
+
el.selectAll('rect').attr('fill', mix(color, bg, 30)).attr('stroke', color);
|
|
4449
|
+
el.selectAll('circle:not(.tl-event-point-outline)').attr('fill', mix(color, bg, 30)).attr('stroke', color);
|
|
4443
4450
|
});
|
|
4444
4451
|
}
|
|
4445
4452
|
|
|
@@ -4635,46 +4642,6 @@ function renderWordCloudAsync(
|
|
|
4635
4642
|
// Venn Diagram Math Helpers
|
|
4636
4643
|
// ============================================================
|
|
4637
4644
|
|
|
4638
|
-
function radiusFromArea(area: number): number {
|
|
4639
|
-
return Math.sqrt(area / Math.PI);
|
|
4640
|
-
}
|
|
4641
|
-
|
|
4642
|
-
function circleOverlapArea(r1: number, r2: number, d: number): number {
|
|
4643
|
-
// No overlap
|
|
4644
|
-
if (d >= r1 + r2) return 0;
|
|
4645
|
-
// Full containment
|
|
4646
|
-
if (d + Math.min(r1, r2) <= Math.max(r1, r2)) {
|
|
4647
|
-
return Math.PI * Math.min(r1, r2) ** 2;
|
|
4648
|
-
}
|
|
4649
|
-
const part1 = r1 * r1 * Math.acos((d * d + r1 * r1 - r2 * r2) / (2 * d * r1));
|
|
4650
|
-
const part2 = r2 * r2 * Math.acos((d * d + r2 * r2 - r1 * r1) / (2 * d * r2));
|
|
4651
|
-
const part3 =
|
|
4652
|
-
0.5 *
|
|
4653
|
-
Math.sqrt((-d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (d + r1 + r2));
|
|
4654
|
-
return part1 + part2 - part3;
|
|
4655
|
-
}
|
|
4656
|
-
|
|
4657
|
-
function distanceForOverlap(
|
|
4658
|
-
r1: number,
|
|
4659
|
-
r2: number,
|
|
4660
|
-
targetArea: number
|
|
4661
|
-
): number {
|
|
4662
|
-
if (targetArea <= 0) return r1 + r2;
|
|
4663
|
-
const minR = Math.min(r1, r2);
|
|
4664
|
-
if (targetArea >= Math.PI * minR * minR) return Math.abs(r1 - r2);
|
|
4665
|
-
let lo = Math.abs(r1 - r2);
|
|
4666
|
-
let hi = r1 + r2;
|
|
4667
|
-
for (let i = 0; i < 64; i++) {
|
|
4668
|
-
const mid = (lo + hi) / 2;
|
|
4669
|
-
if (circleOverlapArea(r1, r2, mid) > targetArea) {
|
|
4670
|
-
lo = mid;
|
|
4671
|
-
} else {
|
|
4672
|
-
hi = mid;
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
return (lo + hi) / 2;
|
|
4676
|
-
}
|
|
4677
|
-
|
|
4678
4645
|
interface Point {
|
|
4679
4646
|
x: number;
|
|
4680
4647
|
y: number;
|
|
@@ -4686,29 +4653,6 @@ interface Circle {
|
|
|
4686
4653
|
r: number;
|
|
4687
4654
|
}
|
|
4688
4655
|
|
|
4689
|
-
function thirdCirclePosition(
|
|
4690
|
-
ax: number,
|
|
4691
|
-
ay: number,
|
|
4692
|
-
dAC: number,
|
|
4693
|
-
bx: number,
|
|
4694
|
-
by: number,
|
|
4695
|
-
dBC: number
|
|
4696
|
-
): Point {
|
|
4697
|
-
const dx = bx - ax;
|
|
4698
|
-
const dy = by - ay;
|
|
4699
|
-
const dAB = Math.sqrt(dx * dx + dy * dy);
|
|
4700
|
-
if (dAB === 0) return { x: ax + dAC, y: ay };
|
|
4701
|
-
const cosA = (dAB * dAB + dAC * dAC - dBC * dBC) / (2 * dAB * dAC);
|
|
4702
|
-
const sinA = Math.sqrt(Math.max(0, 1 - cosA * cosA));
|
|
4703
|
-
const ux = dx / dAB;
|
|
4704
|
-
const uy = dy / dAB;
|
|
4705
|
-
// Place C above the AB line
|
|
4706
|
-
return {
|
|
4707
|
-
x: ax + dAC * (cosA * ux - sinA * uy),
|
|
4708
|
-
y: ay + dAC * (cosA * uy + sinA * ux),
|
|
4709
|
-
};
|
|
4710
|
-
}
|
|
4711
|
-
|
|
4712
4656
|
function fitCirclesToContainerAsymmetric(
|
|
4713
4657
|
circles: Circle[],
|
|
4714
4658
|
w: number,
|
|
@@ -5255,7 +5199,6 @@ export function renderQuadrant(
|
|
|
5255
5199
|
const init = initD3Chart(container, palette, exportDims);
|
|
5256
5200
|
if (!init) return;
|
|
5257
5201
|
const { svg, width, height, textColor } = init;
|
|
5258
|
-
const mutedColor = palette.textMuted;
|
|
5259
5202
|
const borderColor = palette.border;
|
|
5260
5203
|
|
|
5261
5204
|
// Default quadrant colors with alpha
|
|
@@ -5300,14 +5243,24 @@ export function renderQuadrant(
|
|
|
5300
5243
|
return `#${c(ar,br)}${c(ag,bg)}${c(ab,bb)}`;
|
|
5301
5244
|
};
|
|
5302
5245
|
|
|
5303
|
-
|
|
5304
|
-
|
|
5246
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
5247
|
+
|
|
5248
|
+
// Full palette color for a quadrant (used for border and label tinting)
|
|
5249
|
+
const getQuadrantColor = (
|
|
5305
5250
|
label: QuadrantLabel | null,
|
|
5306
5251
|
defaultIdx: number
|
|
5307
5252
|
): string => {
|
|
5308
5253
|
return label?.color ?? defaultColors[defaultIdx % defaultColors.length];
|
|
5309
5254
|
};
|
|
5310
5255
|
|
|
5256
|
+
// Muted fill: palette color blended 30% toward bg — matches other chart fill style
|
|
5257
|
+
const getQuadrantFill = (
|
|
5258
|
+
label: QuadrantLabel | null,
|
|
5259
|
+
defaultIdx: number
|
|
5260
|
+
): string => {
|
|
5261
|
+
return mixHex(getQuadrantColor(label, defaultIdx), bg, 30);
|
|
5262
|
+
};
|
|
5263
|
+
|
|
5311
5264
|
// Quadrant definitions: position, rect bounds, label position
|
|
5312
5265
|
const quadrantDefs: {
|
|
5313
5266
|
position: QuadrantPosition;
|
|
@@ -5378,17 +5331,16 @@ export function renderQuadrant(
|
|
|
5378
5331
|
.attr('width', (d) => d.w)
|
|
5379
5332
|
.attr('height', (d) => d.h)
|
|
5380
5333
|
.attr('fill', (d) => getQuadrantFill(d.label, d.colorIdx))
|
|
5381
|
-
.attr('stroke',
|
|
5382
|
-
.attr('stroke-width',
|
|
5334
|
+
.attr('stroke', (d) => getQuadrantColor(d.label, d.colorIdx))
|
|
5335
|
+
.attr('stroke-width', 2);
|
|
5383
5336
|
|
|
5384
5337
|
// White text for points; quadrant labels use a darkened shade of their fill
|
|
5385
|
-
const contrastColor = '#ffffff';
|
|
5386
5338
|
const shadowColor = 'rgba(0,0,0,0.4)';
|
|
5387
5339
|
|
|
5388
|
-
// Darken the
|
|
5340
|
+
// Darken the full palette color (not the muted fill) to create a watermark-style label
|
|
5389
5341
|
const getQuadrantLabelColor = (d: (typeof quadrantDefs)[number]): string => {
|
|
5390
|
-
const
|
|
5391
|
-
return mixHex('#000000',
|
|
5342
|
+
const color = getQuadrantColor(d.label, d.colorIdx);
|
|
5343
|
+
return mixHex('#000000', color, 40);
|
|
5392
5344
|
};
|
|
5393
5345
|
|
|
5394
5346
|
// Scale label font size to fit within quadrant bounds, wrapping into multiple lines if needed
|
|
@@ -5666,13 +5618,13 @@ export function renderQuadrant(
|
|
|
5666
5618
|
.attr('stroke', pointColor)
|
|
5667
5619
|
.attr('stroke-width', 2);
|
|
5668
5620
|
|
|
5669
|
-
// Label (
|
|
5621
|
+
// Label (palette text color adapts to light/dark mode)
|
|
5670
5622
|
pointG
|
|
5671
5623
|
.append('text')
|
|
5672
5624
|
.attr('x', cx)
|
|
5673
5625
|
.attr('y', cy - 10)
|
|
5674
5626
|
.attr('text-anchor', 'middle')
|
|
5675
|
-
.attr('fill',
|
|
5627
|
+
.attr('fill', textColor)
|
|
5676
5628
|
.attr('font-size', '12px')
|
|
5677
5629
|
.attr('font-weight', '700')
|
|
5678
5630
|
.style('text-shadow', `0 1px 2px ${shadowColor}`)
|
package/src/dgmo-router.ts
CHANGED
|
@@ -18,63 +18,6 @@ import { looksLikeSitemap, parseSitemap } from './sitemap/parser';
|
|
|
18
18
|
import { parseInfra } from './infra/parser';
|
|
19
19
|
import type { DgmoError } from './diagnostics';
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Framework identifiers used by the .dgmo router internally.
|
|
23
|
-
* Not part of the public API — use RenderCategory instead.
|
|
24
|
-
*/
|
|
25
|
-
type DgmoFramework = 'echart' | 'd3' | 'mermaid';
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Maps every supported chart type string to its backing framework (internal).
|
|
29
|
-
*/
|
|
30
|
-
const DGMO_CHART_TYPE_MAP: Record<string, DgmoFramework> = {
|
|
31
|
-
// Standard charts (via ECharts)
|
|
32
|
-
bar: 'echart',
|
|
33
|
-
line: 'echart',
|
|
34
|
-
'multi-line': 'echart',
|
|
35
|
-
area: 'echart',
|
|
36
|
-
pie: 'echart',
|
|
37
|
-
doughnut: 'echart',
|
|
38
|
-
radar: 'echart',
|
|
39
|
-
'polar-area': 'echart',
|
|
40
|
-
'bar-stacked': 'echart',
|
|
41
|
-
|
|
42
|
-
// ECharts
|
|
43
|
-
scatter: 'echart',
|
|
44
|
-
sankey: 'echart',
|
|
45
|
-
chord: 'echart',
|
|
46
|
-
function: 'echart',
|
|
47
|
-
heatmap: 'echart',
|
|
48
|
-
funnel: 'echart',
|
|
49
|
-
|
|
50
|
-
// D3
|
|
51
|
-
slope: 'd3',
|
|
52
|
-
wordcloud: 'd3',
|
|
53
|
-
arc: 'd3',
|
|
54
|
-
timeline: 'd3',
|
|
55
|
-
venn: 'd3',
|
|
56
|
-
quadrant: 'd3',
|
|
57
|
-
sequence: 'd3',
|
|
58
|
-
flowchart: 'd3',
|
|
59
|
-
class: 'd3',
|
|
60
|
-
er: 'd3',
|
|
61
|
-
org: 'd3',
|
|
62
|
-
kanban: 'd3',
|
|
63
|
-
c4: 'd3',
|
|
64
|
-
'initiative-status': 'd3',
|
|
65
|
-
state: 'd3',
|
|
66
|
-
sitemap: 'd3',
|
|
67
|
-
infra: 'd3',
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Returns the internal framework for a given chart type, or `null` if unknown.
|
|
72
|
-
* Internal only — use getRenderCategory() for public dispatch.
|
|
73
|
-
*/
|
|
74
|
-
function getDgmoFramework(chartType: string): DgmoFramework | null {
|
|
75
|
-
return DGMO_CHART_TYPE_MAP[chartType.toLowerCase()] ?? null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
21
|
/**
|
|
79
22
|
* Extracts the `chart:` type value from raw file content.
|
|
80
23
|
* Falls back to inference when no explicit `chart:` line is found
|