@diagrammo/dgmo 0.3.2 → 0.4.1

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.
@@ -99,8 +99,8 @@ export function parseDgmoChartType(content: string): string | null {
99
99
  return null;
100
100
  }
101
101
 
102
- // Standard chart types parsed by parseChart (then rendered via ECharts)
103
- const STANDARD_CHART_TYPES = new Set([
102
+ /** Standard chart types parsed by parseChart (then rendered via ECharts). */
103
+ export const STANDARD_CHART_TYPES = new Set([
104
104
  'bar', 'line', 'multi-line', 'area', 'pie', 'doughnut',
105
105
  'radar', 'polar-area', 'bar-stacked',
106
106
  ]);
@@ -110,6 +110,18 @@ const ECHART_TYPES = new Set([
110
110
  'scatter', 'sankey', 'chord', 'function', 'heatmap', 'funnel',
111
111
  ]);
112
112
 
113
+ /** Map chart type strings to their parse function (content → { diagnostics }). */
114
+ const PARSE_DISPATCH = new Map<string, (content: string) => { diagnostics: DgmoError[] }>([
115
+ ['sequence', (c) => parseSequenceDgmo(c)],
116
+ ['flowchart', (c) => parseFlowchart(c)],
117
+ ['class', (c) => parseClassDiagram(c)],
118
+ ['er', (c) => parseERDiagram(c)],
119
+ ['org', (c) => parseOrg(c)],
120
+ ['kanban', (c) => parseKanban(c)],
121
+ ['c4', (c) => parseC4(c)],
122
+ ['initiative-status', (c) => parseInitiativeStatus(c)],
123
+ ]);
124
+
113
125
  /**
114
126
  * Parse DGMO content and return diagnostics without rendering.
115
127
  * Useful for the CLI and editor to surface all errors before attempting render.
@@ -119,52 +131,19 @@ export function parseDgmo(content: string): { diagnostics: DgmoError[] } {
119
131
 
120
132
  if (!chartType) {
121
133
  // No chart type detected — try D3 parser as fallback (it handles missing chart: line)
122
- const parsed = parseD3(content);
123
- return { diagnostics: parsed.diagnostics };
134
+ return { diagnostics: parseD3(content).diagnostics };
124
135
  }
125
136
 
126
- if (chartType === 'sequence') {
127
- const parsed = parseSequenceDgmo(content);
128
- return { diagnostics: parsed.diagnostics };
129
- }
130
- if (chartType === 'flowchart') {
131
- const parsed = parseFlowchart(content);
132
- return { diagnostics: parsed.diagnostics };
133
- }
134
- if (chartType === 'class') {
135
- const parsed = parseClassDiagram(content);
136
- return { diagnostics: parsed.diagnostics };
137
- }
138
- if (chartType === 'er') {
139
- const parsed = parseERDiagram(content);
140
- return { diagnostics: parsed.diagnostics };
141
- }
142
- if (chartType === 'org') {
143
- const parsed = parseOrg(content);
144
- return { diagnostics: parsed.diagnostics };
145
- }
146
- if (chartType === 'kanban') {
147
- const parsed = parseKanban(content);
148
- return { diagnostics: parsed.diagnostics };
149
- }
150
- if (chartType === 'c4') {
151
- const parsed = parseC4(content);
152
- return { diagnostics: parsed.diagnostics };
153
- }
154
- if (chartType === 'initiative-status') {
155
- const parsed = parseInitiativeStatus(content);
156
- return { diagnostics: parsed.diagnostics };
157
- }
137
+ const directParser = PARSE_DISPATCH.get(chartType);
138
+ if (directParser) return { diagnostics: directParser(content).diagnostics };
139
+
158
140
  if (STANDARD_CHART_TYPES.has(chartType)) {
159
- const parsed = parseChart(content);
160
- return { diagnostics: parsed.diagnostics };
141
+ return { diagnostics: parseChart(content).diagnostics };
161
142
  }
162
143
  if (ECHART_TYPES.has(chartType)) {
163
- const parsed = parseEChart(content);
164
- return { diagnostics: parsed.diagnostics };
144
+ return { diagnostics: parseEChart(content).diagnostics };
165
145
  }
166
146
 
167
147
  // D3 types (slope, wordcloud, arc, timeline, venn, quadrant)
168
- const parsed = parseD3(content);
169
- return { diagnostics: parsed.diagnostics };
148
+ return { diagnostics: parseD3(content).diagnostics };
170
149
  }
package/src/echarts.ts CHANGED
@@ -82,13 +82,19 @@ export interface ParsedEChart {
82
82
  // Nord Colors for Charts
83
83
  // ============================================================
84
84
 
85
- import { resolveColor } from './colors';
86
85
  import type { PaletteColors } from './palettes';
87
86
  import { getSeriesColors, getSegmentColors } from './palettes';
88
87
  import { parseChart } from './chart';
89
88
  import type { ParsedChart } from './chart';
90
89
  import { makeDgmoError, formatDgmoError, suggest } from './diagnostics';
91
- import { collectIndentedValues } from './utils/parsing';
90
+ import { collectIndentedValues, extractColor, parseSeriesNames } from './utils/parsing';
91
+
92
+ // ============================================================
93
+ // Shared Constants
94
+ // ============================================================
95
+
96
+ const EMPHASIS_SELF = { focus: 'self' as const, blurScope: 'global' as const };
97
+ const CHART_BASE: Pick<EChartsOption, 'backgroundColor' | 'animation'> = { backgroundColor: 'transparent', animation: false };
92
98
 
93
99
  // ============================================================
94
100
  // Parser
@@ -133,13 +139,10 @@ export function parseEChart(
133
139
  // Check for markdown-style category header: ## Category Name or ## Category Name(color)
134
140
  const mdCategoryMatch = trimmed.match(/^#{2,}\s+(.+)$/);
135
141
  if (mdCategoryMatch) {
136
- let catName = mdCategoryMatch[1].trim();
137
- const catColorMatch = catName.match(/\(([^)]+)\)\s*$/);
138
- if (catColorMatch) {
139
- const resolved = resolveColor(catColorMatch[1].trim(), palette);
142
+ const { label: catName, color: catColor } = extractColor(mdCategoryMatch[1].trim(), palette);
143
+ if (catColor) {
140
144
  if (!result.categoryColors) result.categoryColors = {};
141
- catName = catName.substring(0, catColorMatch.index!).trim();
142
- result.categoryColors[catName] = resolved;
145
+ result.categoryColors[catName] = catColor;
143
146
  }
144
147
  currentCategory = catName;
145
148
  continue;
@@ -194,32 +197,13 @@ export function parseEChart(
194
197
  }
195
198
 
196
199
  if (key === 'series') {
197
- let rawNames: string[];
198
- if (value) {
199
- result.series = value;
200
- rawNames = value.split(',').map((s) => s.trim()).filter(Boolean);
201
- } else {
202
- const collected = collectIndentedValues(lines, i);
203
- i = collected.newIndex;
204
- rawNames = collected.values;
205
- result.series = rawNames.join(', ');
206
- }
207
- const names: string[] = [];
208
- const nameColors: (string | undefined)[] = [];
209
- for (const raw of rawNames) {
210
- const colorMatch = raw.match(/\(([^)]+)\)\s*$/);
211
- if (colorMatch) {
212
- nameColors.push(resolveColor(colorMatch[1].trim(), palette));
213
- names.push(raw.substring(0, colorMatch.index!).trim());
214
- } else {
215
- nameColors.push(undefined);
216
- names.push(raw);
217
- }
218
- }
219
- if (names.length === 1) {
220
- result.series = names[0];
200
+ const parsed = parseSeriesNames(value, lines, i, palette);
201
+ i = parsed.newIndex;
202
+ result.series = parsed.series;
203
+ if (parsed.names.length > 1) {
204
+ result.seriesNames = parsed.names;
221
205
  }
222
- if (nameColors.some(Boolean)) result.seriesNameColors = nameColors;
206
+ if (parsed.nameColors.some(Boolean)) result.seriesNameColors = parsed.nameColors;
223
207
  continue;
224
208
  }
225
209
 
@@ -296,13 +280,7 @@ export function parseEChart(
296
280
 
297
281
  // For function charts, treat non-numeric values as function expressions
298
282
  if (result.type === 'function') {
299
- let fnName = trimmed.substring(0, colonIndex).trim();
300
- let fnColor: string | undefined;
301
- const colorMatch = fnName.match(/\(([^)]+)\)\s*$/);
302
- if (colorMatch) {
303
- fnColor = resolveColor(colorMatch[1].trim(), palette);
304
- fnName = fnName.substring(0, colorMatch.index!).trim();
305
- }
283
+ const { label: fnName, color: fnColor } = extractColor(trimmed.substring(0, colonIndex).trim(), palette);
306
284
  if (!result.functions) result.functions = [];
307
285
  result.functions.push({
308
286
  name: fnName,
@@ -319,13 +297,7 @@ export function parseEChart(
319
297
  /^(-?[\d.]+)\s*,\s*(-?[\d.]+)(?:\s*,\s*(-?[\d.]+))?$/
320
298
  );
321
299
  if (scatterMatch) {
322
- let scatterName = trimmed.substring(0, colonIndex).trim();
323
- let scatterColor: string | undefined;
324
- const colorMatch = scatterName.match(/\(([^)]+)\)\s*$/);
325
- if (colorMatch) {
326
- scatterColor = resolveColor(colorMatch[1].trim(), palette);
327
- scatterName = scatterName.substring(0, colorMatch.index!).trim();
328
- }
300
+ const { label: scatterName, color: scatterColor } = extractColor(trimmed.substring(0, colonIndex).trim(), palette);
329
301
  if (!result.scatterPoints) result.scatterPoints = [];
330
302
  result.scatterPoints.push({
331
303
  name: scatterName,
@@ -354,14 +326,7 @@ export function parseEChart(
354
326
  // Otherwise treat as data point (label: value)
355
327
  const numValue = parseFloat(value);
356
328
  if (!isNaN(numValue)) {
357
- // Use the original case for the label (before lowercasing)
358
- let rawLabel = trimmed.substring(0, colonIndex).trim();
359
- let pointColor: string | undefined;
360
- const colorMatch = rawLabel.match(/\(([^)]+)\)\s*$/);
361
- if (colorMatch) {
362
- pointColor = resolveColor(colorMatch[1].trim(), palette);
363
- rawLabel = rawLabel.substring(0, colorMatch.index!).trim();
364
- }
329
+ const { label: rawLabel, color: pointColor } = extractColor(trimmed.substring(0, colonIndex).trim(), palette);
365
330
  result.data.push({
366
331
  label: rawLabel,
367
332
  value: numValue,
@@ -416,6 +381,20 @@ export function parseEChart(
416
381
  // ECharts Option Builder
417
382
  // ============================================================
418
383
 
384
+ /**
385
+ * Computes the shared set of theme-derived variables used by all chart option builders.
386
+ */
387
+ function buildChartCommons(parsed: { title?: string; error?: string | null }, palette: PaletteColors, isDark: boolean) {
388
+ const textColor = palette.text;
389
+ const axisLineColor = palette.border;
390
+ const splitLineColor = palette.border;
391
+ const gridOpacity = isDark ? 0.7 : 0.55;
392
+ const colors = getSeriesColors(palette);
393
+ const titleConfig = parsed.title ? { text: parsed.title, left: 'center' as const, top: 8, textStyle: { color: textColor, fontSize: 20, fontWeight: 'bold' as const, fontFamily: FONT_FAMILY } } : undefined;
394
+ const tooltipTheme = { backgroundColor: palette.surface, borderColor: palette.border, textStyle: { color: palette.text } };
395
+ return { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme };
396
+ }
397
+
419
398
  /**
420
399
  * Converts parsed echart data to ECharts option object.
421
400
  */
@@ -424,37 +403,12 @@ export function buildEChartsOption(
424
403
  palette: PaletteColors,
425
404
  isDark: boolean
426
405
  ): EChartsOption {
427
- const textColor = palette.text;
428
- const axisLineColor = palette.border;
429
- const gridOpacity = isDark ? 0.7 : 0.55;
430
- const colors = getSeriesColors(palette);
431
-
432
406
  if (parsed.error) {
433
407
  // Return empty option, error will be shown separately
434
408
  return {};
435
409
  }
436
410
 
437
- // Common title configuration
438
- const titleConfig = parsed.title
439
- ? {
440
- text: parsed.title,
441
- left: 'center' as const,
442
- top: 8,
443
- textStyle: {
444
- color: textColor,
445
- fontSize: 20,
446
- fontWeight: 'bold' as const,
447
- fontFamily: FONT_FAMILY,
448
- },
449
- }
450
- : undefined;
451
-
452
- // Shared tooltip theme so tooltips match light/dark mode
453
- const tooltipTheme = {
454
- backgroundColor: palette.surface,
455
- borderColor: palette.border,
456
- textStyle: { color: palette.text },
457
- };
411
+ const { textColor, axisLineColor, gridOpacity, colors, titleConfig, tooltipTheme } = buildChartCommons(parsed, palette, isDark);
458
412
 
459
413
  // Sankey chart has different structure
460
414
  if (parsed.type === 'sankey') {
@@ -555,8 +509,7 @@ function buildSankeyOption(
555
509
  }));
556
510
 
557
511
  return {
558
- backgroundColor: 'transparent',
559
- animation: false,
512
+ ...CHART_BASE,
560
513
  title: titleConfig,
561
514
  tooltip: {
562
515
  show: false,
@@ -633,8 +586,7 @@ function buildChordOption(
633
586
  }));
634
587
 
635
588
  return {
636
- backgroundColor: 'transparent',
637
- animation: false,
589
+ ...CHART_BASE,
638
590
  title: titleConfig,
639
591
  tooltip: {
640
592
  trigger: 'item',
@@ -776,16 +728,12 @@ function buildFunctionOption(
776
728
  itemStyle: {
777
729
  color: fnColor,
778
730
  },
779
- emphasis: {
780
- focus: 'self' as const,
781
- blurScope: 'global' as const,
782
- },
731
+ emphasis: EMPHASIS_SELF,
783
732
  };
784
733
  });
785
734
 
786
735
  return {
787
- backgroundColor: 'transparent',
788
- animation: false,
736
+ ...CHART_BASE,
789
737
  title: titleConfig,
790
738
  tooltip: {
791
739
  trigger: 'axis',
@@ -971,8 +919,7 @@ function buildScatterOption(
971
919
  const yPad = (yMax - yMin) * 0.1 || 1;
972
920
 
973
921
  return {
974
- backgroundColor: 'transparent',
975
- animation: false,
922
+ ...CHART_BASE,
976
923
  title: titleConfig,
977
924
  tooltip,
978
925
  ...(legendData && {
@@ -1072,8 +1019,7 @@ function buildHeatmapOption(
1072
1019
  });
1073
1020
 
1074
1021
  return {
1075
- backgroundColor: 'transparent',
1076
- animation: false,
1022
+ ...CHART_BASE,
1077
1023
  title: titleConfig,
1078
1024
  tooltip: {
1079
1025
  trigger: 'item',
@@ -1150,8 +1096,7 @@ function buildHeatmapOption(
1150
1096
  fontWeight: 'bold' as const,
1151
1097
  },
1152
1098
  emphasis: {
1153
- focus: 'self' as const,
1154
- blurScope: 'global' as const,
1099
+ ...EMPHASIS_SELF,
1155
1100
  itemStyle: {
1156
1101
  shadowBlur: 10,
1157
1102
  shadowColor: 'rgba(0, 0, 0, 0.5)',
@@ -1206,8 +1151,7 @@ function buildFunnelOption(
1206
1151
  };
1207
1152
 
1208
1153
  return {
1209
- backgroundColor: 'transparent',
1210
- animation: false,
1154
+ ...CHART_BASE,
1211
1155
  title: titleConfig,
1212
1156
  tooltip: {
1213
1157
  trigger: 'item',
@@ -1245,8 +1189,7 @@ function buildFunnelOption(
1245
1189
  lineStyle: { color: textColor, opacity: 0.3 },
1246
1190
  },
1247
1191
  emphasis: {
1248
- focus: 'self' as const,
1249
- blurScope: 'global' as const,
1192
+ ...EMPHASIS_SELF,
1250
1193
  label: {
1251
1194
  fontSize: 15,
1252
1195
  },
@@ -1372,31 +1315,7 @@ export function buildEChartsOptionFromChart(
1372
1315
  ): EChartsOption {
1373
1316
  if (parsed.error) return {};
1374
1317
 
1375
- const textColor = palette.text;
1376
- const axisLineColor = palette.border;
1377
- const splitLineColor = palette.border;
1378
- const gridOpacity = isDark ? 0.7 : 0.55;
1379
- const colors = getSeriesColors(palette);
1380
-
1381
- const titleConfig = parsed.title
1382
- ? {
1383
- text: parsed.title,
1384
- left: 'center' as const,
1385
- top: 8,
1386
- textStyle: {
1387
- color: textColor,
1388
- fontSize: 20,
1389
- fontWeight: 'bold' as const,
1390
- fontFamily: FONT_FAMILY,
1391
- },
1392
- }
1393
- : undefined;
1394
-
1395
- const tooltipTheme = {
1396
- backgroundColor: palette.surface,
1397
- borderColor: palette.border,
1398
- textStyle: { color: palette.text },
1399
- };
1318
+ const { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme } = buildChartCommons(parsed, palette, isDark);
1400
1319
 
1401
1320
  switch (parsed.type) {
1402
1321
  case 'bar':
@@ -1420,6 +1339,19 @@ export function buildEChartsOptionFromChart(
1420
1339
  }
1421
1340
  }
1422
1341
 
1342
+ /**
1343
+ * Builds a standard chart grid object with consistent spacing rules.
1344
+ */
1345
+ function makeChartGrid(options: { xLabel?: string; yLabel?: string; hasTitle: boolean; hasLegend?: boolean }): Record<string, unknown> {
1346
+ return {
1347
+ left: options.yLabel ? '12%' : '3%',
1348
+ right: '4%',
1349
+ bottom: options.hasLegend ? '15%' : options.xLabel ? '10%' : '3%',
1350
+ top: options.hasTitle ? '15%' : '5%',
1351
+ containLabel: true,
1352
+ };
1353
+ }
1354
+
1423
1355
  // ── Bar ──────────────────────────────────────────────────────
1424
1356
 
1425
1357
  function buildBarOption(
@@ -1452,31 +1384,21 @@ function buildBarOption(
1452
1384
  // xAxis is always the bottom axis, yAxis is always the left axis in ECharts
1453
1385
 
1454
1386
  return {
1455
- backgroundColor: 'transparent',
1456
- animation: false,
1387
+ ...CHART_BASE,
1457
1388
  title: titleConfig,
1458
1389
  tooltip: {
1459
1390
  trigger: 'axis',
1460
1391
  ...tooltipTheme,
1461
1392
  axisPointer: { type: 'shadow' },
1462
1393
  },
1463
- grid: {
1464
- left: yLabel ? '12%' : '3%',
1465
- right: '4%',
1466
- bottom: xLabel ? '10%' : '3%',
1467
- top: parsed.title ? '15%' : '5%',
1468
- containLabel: true,
1469
- },
1394
+ grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title }),
1470
1395
  xAxis: isHorizontal ? valueAxis : categoryAxis,
1471
1396
  yAxis: isHorizontal ? categoryAxis : valueAxis,
1472
1397
  series: [
1473
1398
  {
1474
1399
  type: 'bar',
1475
1400
  data,
1476
- emphasis: {
1477
- focus: 'self' as const,
1478
- blurScope: 'global' as const,
1479
- },
1401
+ emphasis: EMPHASIS_SELF,
1480
1402
  },
1481
1403
  ],
1482
1404
  };
@@ -1501,21 +1423,14 @@ function buildLineOption(
1501
1423
  const values = parsed.data.map((d) => d.value);
1502
1424
 
1503
1425
  return {
1504
- backgroundColor: 'transparent',
1505
- animation: false,
1426
+ ...CHART_BASE,
1506
1427
  title: titleConfig,
1507
1428
  tooltip: {
1508
1429
  trigger: 'axis',
1509
1430
  ...tooltipTheme,
1510
1431
  axisPointer: { type: 'line' },
1511
1432
  },
1512
- grid: {
1513
- left: yLabel ? '12%' : '3%',
1514
- right: '4%',
1515
- bottom: xLabel ? '10%' : '3%',
1516
- top: parsed.title ? '15%' : '5%',
1517
- containLabel: true,
1518
- },
1433
+ grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title }),
1519
1434
  xAxis: makeGridAxis('category', textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, undefined, chartWidth),
1520
1435
  yAxis: makeGridAxis('value', textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
1521
1436
  series: [
@@ -1526,10 +1441,7 @@ function buildLineOption(
1526
1441
  symbolSize: 8,
1527
1442
  lineStyle: { color: lineColor, width: 3 },
1528
1443
  itemStyle: { color: lineColor },
1529
- emphasis: {
1530
- focus: 'self' as const,
1531
- blurScope: 'global' as const,
1532
- },
1444
+ emphasis: EMPHASIS_SELF,
1533
1445
  },
1534
1446
  ],
1535
1447
  };
@@ -1565,16 +1477,12 @@ function buildMultiLineOption(
1565
1477
  symbolSize: 8,
1566
1478
  lineStyle: { color, width: 3 },
1567
1479
  itemStyle: { color },
1568
- emphasis: {
1569
- focus: 'self' as const,
1570
- blurScope: 'global' as const,
1571
- },
1480
+ emphasis: EMPHASIS_SELF,
1572
1481
  };
1573
1482
  });
1574
1483
 
1575
1484
  return {
1576
- backgroundColor: 'transparent',
1577
- animation: false,
1485
+ ...CHART_BASE,
1578
1486
  title: titleConfig,
1579
1487
  tooltip: {
1580
1488
  trigger: 'axis',
@@ -1586,13 +1494,7 @@ function buildMultiLineOption(
1586
1494
  bottom: 10,
1587
1495
  textStyle: { color: textColor },
1588
1496
  },
1589
- grid: {
1590
- left: yLabel ? '12%' : '3%',
1591
- right: '4%',
1592
- bottom: '15%',
1593
- top: parsed.title ? '15%' : '5%',
1594
- containLabel: true,
1595
- },
1497
+ grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title, hasLegend: true }),
1596
1498
  xAxis: makeGridAxis('category', textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, undefined, chartWidth),
1597
1499
  yAxis: makeGridAxis('value', textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
1598
1500
  series,
@@ -1618,21 +1520,14 @@ function buildAreaOption(
1618
1520
  const values = parsed.data.map((d) => d.value);
1619
1521
 
1620
1522
  return {
1621
- backgroundColor: 'transparent',
1622
- animation: false,
1523
+ ...CHART_BASE,
1623
1524
  title: titleConfig,
1624
1525
  tooltip: {
1625
1526
  trigger: 'axis',
1626
1527
  ...tooltipTheme,
1627
1528
  axisPointer: { type: 'line' },
1628
1529
  },
1629
- grid: {
1630
- left: yLabel ? '12%' : '3%',
1631
- right: '4%',
1632
- bottom: xLabel ? '10%' : '3%',
1633
- top: parsed.title ? '15%' : '5%',
1634
- containLabel: true,
1635
- },
1530
+ grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title }),
1636
1531
  xAxis: makeGridAxis('category', textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, undefined, chartWidth),
1637
1532
  yAxis: makeGridAxis('value', textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
1638
1533
  series: [
@@ -1644,10 +1539,7 @@ function buildAreaOption(
1644
1539
  lineStyle: { color: lineColor, width: 3 },
1645
1540
  itemStyle: { color: lineColor },
1646
1541
  areaStyle: { opacity: 0.25 },
1647
- emphasis: {
1648
- focus: 'self' as const,
1649
- blurScope: 'global' as const,
1650
- },
1542
+ emphasis: EMPHASIS_SELF,
1651
1543
  },
1652
1544
  ],
1653
1545
  };
@@ -1681,8 +1573,7 @@ function buildPieOption(
1681
1573
  }));
1682
1574
 
1683
1575
  return {
1684
- backgroundColor: 'transparent',
1685
- animation: false,
1576
+ ...CHART_BASE,
1686
1577
  title: titleConfig,
1687
1578
  tooltip: {
1688
1579
  trigger: 'item',
@@ -1700,10 +1591,7 @@ function buildPieOption(
1700
1591
  fontFamily: FONT_FAMILY,
1701
1592
  },
1702
1593
  labelLine: { show: true },
1703
- emphasis: {
1704
- focus: 'self' as const,
1705
- blurScope: 'global' as const,
1706
- },
1594
+ emphasis: EMPHASIS_SELF,
1707
1595
  },
1708
1596
  ],
1709
1597
  };
@@ -1730,8 +1618,7 @@ function buildRadarOption(
1730
1618
  }));
1731
1619
 
1732
1620
  return {
1733
- backgroundColor: 'transparent',
1734
- animation: false,
1621
+ ...CHART_BASE,
1735
1622
  title: titleConfig,
1736
1623
  tooltip: {
1737
1624
  trigger: 'item',
@@ -1773,10 +1660,7 @@ function buildRadarOption(
1773
1660
  },
1774
1661
  },
1775
1662
  ],
1776
- emphasis: {
1777
- focus: 'self' as const,
1778
- blurScope: 'global' as const,
1779
- },
1663
+ emphasis: EMPHASIS_SELF,
1780
1664
  },
1781
1665
  ],
1782
1666
  };
@@ -1798,8 +1682,7 @@ function buildPolarAreaOption(
1798
1682
  }));
1799
1683
 
1800
1684
  return {
1801
- backgroundColor: 'transparent',
1802
- animation: false,
1685
+ ...CHART_BASE,
1803
1686
  title: titleConfig,
1804
1687
  tooltip: {
1805
1688
  trigger: 'item',
@@ -1818,10 +1701,7 @@ function buildPolarAreaOption(
1818
1701
  fontFamily: FONT_FAMILY,
1819
1702
  },
1820
1703
  labelLine: { show: true },
1821
- emphasis: {
1822
- focus: 'self' as const,
1823
- blurScope: 'global' as const,
1824
- },
1704
+ emphasis: EMPHASIS_SELF,
1825
1705
  },
1826
1706
  ],
1827
1707
  };
@@ -1865,10 +1745,7 @@ function buildBarStackedOption(
1865
1745
  fontWeight: 'bold' as const,
1866
1746
  fontFamily: FONT_FAMILY,
1867
1747
  },
1868
- emphasis: {
1869
- focus: 'self' as const,
1870
- blurScope: 'global' as const,
1871
- },
1748
+ emphasis: EMPHASIS_SELF,
1872
1749
  };
1873
1750
  });
