@diagrammo/dgmo 0.3.1 → 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/dist/cli.cjs +134 -135
- package/dist/index.cjs +123 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +123 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/d3.ts +106 -46
- package/src/echarts.ts +54 -21
package/dist/index.d.cts
CHANGED
|
@@ -334,7 +334,7 @@ declare function buildEChartsOption(parsed: ParsedEChart, palette: PaletteColors
|
|
|
334
334
|
* Converts a ParsedChart into an EChartsOption.
|
|
335
335
|
* Renders standard chart types (bar, line, pie, etc.) with ECharts.
|
|
336
336
|
*/
|
|
337
|
-
declare function buildEChartsOptionFromChart(parsed: ParsedChart, palette: PaletteColors, isDark: boolean): EChartsOption;
|
|
337
|
+
declare function buildEChartsOptionFromChart(parsed: ParsedChart, palette: PaletteColors, isDark: boolean, chartWidth?: number): EChartsOption;
|
|
338
338
|
/**
|
|
339
339
|
* Renders an ECharts diagram to SVG using server-side rendering.
|
|
340
340
|
* Mirrors the `renderD3ForExport` API — returns an SVG string or empty string on failure.
|
package/dist/index.d.ts
CHANGED
|
@@ -334,7 +334,7 @@ declare function buildEChartsOption(parsed: ParsedEChart, palette: PaletteColors
|
|
|
334
334
|
* Converts a ParsedChart into an EChartsOption.
|
|
335
335
|
* Renders standard chart types (bar, line, pie, etc.) with ECharts.
|
|
336
336
|
*/
|
|
337
|
-
declare function buildEChartsOptionFromChart(parsed: ParsedChart, palette: PaletteColors, isDark: boolean): EChartsOption;
|
|
337
|
+
declare function buildEChartsOptionFromChart(parsed: ParsedChart, palette: PaletteColors, isDark: boolean, chartWidth?: number): EChartsOption;
|
|
338
338
|
/**
|
|
339
339
|
* Renders an ECharts diagram to SVG using server-side rendering.
|
|
340
340
|
* Mirrors the `renderD3ForExport` API — returns an SVG string or empty string on failure.
|
package/dist/index.js
CHANGED
|
@@ -4196,19 +4196,36 @@ function resolveAxisLabels(parsed) {
|
|
|
4196
4196
|
yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
|
|
4197
4197
|
};
|
|
4198
4198
|
}
|
|
4199
|
-
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride) {
|
|
4199
|
+
function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride, chartWidthHint) {
|
|
4200
4200
|
const defaultGap = type === "value" ? 75 : 40;
|
|
4201
|
+
let catFontSize = 16;
|
|
4202
|
+
let catLabelExtras = {};
|
|
4203
|
+
if (type === "category" && data && data.length > 0) {
|
|
4204
|
+
const maxLabelLen = Math.max(...data.map((l) => l.length));
|
|
4205
|
+
const count = data.length;
|
|
4206
|
+
if (count > 10 || maxLabelLen > 20) catFontSize = 10;
|
|
4207
|
+
else if (count > 5 || maxLabelLen > 14) catFontSize = 11;
|
|
4208
|
+
else if (maxLabelLen > 8) catFontSize = 12;
|
|
4209
|
+
if (chartWidthHint && count > 0) {
|
|
4210
|
+
const availPerLabel = Math.floor(chartWidthHint * 0.85 / count);
|
|
4211
|
+
catLabelExtras = {
|
|
4212
|
+
width: availPerLabel,
|
|
4213
|
+
overflow: "break"
|
|
4214
|
+
};
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4201
4217
|
return {
|
|
4202
4218
|
type,
|
|
4203
4219
|
...data && { data },
|
|
4204
4220
|
axisLine: { lineStyle: { color: axisLineColor } },
|
|
4205
4221
|
axisLabel: {
|
|
4206
4222
|
color: textColor,
|
|
4207
|
-
fontSize: type === "category" && data ?
|
|
4223
|
+
fontSize: type === "category" && data ? catFontSize : 16,
|
|
4208
4224
|
fontFamily: FONT_FAMILY,
|
|
4209
4225
|
...type === "category" && {
|
|
4210
4226
|
interval: 0,
|
|
4211
|
-
formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2")
|
|
4227
|
+
formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2"),
|
|
4228
|
+
...catLabelExtras
|
|
4212
4229
|
}
|
|
4213
4230
|
},
|
|
4214
4231
|
splitLine: { lineStyle: { color: splitLineColor, opacity: gridOpacity } },
|
|
@@ -4220,7 +4237,7 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
|
|
|
4220
4237
|
}
|
|
4221
4238
|
};
|
|
4222
4239
|
}
|
|
4223
|
-
function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
4240
|
+
function buildEChartsOptionFromChart(parsed, palette, isDark, chartWidth) {
|
|
4224
4241
|
if (parsed.error) return {};
|
|
4225
4242
|
const textColor = palette.text;
|
|
4226
4243
|
const axisLineColor = palette.border;
|
|
@@ -4245,13 +4262,13 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
|
4245
4262
|
};
|
|
4246
4263
|
switch (parsed.type) {
|
|
4247
4264
|
case "bar":
|
|
4248
|
-
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
|
|
4265
|
+
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4249
4266
|
case "bar-stacked":
|
|
4250
|
-
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme);
|
|
4267
|
+
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4251
4268
|
case "line":
|
|
4252
|
-
return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4269
|
+
return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4253
4270
|
case "area":
|
|
4254
|
-
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4271
|
+
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4255
4272
|
case "pie":
|
|
4256
4273
|
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, false);
|
|
4257
4274
|
case "doughnut":
|
|
@@ -4262,7 +4279,7 @@ function buildEChartsOptionFromChart(parsed, palette, isDark) {
|
|
|
4262
4279
|
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme);
|
|
4263
4280
|
}
|
|
4264
4281
|
}
|
|
4265
|
-
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4282
|
+
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4266
4283
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4267
4284
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4268
4285
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4271,7 +4288,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4271
4288
|
itemStyle: { color: d.color ?? colors[i % colors.length] }
|
|
4272
4289
|
}));
|
|
4273
4290
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4274
|
-
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4291
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4275
4292
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
4276
4293
|
return {
|
|
4277
4294
|
backgroundColor: "transparent",
|
|
@@ -4303,7 +4320,7 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
|
|
|
4303
4320
|
]
|
|
4304
4321
|
};
|
|
4305
4322
|
}
|
|
4306
|
-
function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
4323
|
+
function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
|
|
4307
4324
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4308
4325
|
const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
4309
4326
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4324,7 +4341,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4324
4341
|
top: parsed.title ? "15%" : "5%",
|
|
4325
4342
|
containLabel: true
|
|
4326
4343
|
},
|
|
4327
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4344
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4328
4345
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4329
4346
|
series: [
|
|
4330
4347
|
{
|
|
@@ -4342,7 +4359,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4342
4359
|
]
|
|
4343
4360
|
};
|
|
4344
4361
|
}
|
|
4345
|
-
function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4362
|
+
function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4346
4363
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4347
4364
|
const seriesNames = parsed.seriesNames ?? [];
|
|
4348
4365
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4386,12 +4403,12 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4386
4403
|
top: parsed.title ? "15%" : "5%",
|
|
4387
4404
|
containLabel: true
|
|
4388
4405
|
},
|
|
4389
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4406
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4390
4407
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4391
4408
|
series
|
|
4392
4409
|
};
|
|
4393
4410
|
}
|
|
4394
|
-
function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
4411
|
+
function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
|
|
4395
4412
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4396
4413
|
const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
4397
4414
|
const labels = parsed.data.map((d) => d.label);
|
|
@@ -4412,7 +4429,7 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
|
|
|
4412
4429
|
top: parsed.title ? "15%" : "5%",
|
|
4413
4430
|
containLabel: true
|
|
4414
4431
|
},
|
|
4415
|
-
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels),
|
|
4432
|
+
xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
|
|
4416
4433
|
yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
|
|
4417
4434
|
series: [
|
|
4418
4435
|
{
|
|
@@ -4572,7 +4589,7 @@ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipThe
|
|
|
4572
4589
|
]
|
|
4573
4590
|
};
|
|
4574
4591
|
}
|
|
4575
|
-
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4592
|
+
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4576
4593
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4577
4594
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4578
4595
|
const seriesNames = parsed.seriesNames ?? [];
|
|
@@ -4604,8 +4621,9 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
4604
4621
|
};
|
|
4605
4622
|
});
|
|
4606
4623
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4607
|
-
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap);
|
|
4608
|
-
const
|
|
4624
|
+
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4625
|
+
const hValueGap = isHorizontal && xLabel ? 40 : void 0;
|
|
4626
|
+
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel, void 0, hValueGap);
|
|
4609
4627
|
return {
|
|
4610
4628
|
backgroundColor: "transparent",
|
|
4611
4629
|
animation: false,
|
|
@@ -4642,7 +4660,7 @@ async function renderEChartsForExport(content, theme, palette, options) {
|
|
|
4642
4660
|
if (chartType && STANDARD_CHART_TYPES.has(chartType)) {
|
|
4643
4661
|
const parsed = parseChart(content, effectivePalette);
|
|
4644
4662
|
if (parsed.error) return "";
|
|
4645
|
-
option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark);
|
|
4663
|
+
option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark, ECHART_EXPORT_WIDTH);
|
|
4646
4664
|
} else {
|
|
4647
4665
|
const parsed = parseEChart(content, effectivePalette);
|
|
4648
4666
|
if (parsed.error) return "";
|
|
@@ -13780,6 +13798,19 @@ function tokenizeFreeformText(text) {
|
|
|
13780
13798
|
}
|
|
13781
13799
|
return Array.from(counts.entries()).map(([text2, count]) => ({ text: text2, weight: count, lineNumber: 0 })).sort((a, b) => b.weight - a.weight);
|
|
13782
13800
|
}
|
|
13801
|
+
function resolveVerticalCollisions(items, minGap) {
|
|
13802
|
+
if (items.length === 0) return [];
|
|
13803
|
+
const sorted = items.map((it, i) => ({ ...it, idx: i })).sort((a, b) => a.naturalY - b.naturalY);
|
|
13804
|
+
const adjustedY = new Array(items.length);
|
|
13805
|
+
let prevBottom = -Infinity;
|
|
13806
|
+
for (const item of sorted) {
|
|
13807
|
+
const halfH = item.height / 2;
|
|
13808
|
+
const top = Math.max(item.naturalY - halfH, prevBottom + minGap);
|
|
13809
|
+
adjustedY[item.idx] = top + halfH;
|
|
13810
|
+
prevBottom = top + item.height;
|
|
13811
|
+
}
|
|
13812
|
+
return adjustedY;
|
|
13813
|
+
}
|
|
13783
13814
|
function renderSlopeChart(container, parsed, palette, isDark, onClickItem, exportDims) {
|
|
13784
13815
|
d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
13785
13816
|
const { periods, data, title } = parsed;
|
|
@@ -13830,25 +13861,80 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
|
|
|
13830
13861
|
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");
|
|
13831
13862
|
}
|
|
13832
13863
|
const lineGen = d3Shape6.line().x((_d, i) => xScale(periods[i])).y((d) => yScale(d));
|
|
13833
|
-
data.
|
|
13864
|
+
const seriesInfo = data.map((item, idx) => {
|
|
13834
13865
|
const color = item.color ?? colors[idx % colors.length];
|
|
13835
|
-
const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
|
|
13836
13866
|
const firstVal = item.values[0];
|
|
13837
13867
|
const lastVal = item.values[item.values.length - 1];
|
|
13838
13868
|
const absChange = lastVal - firstVal;
|
|
13839
13869
|
const pctChange = firstVal !== 0 ? absChange / firstVal * 100 : null;
|
|
13840
13870
|
const sign = absChange > 0 ? "+" : "";
|
|
13841
|
-
const
|
|
13842
|
-
const tipLines = [`${sign}${absChange}`];
|
|
13871
|
+
const tipLines = [`${sign}${parseFloat(absChange.toFixed(2))}`];
|
|
13843
13872
|
if (pctChange !== null) tipLines.push(`${sign}${pctChange.toFixed(1)}%`);
|
|
13844
13873
|
const tipHtml = tipLines.join("<br>");
|
|
13874
|
+
const lastX = xScale(periods[periods.length - 1]);
|
|
13875
|
+
const labelText = `${lastVal} \u2014 ${item.label}`;
|
|
13876
|
+
const availableWidth = rightMargin - 15;
|
|
13877
|
+
const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
|
|
13878
|
+
let labelLineCount = 1;
|
|
13879
|
+
let wrappedLines = null;
|
|
13880
|
+
if (labelText.length > maxChars) {
|
|
13881
|
+
const words = labelText.split(/\s+/);
|
|
13882
|
+
const lines = [];
|
|
13883
|
+
let current = "";
|
|
13884
|
+
for (const word of words) {
|
|
13885
|
+
const test = current ? `${current} ${word}` : word;
|
|
13886
|
+
if (test.length > maxChars && current) {
|
|
13887
|
+
lines.push(current);
|
|
13888
|
+
current = word;
|
|
13889
|
+
} else {
|
|
13890
|
+
current = test;
|
|
13891
|
+
}
|
|
13892
|
+
}
|
|
13893
|
+
if (current) lines.push(current);
|
|
13894
|
+
labelLineCount = lines.length;
|
|
13895
|
+
wrappedLines = lines;
|
|
13896
|
+
}
|
|
13897
|
+
const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
|
|
13898
|
+
const labelHeight = labelLineCount === 1 ? SLOPE_LABEL_FONT_SIZE : labelLineCount * lineHeight;
|
|
13899
|
+
return {
|
|
13900
|
+
item,
|
|
13901
|
+
idx,
|
|
13902
|
+
color,
|
|
13903
|
+
firstVal,
|
|
13904
|
+
lastVal,
|
|
13905
|
+
tipHtml,
|
|
13906
|
+
lastX,
|
|
13907
|
+
labelText,
|
|
13908
|
+
maxChars,
|
|
13909
|
+
wrappedLines,
|
|
13910
|
+
labelHeight
|
|
13911
|
+
};
|
|
13912
|
+
});
|
|
13913
|
+
const leftLabelHeight = 20;
|
|
13914
|
+
const leftLabelCollisions = /* @__PURE__ */ new Map();
|
|
13915
|
+
for (let pi = 0; pi < periods.length - 1; pi++) {
|
|
13916
|
+
const entries = data.map((item) => ({
|
|
13917
|
+
naturalY: yScale(item.values[pi]),
|
|
13918
|
+
height: leftLabelHeight
|
|
13919
|
+
}));
|
|
13920
|
+
leftLabelCollisions.set(pi, resolveVerticalCollisions(entries, 4));
|
|
13921
|
+
}
|
|
13922
|
+
const rightEntries = seriesInfo.map((si) => ({
|
|
13923
|
+
naturalY: yScale(si.lastVal),
|
|
13924
|
+
height: Math.max(si.labelHeight, SLOPE_LABEL_FONT_SIZE * 1.4)
|
|
13925
|
+
}));
|
|
13926
|
+
const rightAdjustedY = resolveVerticalCollisions(rightEntries, 4);
|
|
13927
|
+
data.forEach((item, idx) => {
|
|
13928
|
+
const si = seriesInfo[idx];
|
|
13929
|
+
const color = si.color;
|
|
13930
|
+
const seriesG = g.append("g").attr("class", "slope-series").attr("data-line-number", String(item.lineNumber));
|
|
13845
13931
|
seriesG.append("path").datum(item.values).attr("fill", "none").attr("stroke", color).attr("stroke-width", 2.5).attr("d", lineGen);
|
|
13846
13932
|
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(
|
|
13847
13933
|
"mouseenter",
|
|
13848
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13934
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13849
13935
|
).on(
|
|
13850
13936
|
"mousemove",
|
|
13851
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13937
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13852
13938
|
).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
|
|
13853
13939
|
if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
|
|
13854
13940
|
});
|
|
@@ -13857,46 +13943,30 @@ function renderSlopeChart(container, parsed, palette, isDark, onClickItem, expor
|
|
|
13857
13943
|
const y = yScale(val);
|
|
13858
13944
|
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(
|
|
13859
13945
|
"mouseenter",
|
|
13860
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13946
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13861
13947
|
).on(
|
|
13862
13948
|
"mousemove",
|
|
13863
|
-
(event) => showTooltip(tooltip, tipHtml, event)
|
|
13949
|
+
(event) => showTooltip(tooltip, si.tipHtml, event)
|
|
13864
13950
|
).on("mouseleave", () => hideTooltip(tooltip)).on("click", () => {
|
|
13865
13951
|
if (onClickItem && item.lineNumber) onClickItem(item.lineNumber);
|
|
13866
13952
|
});
|
|
13867
13953
|
const isFirst = i === 0;
|
|
13868
13954
|
const isLast = i === periods.length - 1;
|
|
13869
13955
|
if (!isLast) {
|
|
13870
|
-
|
|
13956
|
+
const adjustedY = leftLabelCollisions.get(i)[idx];
|
|
13957
|
+
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());
|
|
13871
13958
|
}
|
|
13872
13959
|
});
|
|
13873
|
-
const
|
|
13874
|
-
const
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
const maxChars = Math.floor(availableWidth / SLOPE_CHAR_WIDTH);
|
|
13878
|
-
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");
|
|
13879
|
-
if (labelText.length <= maxChars) {
|
|
13880
|
-
labelEl.attr("dy", "0.35em").text(labelText);
|
|
13960
|
+
const adjustedLastY = rightAdjustedY[idx];
|
|
13961
|
+
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");
|
|
13962
|
+
if (!si.wrappedLines) {
|
|
13963
|
+
labelEl.attr("dy", "0.35em").text(si.labelText);
|
|
13881
13964
|
} else {
|
|
13882
|
-
const words = labelText.split(/\s+/);
|
|
13883
|
-
const lines = [];
|
|
13884
|
-
let current = "";
|
|
13885
|
-
for (const word of words) {
|
|
13886
|
-
const test = current ? `${current} ${word}` : word;
|
|
13887
|
-
if (test.length > maxChars && current) {
|
|
13888
|
-
lines.push(current);
|
|
13889
|
-
current = word;
|
|
13890
|
-
} else {
|
|
13891
|
-
current = test;
|
|
13892
|
-
}
|
|
13893
|
-
}
|
|
13894
|
-
if (current) lines.push(current);
|
|
13895
13965
|
const lineHeight = SLOPE_LABEL_FONT_SIZE * 1.2;
|
|
13896
|
-
const totalHeight = (
|
|
13966
|
+
const totalHeight = (si.wrappedLines.length - 1) * lineHeight;
|
|
13897
13967
|
const startDy = -totalHeight / 2;
|
|
13898
|
-
|
|
13899
|
-
labelEl.append("tspan").attr("x", lastX + 10).attr(
|
|
13968
|
+
si.wrappedLines.forEach((line7, li) => {
|
|
13969
|
+
labelEl.append("tspan").attr("x", si.lastX + 10).attr(
|
|
13900
13970
|
"dy",
|
|
13901
13971
|
li === 0 ? `${startDy + SLOPE_LABEL_FONT_SIZE * 0.35}px` : `${lineHeight}px`
|
|
13902
13972
|
).text(line7);
|