@diagrammo/dgmo 0.1.7 → 0.2.0

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 CHANGED
@@ -5066,6 +5066,1491 @@ async function renderD3ForExport(content, theme, palette) {
5066
5066
  }
5067
5067
  }
5068
5068
 
5069
+ // src/echarts.ts
5070
+ var echarts = __toESM(require("echarts"), 1);
5071
+ init_fonts();
5072
+ init_colors();
5073
+ init_palettes();
5074
+
5075
+ // src/chart.ts
5076
+ init_colors();
5077
+ var VALID_TYPES = /* @__PURE__ */ new Set([
5078
+ "bar",
5079
+ "line",
5080
+ "pie",
5081
+ "doughnut",
5082
+ "area",
5083
+ "polar-area",
5084
+ "radar",
5085
+ "bar-stacked"
5086
+ ]);
5087
+ var TYPE_ALIASES = {
5088
+ "multi-line": "line"
5089
+ };
5090
+ function parseChart(content, palette) {
5091
+ const lines = content.split("\n");
5092
+ const result = {
5093
+ type: "bar",
5094
+ data: []
5095
+ };
5096
+ for (let i = 0; i < lines.length; i++) {
5097
+ const trimmed = lines[i].trim();
5098
+ const lineNumber = i + 1;
5099
+ if (!trimmed) continue;
5100
+ if (/^#{2,}\s+/.test(trimmed)) continue;
5101
+ if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
5102
+ const colonIndex = trimmed.indexOf(":");
5103
+ if (colonIndex === -1) continue;
5104
+ const key = trimmed.substring(0, colonIndex).trim().toLowerCase();
5105
+ const value = trimmed.substring(colonIndex + 1).trim();
5106
+ if (key === "chart") {
5107
+ const raw = value.toLowerCase();
5108
+ const chartType = TYPE_ALIASES[raw] ?? raw;
5109
+ if (VALID_TYPES.has(chartType)) {
5110
+ result.type = chartType;
5111
+ } else {
5112
+ result.error = `Unsupported chart type: ${value}. Supported types: ${[...VALID_TYPES].join(", ")}.`;
5113
+ return result;
5114
+ }
5115
+ continue;
5116
+ }
5117
+ if (key === "title") {
5118
+ result.title = value;
5119
+ continue;
5120
+ }
5121
+ if (key === "xlabel") {
5122
+ result.xlabel = value;
5123
+ continue;
5124
+ }
5125
+ if (key === "ylabel") {
5126
+ result.ylabel = value;
5127
+ continue;
5128
+ }
5129
+ if (key === "label") {
5130
+ result.label = value;
5131
+ continue;
5132
+ }
5133
+ if (key === "orientation") {
5134
+ const v = value.toLowerCase();
5135
+ if (v === "horizontal" || v === "vertical") {
5136
+ result.orientation = v;
5137
+ }
5138
+ continue;
5139
+ }
5140
+ if (key === "color") {
5141
+ result.color = resolveColor(value.trim(), palette);
5142
+ continue;
5143
+ }
5144
+ if (key === "series") {
5145
+ result.series = value;
5146
+ const rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
5147
+ const names = [];
5148
+ const nameColors = [];
5149
+ for (const raw of rawNames) {
5150
+ const colorMatch = raw.match(/\(([^)]+)\)\s*$/);
5151
+ if (colorMatch) {
5152
+ const resolved = resolveColor(colorMatch[1].trim(), palette);
5153
+ nameColors.push(resolved);
5154
+ names.push(raw.substring(0, colorMatch.index).trim());
5155
+ } else {
5156
+ nameColors.push(void 0);
5157
+ names.push(raw);
5158
+ }
5159
+ }
5160
+ if (names.length === 1) {
5161
+ result.series = names[0];
5162
+ }
5163
+ if (names.length > 1) {
5164
+ result.seriesNames = names;
5165
+ }
5166
+ if (nameColors.some(Boolean)) result.seriesNameColors = nameColors;
5167
+ continue;
5168
+ }
5169
+ const parts = value.split(",").map((s) => s.trim());
5170
+ const numValue = parseFloat(parts[0]);
5171
+ if (!isNaN(numValue)) {
5172
+ let rawLabel = trimmed.substring(0, colonIndex).trim();
5173
+ let pointColor;
5174
+ const colorMatch = rawLabel.match(/\(([^)]+)\)\s*$/);
5175
+ if (colorMatch) {
5176
+ const resolved = resolveColor(colorMatch[1].trim(), palette);
5177
+ pointColor = resolved;
5178
+ rawLabel = rawLabel.substring(0, colorMatch.index).trim();
5179
+ }
5180
+ const extra = parts.slice(1).map((s) => parseFloat(s)).filter((n) => !isNaN(n));
5181
+ result.data.push({
5182
+ label: rawLabel,
5183
+ value: numValue,
5184
+ ...extra.length > 0 && { extraValues: extra },
5185
+ ...pointColor && { color: pointColor },
5186
+ lineNumber
5187
+ });
5188
+ }
5189
+ }
5190
+ if (!result.error && result.data.length === 0) {
5191
+ result.error = "No data points found. Add data in format: Label: 123";
5192
+ }
5193
+ if (!result.error && result.type === "bar-stacked" && !result.seriesNames) {
5194
+ result.error = `Chart type "bar-stacked" requires multiple series names. Use: series: Name1, Name2, Name3`;
5195
+ }
5196
+ if (!result.error && result.seriesNames) {
5197
+ const expectedCount = result.seriesNames.length;
5198
+ for (const dp of result.data) {
5199
+ const actualCount = 1 + (dp.extraValues?.length ?? 0);
5200
+ if (actualCount !== expectedCount) {
5201
+ result.error = `Data point "${dp.label}" has ${actualCount} value(s), but ${expectedCount} series defined. Each row must have ${expectedCount} comma-separated values.`;
5202
+ break;
5203
+ }
5204
+ }
5205
+ }
5206
+ return result;
5207
+ }
5208
+
5209
+ // src/echarts.ts
5210
+ function parseEChart(content, palette) {
5211
+ const lines = content.split("\n");
5212
+ const result = {
5213
+ type: "scatter",
5214
+ data: []
5215
+ };
5216
+ let currentCategory = "Default";
5217
+ for (let i = 0; i < lines.length; i++) {
5218
+ const trimmed = lines[i].trim();
5219
+ const lineNumber = i + 1;
5220
+ if (!trimmed) continue;
5221
+ const mdCategoryMatch = trimmed.match(/^#{2,}\s+(.+)$/);
5222
+ if (mdCategoryMatch) {
5223
+ let catName = mdCategoryMatch[1].trim();
5224
+ const catColorMatch = catName.match(/\(([^)]+)\)\s*$/);
5225
+ if (catColorMatch) {
5226
+ const resolved = resolveColor(catColorMatch[1].trim(), palette);
5227
+ if (!result.categoryColors) result.categoryColors = {};
5228
+ catName = catName.substring(0, catColorMatch.index).trim();
5229
+ result.categoryColors[catName] = resolved;
5230
+ }
5231
+ currentCategory = catName;
5232
+ continue;
5233
+ }
5234
+ if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
5235
+ const categoryMatch = trimmed.match(/^\[(.+)\]$/);
5236
+ if (categoryMatch) {
5237
+ currentCategory = categoryMatch[1].trim();
5238
+ continue;
5239
+ }
5240
+ const colonIndex = trimmed.indexOf(":");
5241
+ if (colonIndex === -1) continue;
5242
+ const key = trimmed.substring(0, colonIndex).trim().toLowerCase();
5243
+ const value = trimmed.substring(colonIndex + 1).trim();
5244
+ if (key === "chart") {
5245
+ const chartType = value.toLowerCase();
5246
+ if (chartType === "sankey" || chartType === "chord" || chartType === "function" || chartType === "scatter" || chartType === "heatmap" || chartType === "funnel") {
5247
+ result.type = chartType;
5248
+ } else {
5249
+ result.error = `Unsupported chart type: ${value}. Supported types: scatter, sankey, chord, function, heatmap, funnel.`;
5250
+ return result;
5251
+ }
5252
+ continue;
5253
+ }
5254
+ if (key === "title") {
5255
+ result.title = value;
5256
+ continue;
5257
+ }
5258
+ if (key === "series") {
5259
+ result.series = value;
5260
+ const rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
5261
+ const names = [];
5262
+ const nameColors = [];
5263
+ for (const raw of rawNames) {
5264
+ const colorMatch = raw.match(/\(([^)]+)\)\s*$/);
5265
+ if (colorMatch) {
5266
+ nameColors.push(resolveColor(colorMatch[1].trim(), palette));
5267
+ names.push(raw.substring(0, colorMatch.index).trim());
5268
+ } else {
5269
+ nameColors.push(void 0);
5270
+ names.push(raw);
5271
+ }
5272
+ }
5273
+ if (names.length === 1) {
5274
+ result.series = names[0];
5275
+ }
5276
+ if (nameColors.some(Boolean)) result.seriesNameColors = nameColors;
5277
+ continue;
5278
+ }
5279
+ if (key === "xlabel") {
5280
+ result.xlabel = value;
5281
+ continue;
5282
+ }
5283
+ if (key === "ylabel") {
5284
+ result.ylabel = value;
5285
+ continue;
5286
+ }
5287
+ if (key === "sizelabel") {
5288
+ result.sizelabel = value;
5289
+ continue;
5290
+ }
5291
+ if (key === "labels") {
5292
+ result.showLabels = value.toLowerCase() === "on" || value.toLowerCase() === "true";
5293
+ continue;
5294
+ }
5295
+ if (key === "columns") {
5296
+ result.columns = value.split(",").map((s) => s.trim());
5297
+ continue;
5298
+ }
5299
+ if (key === "rows") {
5300
+ result.rows = value.split(",").map((s) => s.trim());
5301
+ continue;
5302
+ }
5303
+ if (key === "x") {
5304
+ const rangeMatch = value.match(/^(-?[\d.]+)\s+to\s+(-?[\d.]+)$/);
5305
+ if (rangeMatch) {
5306
+ result.xRange = {
5307
+ min: parseFloat(rangeMatch[1]),
5308
+ max: parseFloat(rangeMatch[2])
5309
+ };
5310
+ }
5311
+ continue;
5312
+ }
5313
+ const arrowMatch = trimmed.match(/^(.+?)\s*->\s*(.+?):\s*(\d+(?:\.\d+)?)$/);
5314
+ if (arrowMatch) {
5315
+ const [, source, target, val] = arrowMatch;
5316
+ if (!result.links) result.links = [];
5317
+ result.links.push({
5318
+ source: source.trim(),
5319
+ target: target.trim(),
5320
+ value: parseFloat(val),
5321
+ lineNumber
5322
+ });
5323
+ continue;
5324
+ }
5325
+ if (result.type === "function") {
5326
+ let fnName = trimmed.substring(0, colonIndex).trim();
5327
+ let fnColor;
5328
+ const colorMatch = fnName.match(/\(([^)]+)\)\s*$/);
5329
+ if (colorMatch) {
5330
+ fnColor = resolveColor(colorMatch[1].trim(), palette);
5331
+ fnName = fnName.substring(0, colorMatch.index).trim();
5332
+ }
5333
+ if (!result.functions) result.functions = [];
5334
+ result.functions.push({
5335
+ name: fnName,
5336
+ expression: value,
5337
+ ...fnColor && { color: fnColor },
5338
+ lineNumber
5339
+ });
5340
+ continue;
5341
+ }
5342
+ if (result.type === "scatter") {
5343
+ const scatterMatch = value.match(
5344
+ /^(-?[\d.]+)\s*,\s*(-?[\d.]+)(?:\s*,\s*(-?[\d.]+))?$/
5345
+ );
5346
+ if (scatterMatch) {
5347
+ let scatterName = trimmed.substring(0, colonIndex).trim();
5348
+ let scatterColor;
5349
+ const colorMatch = scatterName.match(/\(([^)]+)\)\s*$/);
5350
+ if (colorMatch) {
5351
+ scatterColor = resolveColor(colorMatch[1].trim(), palette);
5352
+ scatterName = scatterName.substring(0, colorMatch.index).trim();
5353
+ }
5354
+ if (!result.scatterPoints) result.scatterPoints = [];
5355
+ result.scatterPoints.push({
5356
+ name: scatterName,
5357
+ x: parseFloat(scatterMatch[1]),
5358
+ y: parseFloat(scatterMatch[2]),
5359
+ size: scatterMatch[3] ? parseFloat(scatterMatch[3]) : void 0,
5360
+ ...scatterColor && { color: scatterColor },
5361
+ ...currentCategory !== "Default" && { category: currentCategory },
5362
+ lineNumber
5363
+ });
5364
+ }
5365
+ continue;
5366
+ }
5367
+ if (result.type === "heatmap") {
5368
+ const values = value.split(",").map((v) => parseFloat(v.trim()));
5369
+ if (values.length > 0 && values.every((v) => !isNaN(v))) {
5370
+ const originalKey = trimmed.substring(0, colonIndex).trim();
5371
+ if (!result.heatmapRows) result.heatmapRows = [];
5372
+ result.heatmapRows.push({ label: originalKey, values, lineNumber });
5373
+ }
5374
+ continue;
5375
+ }
5376
+ const numValue = parseFloat(value);
5377
+ if (!isNaN(numValue)) {
5378
+ let rawLabel = trimmed.substring(0, colonIndex).trim();
5379
+ let pointColor;
5380
+ const colorMatch = rawLabel.match(/\(([^)]+)\)\s*$/);
5381
+ if (colorMatch) {
5382
+ pointColor = resolveColor(colorMatch[1].trim(), palette);
5383
+ rawLabel = rawLabel.substring(0, colorMatch.index).trim();
5384
+ }
5385
+ result.data.push({
5386
+ label: rawLabel,
5387
+ value: numValue,
5388
+ ...pointColor && { color: pointColor },
5389
+ lineNumber
5390
+ });
5391
+ }
5392
+ }
5393
+ if (!result.error) {
5394
+ if (result.type === "sankey") {
5395
+ if (!result.links || result.links.length === 0) {
5396
+ result.error = "No links found. Add links in format: Source -> Target: 123";
5397
+ }
5398
+ } else if (result.type === "chord") {
5399
+ if (!result.links || result.links.length === 0) {
5400
+ result.error = "No links found. Add links in format: Source -> Target: 123";
5401
+ }
5402
+ } else if (result.type === "function") {
5403
+ if (!result.functions || result.functions.length === 0) {
5404
+ result.error = "No functions found. Add functions in format: Name: expression";
5405
+ }
5406
+ if (!result.xRange) {
5407
+ result.xRange = { min: -10, max: 10 };
5408
+ }
5409
+ } else if (result.type === "scatter") {
5410
+ if (!result.scatterPoints || result.scatterPoints.length === 0) {
5411
+ result.error = "No scatter points found. Add points in format: Name: x, y or Name: x, y, size";
5412
+ }
5413
+ } else if (result.type === "heatmap") {
5414
+ if (!result.heatmapRows || result.heatmapRows.length === 0) {
5415
+ result.error = "No heatmap data found. Add data in format: RowLabel: val1, val2, val3";
5416
+ }
5417
+ if (!result.columns || result.columns.length === 0) {
5418
+ result.error = "No columns defined. Add columns in format: columns: Col1, Col2, Col3";
5419
+ }
5420
+ } else if (result.type === "funnel") {
5421
+ if (result.data.length === 0) {
5422
+ result.error = "No data found. Add data in format: Label: value";
5423
+ }
5424
+ }
5425
+ }
5426
+ return result;
5427
+ }
5428
+ function buildEChartsOption(parsed, palette, _isDark) {
5429
+ const textColor = palette.text;
5430
+ const axisLineColor = palette.border;
5431
+ const colors = getSeriesColors(palette);
5432
+ if (parsed.error) {
5433
+ return {};
5434
+ }
5435
+ const titleConfig = parsed.title ? {
5436
+ text: parsed.title,
5437
+ left: "center",
5438
+ textStyle: {
5439
+ color: textColor,
5440
+ fontSize: 18,
5441
+ fontWeight: "bold",
5442
+ fontFamily: FONT_FAMILY
5443
+ }
5444
+ } : void 0;
5445
+ const tooltipTheme = {
5446
+ backgroundColor: palette.surface,
5447
+ borderColor: palette.border,
5448
+ textStyle: { color: palette.text }
5449
+ };
5450
+ if (parsed.type === "sankey") {
5451
+ return buildSankeyOption(
5452
+ parsed,
5453
+ textColor,
5454
+ colors,
5455
+ titleConfig,
5456
+ tooltipTheme
5457
+ );
5458
+ }
5459
+ if (parsed.type === "chord") {
5460
+ return buildChordOption(
5461
+ parsed,
5462
+ textColor,
5463
+ colors,
5464
+ titleConfig,
5465
+ tooltipTheme
5466
+ );
5467
+ }
5468
+ if (parsed.type === "function") {
5469
+ return buildFunctionOption(
5470
+ parsed,
5471
+ palette,
5472
+ textColor,
5473
+ axisLineColor,
5474
+ colors,
5475
+ titleConfig,
5476
+ tooltipTheme
5477
+ );
5478
+ }
5479
+ if (parsed.type === "scatter") {
5480
+ return buildScatterOption(
5481
+ parsed,
5482
+ palette,
5483
+ textColor,
5484
+ axisLineColor,
5485
+ colors,
5486
+ titleConfig,
5487
+ tooltipTheme
5488
+ );
5489
+ }
5490
+ if (parsed.type === "funnel") {
5491
+ return buildFunnelOption(
5492
+ parsed,
5493
+ textColor,
5494
+ colors,
5495
+ titleConfig,
5496
+ tooltipTheme
5497
+ );
5498
+ }
5499
+ return buildHeatmapOption(
5500
+ parsed,
5501
+ palette,
5502
+ textColor,
5503
+ axisLineColor,
5504
+ titleConfig,
5505
+ tooltipTheme
5506
+ );
5507
+ }
5508
+ function buildSankeyOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
5509
+ const nodeSet = /* @__PURE__ */ new Set();
5510
+ if (parsed.links) {
5511
+ for (const link of parsed.links) {
5512
+ nodeSet.add(link.source);
5513
+ nodeSet.add(link.target);
5514
+ }
5515
+ }
5516
+ const nodes = Array.from(nodeSet).map((name, index) => ({
5517
+ name,
5518
+ itemStyle: {
5519
+ color: colors[index % colors.length]
5520
+ }
5521
+ }));
5522
+ return {
5523
+ backgroundColor: "transparent",
5524
+ animation: false,
5525
+ title: titleConfig,
5526
+ tooltip: {
5527
+ show: false,
5528
+ ...tooltipTheme
5529
+ },
5530
+ series: [
5531
+ {
5532
+ type: "sankey",
5533
+ emphasis: {
5534
+ focus: "adjacency"
5535
+ },
5536
+ nodeAlign: "left",
5537
+ nodeGap: 12,
5538
+ nodeWidth: 20,
5539
+ data: nodes,
5540
+ links: parsed.links ?? [],
5541
+ lineStyle: {
5542
+ color: "gradient",
5543
+ curveness: 0.5
5544
+ },
5545
+ label: {
5546
+ color: textColor,
5547
+ fontSize: 12
5548
+ }
5549
+ }
5550
+ ]
5551
+ };
5552
+ }
5553
+ function buildChordOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
5554
+ const nodeSet = /* @__PURE__ */ new Set();
5555
+ if (parsed.links) {
5556
+ for (const link of parsed.links) {
5557
+ nodeSet.add(link.source);
5558
+ nodeSet.add(link.target);
5559
+ }
5560
+ }
5561
+ const nodeNames = Array.from(nodeSet);
5562
+ const nodeCount = nodeNames.length;
5563
+ const matrix = Array(nodeCount).fill(null).map(() => Array(nodeCount).fill(0));
5564
+ if (parsed.links) {
5565
+ for (const link of parsed.links) {
5566
+ const sourceIndex = nodeNames.indexOf(link.source);
5567
+ const targetIndex = nodeNames.indexOf(link.target);
5568
+ if (sourceIndex !== -1 && targetIndex !== -1) {
5569
+ matrix[sourceIndex][targetIndex] = link.value;
5570
+ }
5571
+ }
5572
+ }
5573
+ const categories = nodeNames.map((name, index) => ({
5574
+ name,
5575
+ itemStyle: {
5576
+ color: colors[index % colors.length]
5577
+ }
5578
+ }));
5579
+ return {
5580
+ backgroundColor: "transparent",
5581
+ animation: false,
5582
+ title: titleConfig,
5583
+ tooltip: {
5584
+ trigger: "item",
5585
+ ...tooltipTheme,
5586
+ formatter: (params) => {
5587
+ const p = params;
5588
+ if (p.data && p.data.source && p.data.target) {
5589
+ return `${p.data.source} \u2192 ${p.data.target}: ${p.data.value}`;
5590
+ }
5591
+ return "";
5592
+ }
5593
+ },
5594
+ legend: {
5595
+ data: nodeNames,
5596
+ bottom: 10,
5597
+ textStyle: {
5598
+ color: textColor
5599
+ }
5600
+ },
5601
+ series: [
5602
+ {
5603
+ type: "graph",
5604
+ layout: "circular",
5605
+ circular: {
5606
+ rotateLabel: true
5607
+ },
5608
+ center: ["50%", "55%"],
5609
+ width: "60%",
5610
+ height: "60%",
5611
+ data: categories.map((cat) => ({
5612
+ name: cat.name,
5613
+ symbolSize: 20,
5614
+ itemStyle: cat.itemStyle,
5615
+ label: {
5616
+ show: true,
5617
+ color: textColor
5618
+ }
5619
+ })),
5620
+ links: (parsed.links ?? []).map((link) => ({
5621
+ source: link.source,
5622
+ target: link.target,
5623
+ value: link.value,
5624
+ lineStyle: {
5625
+ width: Math.max(1, Math.min(link.value / 20, 10)),
5626
+ color: colors[nodeNames.indexOf(link.source) % colors.length],
5627
+ curveness: 0.3,
5628
+ opacity: 0.6
5629
+ }
5630
+ })),
5631
+ roam: true,
5632
+ label: {
5633
+ position: "right",
5634
+ formatter: "{b}"
5635
+ },
5636
+ emphasis: {
5637
+ focus: "adjacency",
5638
+ lineStyle: {
5639
+ width: 5,
5640
+ opacity: 1
5641
+ }
5642
+ }
5643
+ }
5644
+ ]
5645
+ };
5646
+ }
5647
+ function evaluateExpression(expr, x) {
5648
+ try {
5649
+ const processed = expr.replace(/\bpi\b/gi, String(Math.PI)).replace(/\be\b/g, String(Math.E)).replace(/\bsin\s*\(/gi, "Math.sin(").replace(/\bcos\s*\(/gi, "Math.cos(").replace(/\btan\s*\(/gi, "Math.tan(").replace(/\bln\s*\(/gi, "Math.log(").replace(/\blog\s*\(/gi, "Math.log10(").replace(/\bexp\s*\(/gi, "Math.exp(").replace(/\bsqrt\s*\(/gi, "Math.sqrt(").replace(/\babs\s*\(/gi, "Math.abs(").replace(/\bx\b/gi, `(${x})`).replace(/\^/g, "**");
5650
+ const result = new Function(`return ${processed}`)();
5651
+ return typeof result === "number" && isFinite(result) ? result : NaN;
5652
+ } catch {
5653
+ return NaN;
5654
+ }
5655
+ }
5656
+ function buildFunctionOption(parsed, palette, textColor, axisLineColor, colors, titleConfig, tooltipTheme) {
5657
+ const xRange = parsed.xRange ?? { min: -10, max: 10 };
5658
+ const samples = 200;
5659
+ const step = (xRange.max - xRange.min) / samples;
5660
+ const xValues = [];
5661
+ for (let i = 0; i <= samples; i++) {
5662
+ xValues.push(xRange.min + i * step);
5663
+ }
5664
+ const series = (parsed.functions ?? []).map((fn, index) => {
5665
+ const data = xValues.map((x) => {
5666
+ const y = evaluateExpression(fn.expression, x);
5667
+ return [x, y];
5668
+ });
5669
+ const fnColor = fn.color ?? colors[index % colors.length];
5670
+ return {
5671
+ name: fn.name,
5672
+ type: "line",
5673
+ showSymbol: false,
5674
+ smooth: true,
5675
+ data,
5676
+ lineStyle: {
5677
+ width: 2,
5678
+ color: fnColor
5679
+ },
5680
+ itemStyle: {
5681
+ color: fnColor
5682
+ }
5683
+ };
5684
+ });
5685
+ return {
5686
+ backgroundColor: "transparent",
5687
+ animation: false,
5688
+ title: titleConfig,
5689
+ tooltip: {
5690
+ trigger: "axis",
5691
+ ...tooltipTheme,
5692
+ axisPointer: {
5693
+ type: "cross"
5694
+ }
5695
+ },
5696
+ legend: {
5697
+ data: (parsed.functions ?? []).map((fn) => fn.name),
5698
+ bottom: 10,
5699
+ textStyle: {
5700
+ color: textColor
5701
+ }
5702
+ },
5703
+ grid: {
5704
+ left: "3%",
5705
+ right: "4%",
5706
+ bottom: "15%",
5707
+ top: parsed.title ? "15%" : "5%",
5708
+ containLabel: true
5709
+ },
5710
+ xAxis: {
5711
+ type: "value",
5712
+ min: xRange.min,
5713
+ max: xRange.max,
5714
+ axisLine: {
5715
+ lineStyle: { color: axisLineColor }
5716
+ },
5717
+ axisLabel: {
5718
+ color: textColor
5719
+ },
5720
+ splitLine: {
5721
+ lineStyle: {
5722
+ color: palette.overlay
5723
+ }
5724
+ }
5725
+ },
5726
+ yAxis: {
5727
+ type: "value",
5728
+ axisLine: {
5729
+ lineStyle: { color: axisLineColor }
5730
+ },
5731
+ axisLabel: {
5732
+ color: textColor
5733
+ },
5734
+ splitLine: {
5735
+ lineStyle: {
5736
+ color: palette.overlay
5737
+ }
5738
+ }
5739
+ },
5740
+ series
5741
+ };
5742
+ }
5743
+ function buildScatterOption(parsed, palette, textColor, axisLineColor, colors, titleConfig, tooltipTheme) {
5744
+ const points = parsed.scatterPoints ?? [];
5745
+ const defaultSize = 15;
5746
+ const hasCategories = points.some((p) => p.category !== void 0);
5747
+ const hasSize = points.some((p) => p.size !== void 0);
5748
+ const labelConfig = {
5749
+ show: parsed.showLabels ?? false,
5750
+ formatter: "{b}",
5751
+ position: "top",
5752
+ color: textColor,
5753
+ fontSize: 11
5754
+ };
5755
+ const emphasisConfig = {
5756
+ focus: "self",
5757
+ itemStyle: {
5758
+ shadowBlur: 10,
5759
+ shadowColor: "rgba(0, 0, 0, 0.3)"
5760
+ }
5761
+ };
5762
+ let series;
5763
+ let legendData;
5764
+ if (hasCategories) {
5765
+ const categories = [
5766
+ ...new Set(points.map((p) => p.category).filter(Boolean))
5767
+ ];
5768
+ legendData = categories;
5769
+ series = categories.map((category, catIndex) => {
5770
+ const categoryPoints = points.filter((p) => p.category === category);
5771
+ const catColor = parsed.categoryColors?.[category] ?? colors[catIndex % colors.length];
5772
+ const data = categoryPoints.map((p) => ({
5773
+ name: p.name,
5774
+ value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
5775
+ ...p.color && { itemStyle: { color: p.color } }
5776
+ }));
5777
+ return {
5778
+ name: category,
5779
+ type: "scatter",
5780
+ data,
5781
+ ...hasSize ? { symbolSize: (val) => val[2] } : { symbolSize: defaultSize },
5782
+ itemStyle: { color: catColor },
5783
+ label: labelConfig,
5784
+ emphasis: emphasisConfig
5785
+ };
5786
+ });
5787
+ } else {
5788
+ const data = points.map((p, index) => ({
5789
+ name: p.name,
5790
+ value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
5791
+ ...hasSize ? { symbolSize: p.size ?? defaultSize } : { symbolSize: defaultSize },
5792
+ itemStyle: {
5793
+ color: p.color ?? colors[index % colors.length]
5794
+ }
5795
+ }));
5796
+ series = [
5797
+ {
5798
+ type: "scatter",
5799
+ data,
5800
+ label: labelConfig,
5801
+ emphasis: emphasisConfig
5802
+ }
5803
+ ];
5804
+ }
5805
+ const tooltip = {
5806
+ trigger: "item",
5807
+ ...tooltipTheme,
5808
+ formatter: (params) => {
5809
+ const p = params;
5810
+ const xLabel = parsed.xlabel || "x";
5811
+ const yLabel = parsed.ylabel || "y";
5812
+ let html = `<strong>${p.name}</strong>`;
5813
+ if (hasCategories) html += `<br/>${p.seriesName}`;
5814
+ html += `<br/>${xLabel}: ${p.value[0]}<br/>${yLabel}: ${p.value[1]}`;
5815
+ if (hasSize) html += `<br/>${parsed.sizelabel || "size"}: ${p.value[2]}`;
5816
+ return html;
5817
+ }
5818
+ };
5819
+ return {
5820
+ backgroundColor: "transparent",
5821
+ animation: false,
5822
+ title: titleConfig,
5823
+ tooltip,
5824
+ ...legendData && {
5825
+ legend: {
5826
+ data: legendData,
5827
+ bottom: 10,
5828
+ textStyle: { color: textColor }
5829
+ }
5830
+ },
5831
+ grid: {
5832
+ left: "3%",
5833
+ right: "4%",
5834
+ bottom: hasCategories ? "15%" : "3%",
5835
+ top: parsed.title ? "15%" : "5%",
5836
+ containLabel: true
5837
+ },
5838
+ xAxis: {
5839
+ type: "value",
5840
+ name: parsed.xlabel,
5841
+ nameLocation: "middle",
5842
+ nameGap: 30,
5843
+ nameTextStyle: {
5844
+ color: textColor,
5845
+ fontSize: 12
5846
+ },
5847
+ axisLine: {
5848
+ lineStyle: { color: axisLineColor }
5849
+ },
5850
+ axisLabel: {
5851
+ color: textColor
5852
+ },
5853
+ splitLine: {
5854
+ lineStyle: {
5855
+ color: palette.overlay
5856
+ }
5857
+ }
5858
+ },
5859
+ yAxis: {
5860
+ type: "value",
5861
+ name: parsed.ylabel,
5862
+ nameLocation: "middle",
5863
+ nameGap: 40,
5864
+ nameTextStyle: {
5865
+ color: textColor,
5866
+ fontSize: 12
5867
+ },
5868
+ axisLine: {
5869
+ lineStyle: { color: axisLineColor }
5870
+ },
5871
+ axisLabel: {
5872
+ color: textColor
5873
+ },
5874
+ splitLine: {
5875
+ lineStyle: {
5876
+ color: palette.overlay
5877
+ }
5878
+ }
5879
+ },
5880
+ series
5881
+ };
5882
+ }
5883
+ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConfig, tooltipTheme) {
5884
+ const heatmapRows = parsed.heatmapRows ?? [];
5885
+ const columns = parsed.columns ?? [];
5886
+ const rowLabels = heatmapRows.map((r) => r.label);
5887
+ const data = [];
5888
+ let minValue = Infinity;
5889
+ let maxValue = -Infinity;
5890
+ heatmapRows.forEach((row, rowIndex) => {
5891
+ row.values.forEach((value, colIndex) => {
5892
+ data.push([colIndex, rowIndex, value]);
5893
+ minValue = Math.min(minValue, value);
5894
+ maxValue = Math.max(maxValue, value);
5895
+ });
5896
+ });
5897
+ return {
5898
+ backgroundColor: "transparent",
5899
+ animation: false,
5900
+ title: titleConfig,
5901
+ tooltip: {
5902
+ trigger: "item",
5903
+ ...tooltipTheme,
5904
+ formatter: (params) => {
5905
+ const p = params;
5906
+ const colName = columns[p.data[0]] ?? p.data[0];
5907
+ const rowName = rowLabels[p.data[1]] ?? p.data[1];
5908
+ return `${rowName} / ${colName}: <strong>${p.data[2]}</strong>`;
5909
+ }
5910
+ },
5911
+ grid: {
5912
+ left: "3%",
5913
+ right: "10%",
5914
+ bottom: "3%",
5915
+ top: parsed.title ? "15%" : "5%",
5916
+ containLabel: true
5917
+ },
5918
+ xAxis: {
5919
+ type: "category",
5920
+ data: columns,
5921
+ splitArea: {
5922
+ show: true
5923
+ },
5924
+ axisLine: {
5925
+ lineStyle: { color: axisLineColor }
5926
+ },
5927
+ axisLabel: {
5928
+ color: textColor
5929
+ }
5930
+ },
5931
+ yAxis: {
5932
+ type: "category",
5933
+ data: rowLabels,
5934
+ splitArea: {
5935
+ show: true
5936
+ },
5937
+ axisLine: {
5938
+ lineStyle: { color: axisLineColor }
5939
+ },
5940
+ axisLabel: {
5941
+ color: textColor
5942
+ }
5943
+ },
5944
+ visualMap: {
5945
+ min: minValue,
5946
+ max: maxValue,
5947
+ calculable: true,
5948
+ orient: "vertical",
5949
+ right: "2%",
5950
+ top: "center",
5951
+ inRange: {
5952
+ color: [
5953
+ palette.bg,
5954
+ palette.primary,
5955
+ palette.colors.cyan,
5956
+ palette.colors.yellow,
5957
+ palette.colors.orange
5958
+ ]
5959
+ },
5960
+ textStyle: {
5961
+ color: textColor
5962
+ }
5963
+ },
5964
+ series: [
5965
+ {
5966
+ type: "heatmap",
5967
+ data,
5968
+ label: {
5969
+ show: true,
5970
+ color: textColor
5971
+ },
5972
+ emphasis: {
5973
+ itemStyle: {
5974
+ shadowBlur: 10,
5975
+ shadowColor: "rgba(0, 0, 0, 0.5)"
5976
+ }
5977
+ }
5978
+ }
5979
+ ]
5980
+ };
5981
+ }
5982
+ function buildFunnelOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
5983
+ const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
5984
+ const topValue = sorted.length > 0 ? sorted[0].value : 1;
5985
+ const data = sorted.map((d) => ({
5986
+ name: d.label,
5987
+ value: d.value,
5988
+ itemStyle: {
5989
+ color: d.color ?? colors[parsed.data.indexOf(d) % colors.length],
5990
+ borderWidth: 0
5991
+ }
5992
+ }));
5993
+ const prevValueMap = /* @__PURE__ */ new Map();
5994
+ for (let i = 0; i < sorted.length; i++) {
5995
+ prevValueMap.set(
5996
+ sorted[i].label,
5997
+ i > 0 ? sorted[i - 1].value : sorted[i].value
5998
+ );
5999
+ }
6000
+ const funnelTop = parsed.title ? 60 : 20;
6001
+ const funnelLayout = {
6002
+ left: "20%",
6003
+ top: funnelTop,
6004
+ bottom: 20,
6005
+ width: "60%",
6006
+ sort: "descending",
6007
+ gap: 2,
6008
+ minSize: "8%"
6009
+ };
6010
+ return {
6011
+ backgroundColor: "transparent",
6012
+ animation: false,
6013
+ title: titleConfig,
6014
+ tooltip: {
6015
+ trigger: "item",
6016
+ ...tooltipTheme,
6017
+ formatter: (params) => {
6018
+ const p = params;
6019
+ const val = p.value;
6020
+ const prev = prevValueMap.get(p.name) ?? val;
6021
+ const isFirst = p.dataIndex === 0;
6022
+ let html = `<strong>${p.name}</strong>: ${val}`;
6023
+ if (!isFirst) {
6024
+ const stepDrop = ((1 - val / prev) * 100).toFixed(1);
6025
+ html += `<br/>Step drop-off: ${stepDrop}%`;
6026
+ }
6027
+ if (!isFirst && topValue > 0) {
6028
+ const totalDrop = ((1 - val / topValue) * 100).toFixed(1);
6029
+ html += `<br/>Overall drop-off: ${totalDrop}%`;
6030
+ }
6031
+ return html;
6032
+ }
6033
+ },
6034
+ series: [
6035
+ {
6036
+ type: "funnel",
6037
+ ...funnelLayout,
6038
+ label: {
6039
+ show: true,
6040
+ position: "left",
6041
+ formatter: "{b}",
6042
+ color: textColor,
6043
+ fontSize: 13
6044
+ },
6045
+ labelLine: {
6046
+ show: true,
6047
+ length: 10,
6048
+ lineStyle: { color: textColor, opacity: 0.3 }
6049
+ },
6050
+ emphasis: {
6051
+ label: {
6052
+ fontSize: 15
6053
+ }
6054
+ },
6055
+ data
6056
+ },
6057
+ {
6058
+ type: "funnel",
6059
+ ...funnelLayout,
6060
+ silent: true,
6061
+ itemStyle: { color: "transparent", borderWidth: 0 },
6062
+ label: {
6063
+ show: true,
6064
+ position: "right",
6065
+ formatter: "{c}",
6066
+ color: textColor,
6067
+ fontSize: 13
6068
+ },
6069
+ labelLine: {
6070
+ show: true,
6071
+ length: 10,
6072
+ lineStyle: { color: textColor, opacity: 0.3 }
6073
+ },
6074
+ emphasis: { disabled: true },
6075
+ data: data.map((d) => ({
6076
+ ...d,
6077
+ itemStyle: { color: "transparent", borderWidth: 0 }
6078
+ }))
6079
+ }
6080
+ ]
6081
+ };
6082
+ }
6083
+ function resolveAxisLabels(parsed) {
6084
+ const isHorizontal = parsed.orientation === "horizontal";
6085
+ return {
6086
+ xLabel: parsed.xlabel ?? (isHorizontal ? parsed.label : void 0),
6087
+ yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
6088
+ };
6089
+ }
6090
+ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, label, data) {
6091
+ return {
6092
+ type,
6093
+ ...data && { data },
6094
+ axisLine: { lineStyle: { color: axisLineColor } },
6095
+ axisLabel: { color: textColor, fontFamily: FONT_FAMILY },
6096
+ splitLine: { lineStyle: { color: splitLineColor } },
6097
+ ...label && {
6098
+ name: label,
6099
+ nameLocation: "middle",
6100
+ nameGap: 30,
6101
+ nameTextStyle: { color: textColor, fontSize: 12, fontFamily: FONT_FAMILY }
6102
+ }
6103
+ };
6104
+ }
6105
+ function buildEChartsOptionFromChart(parsed, palette, _isDark) {
6106
+ if (parsed.error) return {};
6107
+ const textColor = palette.text;
6108
+ const axisLineColor = palette.border;
6109
+ const splitLineColor = palette.overlay;
6110
+ const colors = getSeriesColors(palette);
6111
+ const titleConfig = parsed.title ? {
6112
+ text: parsed.title,
6113
+ left: "center",
6114
+ textStyle: {
6115
+ color: textColor,
6116
+ fontSize: 18,
6117
+ fontWeight: "bold",
6118
+ fontFamily: FONT_FAMILY
6119
+ }
6120
+ } : void 0;
6121
+ const tooltipTheme = {
6122
+ backgroundColor: palette.surface,
6123
+ borderColor: palette.border,
6124
+ textStyle: { color: palette.text }
6125
+ };
6126
+ switch (parsed.type) {
6127
+ case "bar":
6128
+ return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme);
6129
+ case "bar-stacked":
6130
+ return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme);
6131
+ case "line":
6132
+ return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, titleConfig, tooltipTheme);
6133
+ case "area":
6134
+ return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, titleConfig, tooltipTheme);
6135
+ case "pie":
6136
+ return buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, false);
6137
+ case "doughnut":
6138
+ return buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, true);
6139
+ case "radar":
6140
+ return buildRadarOption(parsed, palette, textColor, colors, titleConfig, tooltipTheme);
6141
+ case "polar-area":
6142
+ return buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipTheme);
6143
+ }
6144
+ }
6145
+ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme) {
6146
+ const { xLabel, yLabel } = resolveAxisLabels(parsed);
6147
+ const isHorizontal = parsed.orientation === "horizontal";
6148
+ const labels = parsed.data.map((d) => d.label);
6149
+ const data = parsed.data.map((d, i) => ({
6150
+ value: d.value,
6151
+ itemStyle: { color: d.color ?? colors[i % colors.length] }
6152
+ }));
6153
+ const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, isHorizontal ? yLabel : xLabel, labels);
6154
+ const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, isHorizontal ? xLabel : yLabel);
6155
+ return {
6156
+ backgroundColor: "transparent",
6157
+ animation: false,
6158
+ title: titleConfig,
6159
+ tooltip: {
6160
+ trigger: "axis",
6161
+ ...tooltipTheme,
6162
+ axisPointer: { type: "shadow" }
6163
+ },
6164
+ grid: {
6165
+ left: "3%",
6166
+ right: "4%",
6167
+ bottom: "3%",
6168
+ top: parsed.title ? "15%" : "5%",
6169
+ containLabel: true
6170
+ },
6171
+ xAxis: isHorizontal ? valueAxis : categoryAxis,
6172
+ yAxis: isHorizontal ? categoryAxis : valueAxis,
6173
+ series: [
6174
+ {
6175
+ type: "bar",
6176
+ data
6177
+ }
6178
+ ]
6179
+ };
6180
+ }
6181
+ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, titleConfig, tooltipTheme) {
6182
+ const { xLabel, yLabel } = resolveAxisLabels(parsed);
6183
+ const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
6184
+ const labels = parsed.data.map((d) => d.label);
6185
+ const values = parsed.data.map((d) => d.value);
6186
+ return {
6187
+ backgroundColor: "transparent",
6188
+ animation: false,
6189
+ title: titleConfig,
6190
+ tooltip: {
6191
+ trigger: "axis",
6192
+ ...tooltipTheme,
6193
+ axisPointer: { type: "line" }
6194
+ },
6195
+ grid: {
6196
+ left: "3%",
6197
+ right: "4%",
6198
+ bottom: "3%",
6199
+ top: parsed.title ? "15%" : "5%",
6200
+ containLabel: true
6201
+ },
6202
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, xLabel, labels),
6203
+ yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, yLabel),
6204
+ series: [
6205
+ {
6206
+ type: "line",
6207
+ data: values,
6208
+ smooth: false,
6209
+ symbolSize: 8,
6210
+ lineStyle: { color: lineColor, width: 3 },
6211
+ itemStyle: { color: lineColor }
6212
+ }
6213
+ ]
6214
+ };
6215
+ }
6216
+ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme) {
6217
+ const { xLabel, yLabel } = resolveAxisLabels(parsed);
6218
+ const seriesNames = parsed.seriesNames ?? [];
6219
+ const labels = parsed.data.map((d) => d.label);
6220
+ const series = seriesNames.map((name, idx) => {
6221
+ const color = parsed.seriesNameColors?.[idx] ?? colors[idx % colors.length];
6222
+ const data = parsed.data.map(
6223
+ (dp) => idx === 0 ? dp.value : dp.extraValues?.[idx - 1] ?? 0
6224
+ );
6225
+ return {
6226
+ name,
6227
+ type: "line",
6228
+ data,
6229
+ smooth: false,
6230
+ symbolSize: 8,
6231
+ lineStyle: { color, width: 3 },
6232
+ itemStyle: { color }
6233
+ };
6234
+ });
6235
+ return {
6236
+ backgroundColor: "transparent",
6237
+ animation: false,
6238
+ title: titleConfig,
6239
+ tooltip: {
6240
+ trigger: "axis",
6241
+ ...tooltipTheme,
6242
+ axisPointer: { type: "line" }
6243
+ },
6244
+ legend: {
6245
+ data: seriesNames,
6246
+ bottom: 10,
6247
+ textStyle: { color: textColor }
6248
+ },
6249
+ grid: {
6250
+ left: "3%",
6251
+ right: "4%",
6252
+ bottom: "15%",
6253
+ top: parsed.title ? "15%" : "5%",
6254
+ containLabel: true
6255
+ },
6256
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, xLabel, labels),
6257
+ yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, yLabel),
6258
+ series
6259
+ };
6260
+ }
6261
+ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, titleConfig, tooltipTheme) {
6262
+ const { xLabel, yLabel } = resolveAxisLabels(parsed);
6263
+ const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
6264
+ const labels = parsed.data.map((d) => d.label);
6265
+ const values = parsed.data.map((d) => d.value);
6266
+ return {
6267
+ backgroundColor: "transparent",
6268
+ animation: false,
6269
+ title: titleConfig,
6270
+ tooltip: {
6271
+ trigger: "axis",
6272
+ ...tooltipTheme,
6273
+ axisPointer: { type: "line" }
6274
+ },
6275
+ grid: {
6276
+ left: "3%",
6277
+ right: "4%",
6278
+ bottom: "3%",
6279
+ top: parsed.title ? "15%" : "5%",
6280
+ containLabel: true
6281
+ },
6282
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, xLabel, labels),
6283
+ yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, yLabel),
6284
+ series: [
6285
+ {
6286
+ type: "line",
6287
+ data: values,
6288
+ smooth: false,
6289
+ symbolSize: 8,
6290
+ lineStyle: { color: lineColor, width: 3 },
6291
+ itemStyle: { color: lineColor },
6292
+ areaStyle: { opacity: 0.25 }
6293
+ }
6294
+ ]
6295
+ };
6296
+ }
6297
+ function buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, isDoughnut) {
6298
+ const data = parsed.data.map((d, i) => ({
6299
+ name: d.label,
6300
+ value: d.value,
6301
+ itemStyle: { color: d.color ?? colors[i % colors.length] }
6302
+ }));
6303
+ return {
6304
+ backgroundColor: "transparent",
6305
+ animation: false,
6306
+ title: titleConfig,
6307
+ tooltip: {
6308
+ trigger: "item",
6309
+ ...tooltipTheme
6310
+ },
6311
+ series: [
6312
+ {
6313
+ type: "pie",
6314
+ radius: isDoughnut ? ["40%", "70%"] : ["0%", "70%"],
6315
+ data,
6316
+ label: {
6317
+ position: "outside",
6318
+ formatter: "{b}",
6319
+ color: textColor,
6320
+ fontFamily: FONT_FAMILY
6321
+ },
6322
+ labelLine: { show: true }
6323
+ }
6324
+ ]
6325
+ };
6326
+ }
6327
+ function buildRadarOption(parsed, palette, textColor, colors, titleConfig, tooltipTheme) {
6328
+ const radarColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
6329
+ const values = parsed.data.map((d) => d.value);
6330
+ const maxValue = Math.max(...values) * 1.15;
6331
+ const gridOpacity = 0.6;
6332
+ const indicator = parsed.data.map((d) => ({
6333
+ name: d.label,
6334
+ max: maxValue
6335
+ }));
6336
+ return {
6337
+ backgroundColor: "transparent",
6338
+ animation: false,
6339
+ title: titleConfig,
6340
+ tooltip: {
6341
+ trigger: "item",
6342
+ ...tooltipTheme
6343
+ },
6344
+ radar: {
6345
+ indicator,
6346
+ axisName: {
6347
+ color: textColor,
6348
+ fontFamily: FONT_FAMILY
6349
+ },
6350
+ splitLine: {
6351
+ lineStyle: { color: palette.border, opacity: gridOpacity }
6352
+ },
6353
+ axisLine: {
6354
+ lineStyle: { color: palette.border, opacity: gridOpacity }
6355
+ },
6356
+ splitArea: { show: false }
6357
+ },
6358
+ series: [
6359
+ {
6360
+ type: "radar",
6361
+ data: [
6362
+ {
6363
+ value: values,
6364
+ name: parsed.series ?? "Value",
6365
+ areaStyle: { color: radarColor, opacity: 0.25 },
6366
+ lineStyle: { color: radarColor },
6367
+ itemStyle: { color: radarColor },
6368
+ symbol: "circle",
6369
+ symbolSize: 8,
6370
+ label: {
6371
+ show: true,
6372
+ formatter: "{c}",
6373
+ color: textColor,
6374
+ fontSize: 11,
6375
+ fontFamily: FONT_FAMILY
6376
+ }
6377
+ }
6378
+ ]
6379
+ }
6380
+ ]
6381
+ };
6382
+ }
6383
+ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
6384
+ const data = parsed.data.map((d, i) => ({
6385
+ name: d.label,
6386
+ value: d.value,
6387
+ itemStyle: { color: d.color ?? colors[i % colors.length] }
6388
+ }));
6389
+ return {
6390
+ backgroundColor: "transparent",
6391
+ animation: false,
6392
+ title: titleConfig,
6393
+ tooltip: {
6394
+ trigger: "item",
6395
+ ...tooltipTheme
6396
+ },
6397
+ series: [
6398
+ {
6399
+ type: "pie",
6400
+ roseType: "radius",
6401
+ radius: ["10%", "70%"],
6402
+ data,
6403
+ label: {
6404
+ position: "outside",
6405
+ formatter: "{b}",
6406
+ color: textColor,
6407
+ fontFamily: FONT_FAMILY
6408
+ },
6409
+ labelLine: { show: true }
6410
+ }
6411
+ ]
6412
+ };
6413
+ }
6414
+ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, colors, titleConfig, tooltipTheme) {
6415
+ const { xLabel, yLabel } = resolveAxisLabels(parsed);
6416
+ const isHorizontal = parsed.orientation === "horizontal";
6417
+ const seriesNames = parsed.seriesNames ?? [];
6418
+ const labels = parsed.data.map((d) => d.label);
6419
+ const series = seriesNames.map((name, idx) => {
6420
+ const color = parsed.seriesNameColors?.[idx] ?? colors[idx % colors.length];
6421
+ const data = parsed.data.map(
6422
+ (dp) => idx === 0 ? dp.value : dp.extraValues?.[idx - 1] ?? 0
6423
+ );
6424
+ return {
6425
+ name,
6426
+ type: "bar",
6427
+ stack: "total",
6428
+ data,
6429
+ itemStyle: { color }
6430
+ };
6431
+ });
6432
+ const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, isHorizontal ? yLabel : xLabel, labels);
6433
+ const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, isHorizontal ? xLabel : yLabel);
6434
+ return {
6435
+ backgroundColor: "transparent",
6436
+ animation: false,
6437
+ title: titleConfig,
6438
+ tooltip: {
6439
+ trigger: "axis",
6440
+ ...tooltipTheme,
6441
+ axisPointer: { type: "shadow" }
6442
+ },
6443
+ legend: {
6444
+ data: seriesNames,
6445
+ bottom: 10,
6446
+ textStyle: { color: textColor }
6447
+ },
6448
+ grid: {
6449
+ left: "3%",
6450
+ right: "4%",
6451
+ bottom: "15%",
6452
+ top: parsed.title ? "15%" : "5%",
6453
+ containLabel: true
6454
+ },
6455
+ xAxis: isHorizontal ? valueAxis : categoryAxis,
6456
+ yAxis: isHorizontal ? categoryAxis : valueAxis,
6457
+ series
6458
+ };
6459
+ }
6460
+ var ECHART_EXPORT_WIDTH = 1200;
6461
+ var ECHART_EXPORT_HEIGHT = 800;
6462
+ var STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
6463
+ "bar",
6464
+ "line",
6465
+ "multi-line",
6466
+ "area",
6467
+ "pie",
6468
+ "doughnut",
6469
+ "radar",
6470
+ "polar-area",
6471
+ "bar-stacked"
6472
+ ]);
6473
+ async function renderEChartsForExport(content, theme, palette) {
6474
+ const isDark = theme === "dark";
6475
+ const { getPalette: getPalette2 } = await Promise.resolve().then(() => (init_palettes(), palettes_exports));
6476
+ const effectivePalette = palette ?? (isDark ? getPalette2("nord").dark : getPalette2("nord").light);
6477
+ const chartLine = content.match(/^chart\s*:\s*(.+)/im);
6478
+ const chartType = chartLine?.[1]?.trim().toLowerCase();
6479
+ let option;
6480
+ if (chartType && STANDARD_CHART_TYPES.has(chartType)) {
6481
+ const parsed = parseChart(content, effectivePalette);
6482
+ if (parsed.error) return "";
6483
+ option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark);
6484
+ } else {
6485
+ const parsed = parseEChart(content, effectivePalette);
6486
+ if (parsed.error) return "";
6487
+ option = buildEChartsOption(parsed, effectivePalette, isDark);
6488
+ }
6489
+ if (!option || Object.keys(option).length === 0) return "";
6490
+ const chart = echarts.init(null, null, {
6491
+ renderer: "svg",
6492
+ ssr: true,
6493
+ width: ECHART_EXPORT_WIDTH,
6494
+ height: ECHART_EXPORT_HEIGHT
6495
+ });
6496
+ try {
6497
+ chart.setOption(option);
6498
+ const svgString = chart.renderToSVGString();
6499
+ if (!svgString) return "";
6500
+ return svgString.replace(
6501
+ /^<svg /,
6502
+ `<svg style="font-family: ${FONT_FAMILY}" `
6503
+ );
6504
+ } finally {
6505
+ chart.dispose();
6506
+ }
6507
+ }
6508
+
6509
+ // src/dgmo-router.ts
6510
+ init_parser();
6511
+ var DGMO_CHART_TYPE_MAP = {
6512
+ // Standard charts (via ECharts)
6513
+ bar: "echart",
6514
+ line: "echart",
6515
+ "multi-line": "echart",
6516
+ area: "echart",
6517
+ pie: "echart",
6518
+ doughnut: "echart",
6519
+ radar: "echart",
6520
+ "polar-area": "echart",
6521
+ "bar-stacked": "echart",
6522
+ // ECharts
6523
+ scatter: "echart",
6524
+ sankey: "echart",
6525
+ chord: "echart",
6526
+ function: "echart",
6527
+ heatmap: "echart",
6528
+ funnel: "echart",
6529
+ // D3
6530
+ slope: "d3",
6531
+ wordcloud: "d3",
6532
+ arc: "d3",
6533
+ timeline: "d3",
6534
+ venn: "d3",
6535
+ quadrant: "d3",
6536
+ sequence: "d3"
6537
+ };
6538
+ function getDgmoFramework(chartType) {
6539
+ return DGMO_CHART_TYPE_MAP[chartType.toLowerCase()] ?? null;
6540
+ }
6541
+ function parseDgmoChartType(content) {
6542
+ const lines = content.split("\n");
6543
+ for (const line2 of lines) {
6544
+ const trimmed = line2.trim();
6545
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("//"))
6546
+ continue;
6547
+ const match = trimmed.match(/^chart\s*:\s*(.+)/i);
6548
+ if (match) return match[1].trim().toLowerCase();
6549
+ }
6550
+ if (looksLikeSequence(content)) return "sequence";
6551
+ return null;
6552
+ }
6553
+
5069
6554
  // src/cli.ts