1874
1751
 
@@ -1882,8 +1759,7 @@ function buildBarStackedOption(
1882
1759
  const valueAxis = makeGridAxis('value', textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel, undefined, hValueGap);
1883
1760
 
1884
1761
  return {
1885
- backgroundColor: 'transparent',
1886
- animation: false,
1762
+ ...CHART_BASE,
1887
1763
  title: titleConfig,
1888
1764
  tooltip: {
1889
1765
  trigger: 'axis',
@@ -1895,13 +1771,7 @@ function buildBarStackedOption(
1895
1771
  bottom: 10,
1896
1772
  textStyle: { color: textColor },
1897
1773
  },
1898
- grid: {
1899
- left: yLabel ? '12%' : '3%',
1900
- right: '4%',
1901
- bottom: '15%',
1902
- top: parsed.title ? '15%' : '5%',
1903
- containLabel: true,
1904
- },
1774
+ grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title, hasLegend: true }),
1905
1775
  xAxis: isHorizontal ? valueAxis : categoryAxis,
1906
1776
  yAxis: isHorizontal ? categoryAxis : valueAxis,
1907
1777
  series,
@@ -1915,17 +1785,7 @@ function buildBarStackedOption(
1915
1785
  const ECHART_EXPORT_WIDTH = 1200;
1916
1786
  const ECHART_EXPORT_HEIGHT = 800;
1917
1787
 
1918
- const STANDARD_CHART_TYPES = new Set([
1919
- 'bar',
1920
- 'line',
1921
- 'multi-line',
1922
- 'area',
1923
- 'pie',
1924
- 'doughnut',
1925
- 'radar',
1926
- 'polar-area',
1927
- 'bar-stacked',
1928
- ]);
1788
+ import { STANDARD_CHART_TYPES } from './dgmo-router';
1929
1789
 
1930
1790
  /**
1931
1791
  * Renders an ECharts diagram to SVG using server-side rendering.
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ export {
20
20
  getDgmoFramework,
21
21
  parseDgmo,
22
22
  DGMO_CHART_TYPE_MAP,
23
+ STANDARD_CHART_TYPES,
23
24
  } from './dgmo-router';
24
25
  export type { DgmoFramework } from './dgmo-router';
25
26