@diagrammo/dgmo 0.2.8 → 0.2.10
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/README.md +29 -1
- package/dist/cli.cjs +105 -105
- package/dist/index.cjs +6457 -6137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +6474 -6158
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/chart.ts +11 -0
- package/src/cli.ts +14 -34
- package/src/d3.ts +160 -15
- package/src/echarts.ts +56 -2
- package/src/graph/flowchart-parser.ts +1 -0
- package/src/graph/flowchart-renderer.ts +15 -4
- package/src/graph/types.ts +1 -0
- package/src/index.ts +7 -0
- package/src/render.ts +68 -0
- package/src/sequence/parser.ts +3 -0
- package/src/sequence/renderer.ts +311 -127
package/src/echarts.ts
CHANGED
|
@@ -54,6 +54,7 @@ export interface ParsedHeatmapRow {
|
|
|
54
54
|
export interface ParsedEChart {
|
|
55
55
|
type: EChartsChartType;
|
|
56
56
|
title?: string;
|
|
57
|
+
titleLineNumber?: number;
|
|
57
58
|
series?: string;
|
|
58
59
|
seriesNames?: string[];
|
|
59
60
|
seriesNameColors?: (string | undefined)[];
|
|
@@ -174,6 +175,7 @@ export function parseEChart(
|
|
|
174
175
|
|
|
175
176
|
if (key === 'title') {
|
|
176
177
|
result.title = value;
|
|
178
|
+
result.titleLineNumber = lineNumber;
|
|
177
179
|
continue;
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -536,6 +538,7 @@ function buildSankeyOption(
|
|
|
536
538
|
type: 'sankey',
|
|
537
539
|
emphasis: {
|
|
538
540
|
focus: 'adjacency',
|
|
541
|
+
blurScope: 'global' as const,
|
|
539
542
|
},
|
|
540
543
|
nodeAlign: 'left',
|
|
541
544
|
nodeGap: 12,
|
|
@@ -744,6 +747,10 @@ function buildFunctionOption(
|
|
|
744
747
|
itemStyle: {
|
|
745
748
|
color: fnColor,
|
|
746
749
|
},
|
|
750
|
+
emphasis: {
|
|
751
|
+
focus: 'self' as const,
|
|
752
|
+
blurScope: 'global' as const,
|
|
753
|
+
},
|
|
747
754
|
};
|
|
748
755
|
});
|
|
749
756
|
|
|
@@ -1114,6 +1121,8 @@ function buildHeatmapOption(
|
|
|
1114
1121
|
fontWeight: 'bold' as const,
|
|
1115
1122
|
},
|
|
1116
1123
|
emphasis: {
|
|
1124
|
+
focus: 'self' as const,
|
|
1125
|
+
blurScope: 'global' as const,
|
|
1117
1126
|
itemStyle: {
|
|
1118
1127
|
shadowBlur: 10,
|
|
1119
1128
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
@@ -1208,6 +1217,8 @@ function buildFunnelOption(
|
|
|
1208
1217
|
lineStyle: { color: textColor, opacity: 0.3 },
|
|
1209
1218
|
},
|
|
1210
1219
|
emphasis: {
|
|
1220
|
+
focus: 'self' as const,
|
|
1221
|
+
blurScope: 'global' as const,
|
|
1211
1222
|
label: {
|
|
1212
1223
|
fontSize: 15,
|
|
1213
1224
|
},
|
|
@@ -1392,6 +1403,10 @@ function buildBarOption(
|
|
|
1392
1403
|
{
|
|
1393
1404
|
type: 'bar',
|
|
1394
1405
|
data,
|
|
1406
|
+
emphasis: {
|
|
1407
|
+
focus: 'self' as const,
|
|
1408
|
+
blurScope: 'global' as const,
|
|
1409
|
+
},
|
|
1395
1410
|
},
|
|
1396
1411
|
],
|
|
1397
1412
|
};
|
|
@@ -1440,6 +1455,10 @@ function buildLineOption(
|
|
|
1440
1455
|
symbolSize: 8,
|
|
1441
1456
|
lineStyle: { color: lineColor, width: 3 },
|
|
1442
1457
|
itemStyle: { color: lineColor },
|
|
1458
|
+
emphasis: {
|
|
1459
|
+
focus: 'self' as const,
|
|
1460
|
+
blurScope: 'global' as const,
|
|
1461
|
+
},
|
|
1443
1462
|
},
|
|
1444
1463
|
],
|
|
1445
1464
|
};
|
|
@@ -1474,6 +1493,10 @@ function buildMultiLineOption(
|
|
|
1474
1493
|
symbolSize: 8,
|
|
1475
1494
|
lineStyle: { color, width: 3 },
|
|
1476
1495
|
itemStyle: { color },
|
|
1496
|
+
emphasis: {
|
|
1497
|
+
focus: 'self' as const,
|
|
1498
|
+
blurScope: 'global' as const,
|
|
1499
|
+
},
|
|
1477
1500
|
};
|
|
1478
1501
|
});
|
|
1479
1502
|
|
|
@@ -1548,11 +1571,26 @@ function buildAreaOption(
|
|
|
1548
1571
|
lineStyle: { color: lineColor, width: 3 },
|
|
1549
1572
|
itemStyle: { color: lineColor },
|
|
1550
1573
|
areaStyle: { opacity: 0.25 },
|
|
1574
|
+
emphasis: {
|
|
1575
|
+
focus: 'self' as const,
|
|
1576
|
+
blurScope: 'global' as const,
|
|
1577
|
+
},
|
|
1551
1578
|
},
|
|
1552
1579
|
],
|
|
1553
1580
|
};
|
|
1554
1581
|
}
|
|
1555
1582
|
|
|
1583
|
+
// ── Segment label formatter ──────────────────────────────────
|
|
1584
|
+
|
|
1585
|
+
function segmentLabelFormatter(mode: ParsedChart['labels']): string {
|
|
1586
|
+
switch (mode) {
|
|
1587
|
+
case 'name': return '{b}';
|
|
1588
|
+
case 'value': return '{b} — {c}';
|
|
1589
|
+
case 'percent': return '{b} — {d}%';
|
|
1590
|
+
default: return '{b} — {c} ({d}%)';
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1556
1594
|
// ── Pie / Doughnut ───────────────────────────────────────────
|
|
1557
1595
|
|
|
1558
1596
|
function buildPieOption(
|
|
@@ -1584,11 +1622,15 @@ function buildPieOption(
|
|
|
1584
1622
|
data,
|
|
1585
1623
|
label: {
|
|
1586
1624
|
position: 'outside',
|
|
1587
|
-
formatter:
|
|
1625
|
+
formatter: segmentLabelFormatter(parsed.labels),
|
|
1588
1626
|
color: textColor,
|
|
1589
1627
|
fontFamily: FONT_FAMILY,
|
|
1590
1628
|
},
|
|
1591
1629
|
labelLine: { show: true },
|
|
1630
|
+
emphasis: {
|
|
1631
|
+
focus: 'self' as const,
|
|
1632
|
+
blurScope: 'global' as const,
|
|
1633
|
+
},
|
|
1592
1634
|
},
|
|
1593
1635
|
],
|
|
1594
1636
|
};
|
|
@@ -1658,6 +1700,10 @@ function buildRadarOption(
|
|
|
1658
1700
|
},
|
|
1659
1701
|
},
|
|
1660
1702
|
],
|
|
1703
|
+
emphasis: {
|
|
1704
|
+
focus: 'self' as const,
|
|
1705
|
+
blurScope: 'global' as const,
|
|
1706
|
+
},
|
|
1661
1707
|
},
|
|
1662
1708
|
],
|
|
1663
1709
|
};
|
|
@@ -1694,11 +1740,15 @@ function buildPolarAreaOption(
|
|
|
1694
1740
|
data,
|
|
1695
1741
|
label: {
|
|
1696
1742
|
position: 'outside',
|
|
1697
|
-
formatter:
|
|
1743
|
+
formatter: segmentLabelFormatter(parsed.labels),
|
|
1698
1744
|
color: textColor,
|
|
1699
1745
|
fontFamily: FONT_FAMILY,
|
|
1700
1746
|
},
|
|
1701
1747
|
labelLine: { show: true },
|
|
1748
|
+
emphasis: {
|
|
1749
|
+
focus: 'self' as const,
|
|
1750
|
+
blurScope: 'global' as const,
|
|
1751
|
+
},
|
|
1702
1752
|
},
|
|
1703
1753
|
],
|
|
1704
1754
|
};
|
|
@@ -1741,6 +1791,10 @@ function buildBarStackedOption(
|
|
|
1741
1791
|
fontWeight: 'bold' as const,
|
|
1742
1792
|
fontFamily: FONT_FAMILY,
|
|
1743
1793
|
},
|
|
1794
|
+
emphasis: {
|
|
1795
|
+
focus: 'self' as const,
|
|
1796
|
+
blurScope: 'global' as const,
|
|
1797
|
+
},
|
|
1744
1798
|
};
|
|
1745
1799
|
});
|
|
1746
1800
|
|
|
@@ -257,7 +257,6 @@ export function renderFlowchart(
|
|
|
257
257
|
.append('svg')
|
|
258
258
|
.attr('width', width)
|
|
259
259
|
.attr('height', height)
|
|
260
|
-
.style('background', palette.bg)
|
|
261
260
|
.style('font-family', FONT_FAMILY);
|
|
262
261
|
|
|
263
262
|
// Defs: arrowhead markers
|
|
@@ -305,7 +304,7 @@ export function renderFlowchart(
|
|
|
305
304
|
|
|
306
305
|
// Title
|
|
307
306
|
if (graph.title) {
|
|
308
|
-
mainG
|
|
307
|
+
const titleEl = mainG
|
|
309
308
|
.append('text')
|
|
310
309
|
.attr('x', diagramW / 2)
|
|
311
310
|
.attr('y', TITLE_FONT_SIZE)
|
|
@@ -313,8 +312,19 @@ export function renderFlowchart(
|
|
|
313
312
|
.attr('fill', palette.text)
|
|
314
313
|
.attr('font-size', TITLE_FONT_SIZE)
|
|
315
314
|
.attr('font-weight', 'bold')
|
|
316
|
-
.attr('class', 'fc-title')
|
|
315
|
+
.attr('class', 'fc-title chart-title')
|
|
316
|
+
.style('cursor', onClickItem && graph.titleLineNumber ? 'pointer' : 'default')
|
|
317
317
|
.text(graph.title);
|
|
318
|
+
|
|
319
|
+
if (graph.titleLineNumber) {
|
|
320
|
+
titleEl.attr('data-line-number', graph.titleLineNumber);
|
|
321
|
+
if (onClickItem) {
|
|
322
|
+
titleEl
|
|
323
|
+
.on('click', () => onClickItem(graph.titleLineNumber!))
|
|
324
|
+
.on('mouseenter', function () { d3Selection.select(this).attr('opacity', 0.7); })
|
|
325
|
+
.on('mouseleave', function () { d3Selection.select(this).attr('opacity', 1); });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
318
328
|
}
|
|
319
329
|
|
|
320
330
|
// Content group (offset by title)
|
|
@@ -425,7 +435,8 @@ export function renderFlowchart(
|
|
|
425
435
|
.append('g')
|
|
426
436
|
.attr('transform', `translate(${node.x}, ${node.y})`)
|
|
427
437
|
.attr('class', 'fc-node')
|
|
428
|
-
.attr('data-line-number', String(node.lineNumber))
|
|
438
|
+
.attr('data-line-number', String(node.lineNumber))
|
|
439
|
+
.attr('data-node-id', node.id);
|
|
429
440
|
|
|
430
441
|
if (onClickItem) {
|
|
431
442
|
nodeG.style('cursor', 'pointer').on('click', () => {
|
package/src/graph/types.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Unified API
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
export { render } from './render';
|
|
6
|
+
|
|
1
7
|
// ============================================================
|
|
2
8
|
// Router
|
|
3
9
|
// ============================================================
|
|
@@ -109,6 +115,7 @@ export {
|
|
|
109
115
|
applyPositionOverrides,
|
|
110
116
|
applyGroupOrdering,
|
|
111
117
|
groupMessagesBySection,
|
|
118
|
+
buildNoteMessageMap,
|
|
112
119
|
} from './sequence/renderer';
|
|
113
120
|
export type {
|
|
114
121
|
RenderStep,
|
package/src/render.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { renderD3ForExport } from './d3';
|
|
2
|
+
import { renderEChartsForExport } from './echarts';
|
|
3
|
+
import { parseDgmoChartType, getDgmoFramework } from './dgmo-router';
|
|
4
|
+
import { getPalette } from './palettes/registry';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ensures DOM globals are available for D3 renderers.
|
|
8
|
+
* No-ops in browser environments where `document` already exists.
|
|
9
|
+
* Dynamically imports jsdom only in Node.js to avoid bundling it for browsers.
|
|
10
|
+
*/
|
|
11
|
+
async function ensureDom(): Promise<void> {
|
|
12
|
+
if (typeof document !== 'undefined') return;
|
|
13
|
+
|
|
14
|
+
const { JSDOM } = await import('jsdom');
|
|
15
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
|
|
16
|
+
const win = dom.window;
|
|
17
|
+
|
|
18
|
+
Object.defineProperty(globalThis, 'document', { value: win.document, configurable: true });
|
|
19
|
+
Object.defineProperty(globalThis, 'window', { value: win, configurable: true });
|
|
20
|
+
Object.defineProperty(globalThis, 'navigator', { value: win.navigator, configurable: true });
|
|
21
|
+
Object.defineProperty(globalThis, 'HTMLElement', { value: win.HTMLElement, configurable: true });
|
|
22
|
+
Object.defineProperty(globalThis, 'SVGElement', { value: win.SVGElement, configurable: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Render DGMO source to an SVG string.
|
|
27
|
+
*
|
|
28
|
+
* Automatically detects the chart type, selects the appropriate renderer,
|
|
29
|
+
* and returns a complete SVG document string.
|
|
30
|
+
*
|
|
31
|
+
* @param content - DGMO source text
|
|
32
|
+
* @param options - Optional theme and palette settings
|
|
33
|
+
* @returns SVG string, or empty string on error
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { render } from '@diagrammo/dgmo';
|
|
38
|
+
*
|
|
39
|
+
* const svg = await render(`chart: pie
|
|
40
|
+
* title: Languages
|
|
41
|
+
* TypeScript: 45
|
|
42
|
+
* Python: 30
|
|
43
|
+
* Rust: 25`);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export async function render(
|
|
47
|
+
content: string,
|
|
48
|
+
options?: {
|
|
49
|
+
theme?: 'light' | 'dark' | 'transparent';
|
|
50
|
+
palette?: string;
|
|
51
|
+
},
|
|
52
|
+
): Promise<string> {
|
|
53
|
+
const theme = options?.theme ?? 'light';
|
|
54
|
+
const paletteName = options?.palette ?? 'nord';
|
|
55
|
+
|
|
56
|
+
const paletteColors = getPalette(paletteName)[theme === 'dark' ? 'dark' : 'light'];
|
|
57
|
+
|
|
58
|
+
const chartType = parseDgmoChartType(content);
|
|
59
|
+
const framework = chartType ? getDgmoFramework(chartType) : null;
|
|
60
|
+
|
|
61
|
+
if (framework === 'echart') {
|
|
62
|
+
return renderEChartsForExport(content, theme, paletteColors);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// D3 and unknown/null frameworks both go through D3 renderer
|
|
66
|
+
await ensureDom();
|
|
67
|
+
return renderD3ForExport(content, theme, paletteColors);
|
|
68
|
+
}
|
package/src/sequence/parser.ts
CHANGED
|
@@ -133,6 +133,7 @@ export interface SequenceGroup {
|
|
|
133
133
|
*/
|
|
134
134
|
export interface ParsedSequenceDgmo {
|
|
135
135
|
title: string | null;
|
|
136
|
+
titleLineNumber: number | null;
|
|
136
137
|
participants: SequenceParticipant[];
|
|
137
138
|
messages: SequenceMessage[];
|
|
138
139
|
elements: SequenceElement[];
|
|
@@ -227,6 +228,7 @@ function measureIndent(line: string): number {
|
|
|
227
228
|
export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
228
229
|
const result: ParsedSequenceDgmo = {
|
|
229
230
|
title: null,
|
|
231
|
+
titleLineNumber: null,
|
|
230
232
|
participants: [],
|
|
231
233
|
messages: [],
|
|
232
234
|
elements: [],
|
|
@@ -367,6 +369,7 @@ export function parseSequenceDgmo(content: string): ParsedSequenceDgmo {
|
|
|
367
369
|
|
|
368
370
|
if (key === 'title') {
|
|
369
371
|
result.title = value;
|
|
372
|
+
result.titleLineNumber = lineNumber;
|
|
370
373
|
continue;
|
|
371
374
|
}
|
|
372
375
|
|