@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/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 ? data.length > 10 ? 11 : data.length > 5 ? 12 : 16 : 16,
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").replace(/ /g, "\n")
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 valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
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.forEach((item, idx) => {
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 pctPart = pctChange !== null ? ` (${sign}${pctChange.toFixed(1)}%)` : "";
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
- seriesG.append("text").attr("x", isFirst ? x - 10 : x).attr("y", y).attr("dy", "0.35em").attr("text-anchor", isFirst ? "end" : "middle").attr("fill", textColor).attr("font-size", "16px").text(val.toString());
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 lastX = xScale(periods[periods.length - 1]);
13874
- const lastY = yScale(lastVal);
13875
- const labelText = `${lastVal} \u2014 ${item.label}`;
13876
- const availableWidth = rightMargin - 15;
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 = (lines.length - 1) * lineHeight;
13966
+ const totalHeight = (si.wrappedLines.length - 1) * lineHeight;
13897
13967
  const startDy = -totalHeight / 2;
13898
- lines.forEach((line7, li) => {
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);