@diagrammo/dgmo 0.3.0 → 0.3.2
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/skills/dgmo-chart/SKILL.md +6 -0
- package/README.md +5 -0
- package/dist/cli.cjs +139 -140
- package/dist/index.cjs +267 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +267 -113
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +35 -0
- package/package.json +1 -1
- package/src/chart.ts +12 -6
- package/src/d3.ts +129 -52
- package/src/echarts.ts +79 -28
- package/src/sequence/parser.ts +16 -3
- package/src/sequence/renderer.ts +22 -0
- package/src/utils/parsing.ts +31 -0
package/dist/index.cjs
CHANGED
|
@@ -1275,6 +1275,67 @@ var init_palettes = __esm({
|
|
|
1275
1275
|
}
|
|
1276
1276
|
});
|
|
1277
1277
|
|
|
1278
|
+
// src/utils/parsing.ts
|
|
1279
|
+
function measureIndent(line7) {
|
|
1280
|
+
let indent = 0;
|
|
1281
|
+
for (const ch of line7) {
|
|
1282
|
+
if (ch === " ") indent++;
|
|
1283
|
+
else if (ch === " ") indent += 4;
|
|
1284
|
+
else break;
|
|
1285
|
+
}
|
|
1286
|
+
return indent;
|
|
1287
|
+
}
|
|
1288
|
+
function extractColor(label, palette) {
|
|
1289
|
+
const m = label.match(COLOR_SUFFIX_RE);
|
|
1290
|
+
if (!m) return { label };
|
|
1291
|
+
const colorName = m[1].trim();
|
|
1292
|
+
return {
|
|
1293
|
+
label: label.substring(0, m.index).trim(),
|
|
1294
|
+
color: resolveColor(colorName, palette)
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
function collectIndentedValues(lines, startIndex) {
|
|
1298
|
+
const values = [];
|
|
1299
|
+
let j = startIndex + 1;
|
|
1300
|
+
for (; j < lines.length; j++) {
|
|
1301
|
+
const raw = lines[j];
|
|
1302
|
+
const trimmed = raw.trim();
|
|
1303
|
+
if (!trimmed) continue;
|
|
1304
|
+
if (trimmed.startsWith("//")) continue;
|
|
1305
|
+
if (raw[0] !== " " && raw[0] !== " ") break;
|
|
1306
|
+
values.push(trimmed.replace(/,\s*$/, ""));
|
|
1307
|
+
}
|
|
1308
|
+
return { values, newIndex: j - 1 };
|
|
1309
|
+
}
|
|
1310
|
+
function parsePipeMetadata(segments, aliasMap = /* @__PURE__ */ new Map()) {
|
|
1311
|
+
const metadata = {};
|
|
1312
|
+
for (let j = 1; j < segments.length; j++) {
|
|
1313
|
+
for (const part of segments[j].split(",")) {
|
|
1314
|
+
const trimmedPart = part.trim();
|
|
1315
|
+
if (!trimmedPart) continue;
|
|
1316
|
+
const colonIdx = trimmedPart.indexOf(":");
|
|
1317
|
+
if (colonIdx > 0) {
|
|
1318
|
+
const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
|
|
1319
|
+
const key = aliasMap.get(rawKey) ?? rawKey;
|
|
1320
|
+
const value = trimmedPart.substring(colonIdx + 1).trim();
|
|
1321
|
+
metadata[key] = value;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
return metadata;
|
|
1326
|
+
}
|
|
1327
|
+
var COLOR_SUFFIX_RE, CHART_TYPE_RE, TITLE_RE, OPTION_RE;
|
|
1328
|
+
var init_parsing = __esm({
|
|
1329
|
+
"src/utils/parsing.ts"() {
|
|
1330
|
+
"use strict";
|
|
1331
|
+
init_colors();
|
|
1332
|
+
COLOR_SUFFIX_RE = /\(([^)]+)\)\s*$/;
|
|
1333
|
+
CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
|
|
1334
|
+
TITLE_RE = /^title\s*:\s*(.+)/i;
|
|
1335
|
+
OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1278
1339
|
// src/sequence/participant-inference.ts
|
|
1279
1340
|
function inferParticipantType(name) {
|
|
1280
1341
|
for (const rule of PARTICIPANT_RULES) {
|
|
@@ -1591,54 +1652,6 @@ var init_arrows = __esm({
|
|
|
1591
1652
|
}
|
|
1592
1653
|
});
|
|
1593
1654
|
|
|
1594
|
-
// src/utils/parsing.ts
|
|
1595
|
-
function measureIndent(line7) {
|
|
1596
|
-
let indent = 0;
|
|
1597
|
-
for (const ch of line7) {
|
|
1598
|
-
if (ch === " ") indent++;
|
|
1599
|
-
else if (ch === " ") indent += 4;
|
|
1600
|
-
else break;
|
|
1601
|
-
}
|
|
1602
|
-
return indent;
|
|
1603
|
-
}
|
|
1604
|
-
function extractColor(label, palette) {
|
|
1605
|
-
const m = label.match(COLOR_SUFFIX_RE);
|
|
1606
|
-
if (!m) return { label };
|
|
1607
|
-
const colorName = m[1].trim();
|
|
1608
|
-
return {
|
|
1609
|
-
label: label.substring(0, m.index).trim(),
|
|
1610
|
-
color: resolveColor(colorName, palette)
|
|
1611
|
-
};
|
|
1612
|
-
}
|
|
1613
|
-
function parsePipeMetadata(segments, aliasMap = /* @__PURE__ */ new Map()) {
|
|
1614
|
-
const metadata = {};
|
|
1615
|
-
for (let j = 1; j < segments.length; j++) {
|
|
1616
|
-
for (const part of segments[j].split(",")) {
|
|
1617
|
-
const trimmedPart = part.trim();
|
|
1618
|
-
if (!trimmedPart) continue;
|
|
1619
|
-
const colonIdx = trimmedPart.indexOf(":");
|
|
1620
|
-
if (colonIdx > 0) {
|
|
1621
|
-
const rawKey = trimmedPart.substring(0, colonIdx).trim().toLowerCase();
|
|
1622
|
-
const key = aliasMap.get(rawKey) ?? rawKey;
|
|
1623
|
-
const value = trimmedPart.substring(colonIdx + 1).trim();
|
|
1624
|
-
metadata[key] = value;
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
return metadata;
|
|
1629
|
-
}
|
|
1630
|
-
var COLOR_SUFFIX_RE, CHART_TYPE_RE, TITLE_RE, OPTION_RE;
|
|
1631
|
-
var init_parsing = __esm({
|
|
1632
|
-
"src/utils/parsing.ts"() {
|
|
1633
|
-
"use strict";
|
|
1634
|
-
init_colors();
|
|
1635
|
-
COLOR_SUFFIX_RE = /\(([^)]+)\)\s*$/;
|
|
1636
|
-
CHART_TYPE_RE = /^chart\s*:\s*(.+)/i;
|
|
1637
|
-
TITLE_RE = /^title\s*:\s*(.+)/i;
|
|
1638
|
-
OPTION_RE = /^([a-z][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
1639
|
-
}
|
|
1640
|
-
});
|
|
1641
|
-
|
|
1642
1655
|
// src/sequence/parser.ts
|
|
1643
1656
|
var parser_exports = {};
|
|
1644
1657
|
__export(parser_exports, {
|
|
@@ -1659,6 +1672,13 @@ function isSequenceNote(el) {
|
|
|
1659
1672
|
}
|
|
1660
1673
|
function parseReturnLabel(rawLabel) {
|
|
1661
1674
|
if (!rawLabel) return { label: "" };
|
|
1675
|
+
const standaloneMatch = rawLabel.match(/^<-\s*(.*)$/);
|
|
1676
|
+
if (standaloneMatch) {
|
|
1677
|
+
return {
|
|
1678
|
+
label: standaloneMatch[1].trim(),
|
|
1679
|
+
standaloneReturn: true
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1662
1682
|
const arrowReturn = rawLabel.match(ARROW_RETURN_PATTERN);
|
|
1663
1683
|
if (arrowReturn) {
|
|
1664
1684
|
return { label: arrowReturn[1].trim(), returnLabel: arrowReturn[2].trim() };
|
|
@@ -1996,14 +2016,15 @@ function parseSequenceDgmo(content) {
|
|
|
1996
2016
|
const to = arrowMatch[2];
|
|
1997
2017
|
lastMsgFrom = from;
|
|
1998
2018
|
const rawLabel = arrowMatch[3]?.trim() || "";
|
|
1999
|
-
const { label, returnLabel } = isAsync ? { label: rawLabel, returnLabel: void 0 } : parseReturnLabel(rawLabel);
|
|
2019
|
+
const { label, returnLabel, standaloneReturn } = isAsync ? { label: rawLabel, returnLabel: void 0, standaloneReturn: void 0 } : parseReturnLabel(rawLabel);
|
|
2000
2020
|
const msg = {
|
|
2001
2021
|
from,
|
|
2002
2022
|
to,
|
|
2003
2023
|
label,
|
|
2004
2024
|
returnLabel,
|
|
2005
2025
|
lineNumber,
|
|
2006
|
-
...isAsync ? { async: true } : {}
|
|
2026
|
+
...isAsync ? { async: true } : {},
|
|
2027
|
+
...standaloneReturn ? { standaloneReturn: true } : {}
|
|
2007
2028
|
};
|
|
2008
2029
|
result.messages.push(msg);
|
|
2009
2030
|
currentContainer().push(msg);
|
|
@@ -3143,8 +3164,16 @@ function parseChart(content, palette) {
|
|
|
3143
3164
|
continue;
|
|
3144
3165
|
}
|
|
3145
3166
|
if (key === "series") {
|
|
3146
|
-
|
|
3147
|
-
|
|
3167
|
+
let rawNames;
|
|
3168
|
+
if (value) {
|
|
3169
|
+
result.series = value;
|
|
3170
|
+
rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
3171
|
+
} else {
|
|
3172
|
+
const collected = collectIndentedValues(lines, i);
|
|
3173
|
+
i = collected.newIndex;
|
|
3174
|
+
rawNames = collected.values;
|
|
3175
|
+
result.series = rawNames.join(", ");
|
|
3176
|
+
}
|
|
3148
3177
|
const names = [];
|
|
3149
3178
|
const nameColors = [];
|
|
3150
3179
|
for (const raw of rawNames) {
|
|
@@ -3223,6 +3252,7 @@ var init_chart = __esm({
|
|
|
3223
3252
|
"use strict";
|
|
3224
3253
|
init_colors();
|
|
3225
3254
|
init_diagnostics();
|
|
3255
|
+
init_parsing();
|
|
3226
3256
|
VALID_TYPES = /* @__PURE__ */ new Set([
|
|
3227
3257
|
"bar",
|
|
3228
3258
|
"line",
|
|
@@ -3298,8 +3328,16 @@ function parseEChart(content, palette) {
|
|
|
3298
3328
|
continue;
|
|
3299
3329
|
}
|
|
3300
3330
|
if (key === "series") {
|
|
3301
|
-
|
|
3302
|
-
|
|
3331
|
+
let rawNames;
|
|
3332
|
+
if (value) {
|
|
3333
|
+
result.series = value;
|
|
3334
|
+
rawNames = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
3335
|
+
} else {
|
|
3336
|
+
const collected = collectIndentedValues(lines, i);
|
|
3337
|
+
i = collected.newIndex;
|
|
3338
|
+
rawNames = collected.values;
|
|
3339
|
+
result.series = rawNames.join(", ");
|
|
3340
|
+
}
|
|
3303
3341
|
const names = [];
|
|
3304
3342
|
const nameColors = [];
|
|
3305
3343
|
for (const raw of rawNames) {
|
|
@@ -3335,11 +3373,23 @@ function parseEChart(content, palette) {
|
|
|
3335
3373
|
continue;
|
|
3336
3374
|
}
|
|
3337
3375
|
if (key === "columns") {
|
|
3338
|
-
|
|
3376
|
+
if (value) {
|
|
3377
|
+
result.columns = value.split(",").map((s) => s.trim());
|
|
3378
|
+
} else {
|
|
3379
|
+
const collected = collectIndentedValues(lines, i);
|
|
3380
|
+
i = collected.newIndex;
|
|
3381
|
+
result.columns = collected.values;
|
|
3382
|
+
}
|
|
3339
3383
|
continue;
|
|
3340
3384
|
}
|
|
3341
3385
|
if (key === "rows") {
|
|
3342
|
-
|
|
3386
|
+
if (value) {
|
|
3387
|
+
result.rows = value.split(",").map((s) => s.trim());
|
|
3388
|
+
} else {
|
|
3389
|
+
const collected = collectIndentedValues(lines, i);
|
|
3390
|
+
i = collected.newIndex;
|
|
3391
|
+
result.rows = collected.values;
|
|
3392
|
+
}
|
|
3343
3393
|
continue;
|
|
3344
3394
|
}
|
|
3345
3395
|
if (key === "x") {
|
|
@@ -4167,19 +4217,36 @@ function resolveAxisLabels(parsed) {
|
|
|
4167
4217
|
yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
|
|
4168
4218
|
};
|
|
4169
4219
|
}
|
|
4170
|
-
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride) {
|
|
4220
|
+
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride, chartWidthHint) {
|
|
4171
4221
|
const defaultGap = type === "value" ? 75 : 40;
|
|
4222
|
+
let catFontSize = 16;
|
|
4223
|
+
let catLabelExtras = {};
|
|
4224
|
+
if (type === "category" && data && data.length > 0) {
|
|
4225
|
+
const maxLabelLen = Math.max(...data.map((l) => l.length));
|
|
4226
|
+
const count = data.length;
|
|
4227
|
+
if (count > 10 || maxLabelLen > 20) catFontSize = 10;
|
|
4228
|
+
else if (count > 5 || maxLabelLen > 14) catFontSize = 11;
|
|
4229
|
+
else if (maxLabelLen > 8) catFontSize = 12;
|
|
4230
|
+
if (chartWidthHint && count > 0) {
|
|
4231
|
+
const availPerLabel = Math.floor(chartWidthHint * 0.85 / count);
|
|
4232
|
+
catLabelExtras = {
|
|
4233
|
+
width: availPerLabel,
|
|
4234
|
+
overflow: "break"
|
|
4235
|
+
};
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4172
4238
|
return {
|
|
4173
4239
|
type,
|
|
4174
4240
|
...data && { data },
|
|
4175
4241
|
axisLine: { lineStyle: { color: axisLineColor } },
|
|
4176
4242
|
axisLabel: {
|
|
4177
4243
|
color: textColor,
|
|
4178
|
-
fontSize: type === "category" && data ?
|
|
4244
|
+
fontSize: type === "category" && data ? catFontSize : 16,
|
|
4179
4245
|
fontFamily: FONT_FAMILY,
|
|
4180
4246
|
...type === "category" && {
|
|
4181
4247
|
interval: 0,
|
|
4182
|
-
formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2")
|
|
4248
|
+
formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2"),
|
|
4249
|
+
...catLabelExtras
|
|
4183
4250
|
}
|
|
4184
4251
|
},
|
|
4185
4252
|
splitLine: { lineStyle: { color: splitLineColor, opacity: gridOpacity } },
|
|
@@ -4191,7 +4258,7 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
|
|
|
4191
4258
|
}
|
|
4192
4259
|
};
|
|
4193
4260
|
}
|
|
4194
|
-
function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
4261
|
+
function buildEChartsOptionFromChart(parsed, palette, isDark, chartWidth) {
|
|
4195
4262
|
if (parsed.error) return {};
|
|
4196
4263
|
const textColor = palette.text;
|
|
4197
4264
|
const axisLineColor = palette.border;
|
|
@@ -4216,13 +4283,13 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
|
4216
4283
|
};
|
|
4217
4284
|
switch (parsed.type) {
|
|
4218
4285
|
case "bar":
|
|
4219
|
-
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
|
|
4286
|
+
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4220
4287
|
case "bar-stacked":
|
|
4221
|
-
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
|
|
4288
|
+
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4222
4289
|
case "line":
|
|
4223
|
-
return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4290
|
+
return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4224
4291
|
case "area":
|
|
4225
|
-
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4292
|
+
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4226
4293
|
case "pie":
|
|
4227
4294
|
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, false);
|
|
4228
4295
|
case "doughnut":
|
|
@@ -4233,7 +4300,7 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
|
4233
4300
|
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme);
|
|
4234
4301
|
}
|
|
4235
4302
|
}
|
|
4236
|
-
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4303
|
+
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4237
4304
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4238
4305
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4239
4306
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4242,7 +4309,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4242
4309
|
itemStyle: { color: d.color ?? colors[i % colors.length] }
|
|
4243
4310
|
}));
|
|
4244
4311
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4245
|
-
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4312
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4246
4313
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
4247
4314
|
return {
|
|
4248
4315
|
backgroundColor: "transparent",
|
|
@@ -4274,7 +4341,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4274
4341
|
]
|
|
4275
4342
|
};
|
|
4276
4343
|
}
|
|
4277
|
-
function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
4344
|
+
function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
|
|
4278
4345
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4279
4346
|
const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
4280
4347
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4295,7 +4362,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4295
4362
|
top: parsed.title ? "15%" : "5%",
|
|
4296
4363
|
containLabel: true
|
|
4297
4364
|
},
|
|
4298
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4365
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4299
4366
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4300
4367
|
series: [
|
|
4301
4368
|
{
|
|
@@ -4313,7 +4380,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4313
4380
|
]
|
|
4314
4381
|
};
|
|
4315
4382
|
}
|
|
4316
|
-
function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4383
|
+
function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4317
4384
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4318
4385
|
const seriesNames = parsed.seriesNames ?? [];
|
|
4319
4386
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4357,12 +4424,12 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4357
4424
|
top: parsed.title ? "15%" : "5%",
|
|
4358
4425
|
containLabel: true
|
|
4359
4426
|
},
|
|
4360
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4427
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4361
4428
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4362
4429
|
series
|
|
4363
4430
|
};
|
|
4364
4431
|
}
|
|
4365
|
-
function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
4432
|
+
function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
|
|
4366
4433
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4367
4434
|
const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
4368
4435
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4383,7 +4450,7 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4383
4450
|
top: parsed.title ? "15%" : "5%",
|
|
4384
4451
|
containLabel: true
|
|
4385
4452
|
},
|
|
4386
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4453
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4387
4454
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4388
4455
|
series: [
|
|
4389
4456
|
{
|
|
@@ -4543,7 +4610,7 @@ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipThe
|
|
|
4543
4610
|
]
|
|
4544
4611
|
};
|
|
4545
4612
|
}
|
|
4546
|
-
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4613
|
+
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4547
4614
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4548
4615
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4549
4616
|
const seriesNames = parsed.seriesNames ?? [];
|
|
@@ -4575,8 +4642,9 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4575
4642
|
};
|
|
4576
4643
|
});
|
|
4577
4644
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4578
|
-
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4579
|
-
const
|
|
4645
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4646
|
+
const hValueGap = isHorizontal && xLabel ? 40 : void 0;
|
|
4647
|
+
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel, void 0, hValueGap);
|
|
4580
4648
|
return {
|
|
4581
4649
|
backgroundColor: "transparent",
|
|
4582
4650
|
animation: false,
|
|
@@ -4613,7 +4681,7 @@ async function renderEChartsForExport(content, theme, palette, options) {
|
|
|
4613
4681
|
if (chartType && STANDARD_CHART_TYPES.has(chartType)) {
|
|
4614
4682
|
const parsed = parseChart(content, effectivePalette);
|
|
4615
4683
|
if (parsed.error) return "";
|
|
4616
|
-
option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark);
|
|
4684
|
+
option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark, ECHART_EXPORT_WIDTH);
|
|
4617
4685
|
} else {
|
|
4618
4686
|
const parsed = parseEChart(content, effectivePalette);
|
|
4619
4687
|
if (parsed.error) return "";
|
|
@@ -4655,6 +4723,7 @@ var init_echarts = __esm({
|
|
|
4655
4723
|
init_palettes();
|
|
4656
4724
|
init_chart();
|
|
4657
4725
|
init_diagnostics();
|
|
4726
|
+
init_parsing();
|
|
4658
4727
|
ECHART_EXPORT_WIDTH = 1200;
|
|
4659
4728
|
ECHART_EXPORT_HEIGHT = 800;
|
|
4660
4729
|
STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -12140,6 +12209,22 @@ function buildRenderSequence(messages) {
|
|
|
12140
12209
|
messageIndex: top.messageIndex
|
|
12141
12210
|
});
|
|
12142
12211
|
}
|
|
12212
|
+
if (msg.standaloneReturn) {
|
|
12213
|
+
for (let si = stack.length - 1; si >= 0; si--) {
|
|
12214
|
+
if (stack[si].from === msg.to && stack[si].to === msg.from) {
|
|
12215
|
+
stack.splice(si, 1);
|
|
12216
|
+
break;
|
|
12217
|
+
}
|
|
12218
|
+
}
|
|
12219
|
+
steps.push({
|
|
12220
|
+
type: "return",
|
|
12221
|
+
from: msg.from,
|
|
12222
|
+
to: msg.to,
|
|
12223
|
+
label: msg.label,
|
|
12224
|
+
messageIndex: mi
|
|
12225
|
+
});
|
|
12226
|
+
continue;
|
|
12227
|
+
}
|
|
12143
12228
|
steps.push({
|
|
12144
12229
|
type: "call",
|
|
12145
12230
|
from: msg.from,
|
|
@@ -13421,18 +13506,34 @@ function parseD3(content, palette) {
|
|
|
13421
13506
|
}
|
|
13422
13507
|
}
|
|
13423
13508
|
if (result.type === "quadrant") {
|
|
13424
|
-
const xAxisMatch = line7.match(/^x-axis\s*:\s*(
|
|
13509
|
+
const xAxisMatch = line7.match(/^x-axis\s*:\s*(.*)/i);
|
|
13425
13510
|
if (xAxisMatch) {
|
|
13426
|
-
const
|
|
13511
|
+
const val = xAxisMatch[1].trim();
|
|
13512
|
+
let parts;
|
|
13513
|
+
if (val) {
|
|
13514
|
+
parts = val.split(",").map((s) => s.trim());
|
|
13515
|
+
} else {
|
|
13516
|
+
const collected = collectIndentedValues(lines, i);
|
|
13517
|
+
i = collected.newIndex;
|
|
13518
|
+
parts = collected.values;
|
|
13519
|
+
}
|
|
13427
13520
|
if (parts.length >= 2) {
|
|
13428
13521
|
result.quadrantXAxis = [parts[0], parts[1]];
|
|
13429
13522
|
result.quadrantXAxisLineNumber = lineNumber;
|
|
13430
13523
|
}
|
|
13431
13524
|
continue;
|
|
13432
13525
|
}
|
|
13433
|
-
const yAxisMatch = line7.match(/^y-axis\s*:\s*(
|
|
13526
|
+
const yAxisMatch = line7.match(/^y-axis\s*:\s*(.*)/i);
|
|
13434
13527
|
if (yAxisMatch) {
|
|
13435
|
-
const
|
|
13528
|
+
const val = yAxisMatch[1].trim();
|
|
13529
|
+
let parts;
|
|
13530
|
+
if (val) {
|
|
13531
|
+
parts = val.split(",").map((s) => s.trim());
|
|
13532
|
+
} else {
|
|
13533
|
+
const collected = collectIndentedValues(lines, i);
|
|
13534
|
+
i = collected.newIndex;
|
|
13535
|
+
parts = collected.values;
|
|
13536
|
+
}
|
|
13436
13537
|
if (parts.length >= 2) {
|
|
13437
13538
|
result.quadrantYAxis = [parts[0], parts[1]];
|
|
13438
13539
|
result.quadrantYAxisLineNumber = lineNumber;
|
|
@@ -13714,6 +13815,19 @@ function tokenizeFreeformText(text) {
|
|
|
13714
13815
|
}
|
|
13715
13816
|
return Array.from(counts.entries()).map(([text2, count]) => ({ text: text2, weight: count, lineNumber: 0 })).sort((a, b) => b.weight - a.weight);
|
|
13716
13817
|
}
|
|
13818
|
+
function resolveVerticalCollisions(items, minGap) {
|
|
13819
|
+
if (items.length === 0) return [];
|
|
13820
|
+
const sorted = items.map((it, i) => ({ ...it, idx: i })).sort((a, b) => a.naturalY - b.naturalY);
|
|
13821
|
+
const adjustedY = new Array(items.length);
|
|
13822
|
+
let prevBottom = -Infinity;
|
|
13823
|
+
for (const item of sorted) {
|
|
13824
|
+
const halfH = item.height / 2;
|
|
13825
|
+
const top = Math.max(item.naturalY - halfH, prevBottom + minGap);
|
|
13826
|
+
adjustedY[item.idx] = top + halfH;
|
|
13827
|
+
prevBottom = top + item.height;
|
|
13828
|
+
}
|
|
13829
|
+
return adjustedY;
|
|
13830
|
+
}
|
|
13717
13831
|
function renderSlopeChart(container, parsed, palette, isDark, onClickItem, exportDims) {
|
|
13718
13832
|
d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
13719
13833
|
const { periods, data, title } = parsed;
|
|
@@ -13764,25 +13878,80 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
|
|
|
13764
13878
|
g.append("line").attr("x1", x).attr("y1", 0).attr("x2", x).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
|
|
13765
13879
|
}
|
|
13766
13880
|
const lineGen = d3Shape6.line().x((_d, i) => xScale(periods[i])).y((d) => yScale(d));
|
|
13767
|
-
data.
|
|
13881
|
+
const seriesInfo = data.map((item, idx) => {
|
|
13768
13882
|
const color = item.color ?? colors[idx % colors.length];
|
|
13769
|
-
const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
|
|
13770
13883
|
const firstVal = item.values[0];
|
|
13771
13884
|
const lastVal = item.values[item.values.length - 1];
|
|
13772
13885
|
const absChange = lastVal - firstVal;
|
|
13773
13886
|
const pctChange = firstVal !== 0 ? absChange / firstVal * 100 : null;
|
|
13774
13887
|
const sign = absChange > 0 ? "+" : "";
|
|
13775
|
-
const
|
|
13776
|
-
const tipLines = [`${sign}${absChange}`];
|
|
13888
|
+
const tipLines = [`${sign}${parseFloat(absChange.toFixed(2))}`];
|
|
13777
13889
|
if (pctChange !== null) tipLines.push(`${sign}${pctChange.toFixed(1)}%`);
|
|
13778
13890
|
const tipHtml = tipLines.join("<br>");
|
|
13891
|
+
const lastX = xScale(periods[periods.length - 1]);
|
|
13892
|
+
const labelText = `${lastVal} \u2014 ${item.label}`;
|
|
13893
|
+
const availableWidth = rightMargin - 15;
|
|
13894
|
+
const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
|
|
13895
|
+
let labelLineCount = 1;
|
|
13896
|
+
let wrappedLines = null;
|
|
13897
|
+
if (labelText.length > maxChars) {
|
|
13898
|
+
const words = labelText.split(/\s+/);
|
|
13899
|
+
const lines = [];
|
|
13900
|
+
let current = "";
|
|
13901
|
+
for (const word of words) {
|
|
13902
|
+
const test = current ? `${current} ${word}` : word;
|
|
13903
|
+
if (test.length > maxChars && current) {
|
|
13904
|
+
lines.push(current);
|
|
13905
|
+
current = word;
|
|
13906
|
+
} else {
|
|
13907
|
+
current = test;
|
|
13908
|
+
}
|
|
13909
|
+
}
|
|
13910
|
+
if (current) lines.push(current);
|
|
13911
|
+
labelLineCount = lines.length;
|
|
13912
|
+
wrappedLines = lines;
|
|
13913
|
+
}
|
|
13914
|
+
const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
|
|
13915
|
+
const labelHeight = labelLineCount === 1 ? SLOPE_LABEL_FONT_SIZE : labelLineCount * lineHeight;
|
|
13916
|
+
return {
|
|
13917
|
+
item,
|
|
13918
|
+
idx,
|
|
13919
|
+
color,
|
|
13920
|
+
firstVal,
|
|
13921
|
+
lastVal,
|
|
13922
|
+
tipHtml,
|
|
13923
|
+
lastX,
|
|
13924
|
+
labelText,
|
|
13925
|
+
maxChars,
|
|
13926
|
+
wrappedLines,
|
|
13927
|
+
labelHeight
|
|
13928
|
+
};
|
|
13929
|
+
});
|
|
13930
|
+
const leftLabelHeight = 20;
|
|
13931
|
+
const leftLabelCollisions = /* @__PURE__ */ new Map();
|
|
13932
|
+
for (let pi = 0; pi < periods.length - 1; pi++) {
|
|
13933
|
+
const entries = data.map((item) => ({
|
|
13934
|
+
naturalY: yScale(item.values[pi]),
|
|
13935
|
+
height: leftLabelHeight
|
|
13936
|
+
}));
|
|
13937
|
+
leftLabelCollisions.set(pi, resolveVerticalCollisions(entries, 4));
|
|
13938
|
+
}
|
|
13939
|
+
const rightEntries = seriesInfo.map((si) => ({
|
|
13940
|
+
naturalY: yScale(si.lastVal),
|
|
13941
|
+
height: Math.max(si.labelHeight, SLOPE_LABEL_FONT_SIZE * 1.4)
|
|
13942
|
+
}));
|
|
13943
|
+
const rightAdjustedY = resolveVerticalCollisions(rightEntries, 4);
|
|
13944
|
+
data.forEach((item, idx) => {
|
|
13945
|
+
const si = seriesInfo[idx];
|
|
13946
|
+
const color = si.color;
|
|
13947
|
+
const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
|
|
13779
13948
|
seriesG.append("path").datum(item.values).attr("fill", "none").attr("stroke", color).attr("stroke-width", 2.5).attr("d", lineGen);
|
|
13780
13949
|
seriesG.append("path").datum(item.values).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 14).attr("d", lineGen).style("cursor", onClickItem ? "pointer" : "default").on(
|
|
13781
13950
|
"mouseenter",
|
|
13782
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13951
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13783
13952
|
).on(
|
|
13784
13953
|
"mousemove",
|
|
13785
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13954
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13786
13955
|
).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
|
|
13787
13956
|
if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
|
|
13788
13957
|
});
|
|
@@ -13791,46 +13960,30 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
|
|
|
13791
13960
|
const y = yScale(val);
|
|
13792
13961
|
seriesG.append("circle").attr("cx", x).attr("cy", y).attr("r", 4).attr("fill", color).attr("stroke", bgColor).attr("stroke-width", 1.5).style("cursor", onClickItem ? "pointer" : "default").on(
|
|
13793
13962
|
"mouseenter",
|
|
13794
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13963
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13795
13964
|
).on(
|
|
13796
13965
|
"mousemove",
|
|
13797
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13966
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13798
13967
|
).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
|
|
13799
13968
|
if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
|
|
13800
13969
|
});
|
|
13801
13970
|
const isFirst = i === 0;
|
|
13802
13971
|
const isLast = i === periods.length - 1;
|
|
13803
13972
|
if (!isLast) {
|
|
13804
|
-
|
|
13973
|
+
const adjustedY = leftLabelCollisions.get(i)[idx];
|
|
13974
|
+
seriesG.append("text").attr("x", isFirst ? x - 10 : x).attr("y", adjustedY).attr("dy", "0.35em").attr("text-anchor", isFirst ? "end" : "middle").attr("fill", color).attr("font-size", "16px").text(val.toString());
|
|
13805
13975
|
}
|
|
13806
13976
|
});
|
|
13807
|
-
const
|
|
13808
|
-
const
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
|
|
13812
|
-
const labelEl = seriesG.append("text").attr("x", lastX + 10).attr("y", lastY).attr("text-anchor", "start").attr("fill", color).attr("font-size", `${SLOPE_LABEL_FONT_SIZE}px`).attr("font-weight", "500");
|
|
13813
|
-
if (labelText.length <= maxChars) {
|
|
13814
|
-
labelEl.attr("dy", "0.35em").text(labelText);
|
|
13977
|
+
const adjustedLastY = rightAdjustedY[idx];
|
|
13978
|
+
const labelEl = seriesG.append("text").attr("x", si.lastX + 10).attr("y", adjustedLastY).attr("text-anchor", "start").attr("fill", color).attr("font-size", `${SLOPE_LABEL_FONT_SIZE}px`).attr("font-weight", "500");
|
|
13979
|
+
if (!si.wrappedLines) {
|
|
13980
|
+
labelEl.attr("dy", "0.35em").text(si.labelText);
|
|
13815
13981
|
} else {
|
|
13816
|
-
const words = labelText.split(/\s+/);
|
|
13817
|
-
const lines = [];
|
|
13818
|
-
let current = "";
|
|
13819
|
-
for (const word of words) {
|
|
13820
|
-
const test = current ? `${current} ${word}` : word;
|
|
13821
|
-
if (test.length > maxChars && current) {
|
|
13822
|
-
lines.push(current);
|
|
13823
|
-
current = word;
|
|
13824
|
-
} else {
|
|
13825
|
-
current = test;
|
|
13826
|
-
}
|
|
13827
|
-
}
|
|
13828
|
-
if (current) lines.push(current);
|
|
13829
13982
|
const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
|
|
13830
|
-
const totalHeight = (
|
|
13983
|
+
const totalHeight = (si.wrappedLines.length - 1) * lineHeight;
|
|
13831
13984
|
const startDy = -totalHeight / 2;
|
|
13832
|
-
|
|
13833
|
-
labelEl.append("tspan").attr("x", lastX + 10).attr(
|
|
13985
|
+
si.wrappedLines.forEach((line7, li) => {
|
|
13986
|
+
labelEl.append("tspan").attr("x", si.lastX + 10).attr(
|
|
13834
13987
|
"dy",
|
|
13835
13988
|
li === 0 ? `${startDy + SLOPE_LABEL_FONT_SIZE * 0.35}px` : `${lineHeight}px`
|
|
13836
13989
|
).text(line7);
|
|
@@ -16248,6 +16401,7 @@ var init_d3 = __esm({
|
|
|
16248
16401
|
init_colors();
|
|
16249
16402
|
init_palettes();
|
|
16250
16403
|
init_diagnostics();
|
|
16404
|
+
init_parsing();
|
|
16251
16405
|
DEFAULT_CLOUD_OPTIONS = {
|
|
16252
16406
|
rotate: "none",
|
|
16253
16407
|
max: 0,
|