5070
6555
  init_registry();
5071
6556
  init_fonts();
@@ -5247,13 +6732,23 @@ async function main() {
5247
6732
  } else {
5248
6733
  noInput();
5249
6734
  }
5250
- setupDom();
5251
6735
  const isDark = opts.theme === "dark";
5252
6736
  const paletteColors = isDark ? getPalette(opts.palette).dark : getPalette(opts.palette).light;
5253
- const svg = await renderD3ForExport(content, opts.theme, paletteColors);
6737
+ const chartType = parseDgmoChartType(content);
6738
+ const framework = chartType ? getDgmoFramework(chartType) : null;
6739
+ let svg;
6740
+ if (framework === "echart") {
6741
+ svg = await renderEChartsForExport(content, opts.theme, paletteColors);
6742
+ } else if (framework === "d3" || framework === null) {
6743
+ setupDom();
6744
+ svg = await renderD3ForExport(content, opts.theme, paletteColors);
6745
+ } else {
6746
+ console.error(`Error: Unknown chart framework "${framework}".`);
6747
+ process.exit(1);
6748
+ }
5254
6749
  if (!svg) {
5255
6750
  console.error(
5256
- "Error: Failed to render diagram. The input may be empty, invalid, or use an unsupported chart type (e.g. Chart.js/ECharts charts require a browser)."
6751
+ "Error: Failed to render diagram. The input may be empty, invalid, or use an unsupported chart type."
5257
6752
  );
5258
6753
  process.exit(1);
5259
6754
  }