@rowsncolumns/charts 28.1.6 → 28.1.7

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.
Files changed (29) hide show
  1. package/dist/cjs/basic-chart/basic-chart.d.ts +1 -1
  2. package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
  3. package/dist/cjs/basic-chart/basic-chart.js +152 -137
  4. package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
  5. package/dist/cjs/components/editors/chart-editor.js +5 -1
  6. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts +1 -1
  7. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  8. package/dist/cjs/plotly/basic-chart/basic-chart.js +56 -11
  9. package/dist/cjs/utils/axis-number-format.d.ts +26 -7
  10. package/dist/cjs/utils/axis-number-format.d.ts.map +1 -1
  11. package/dist/cjs/utils/axis-number-format.js +94 -16
  12. package/dist/cjs/utils/overrides.d.ts +3 -3
  13. package/dist/cjs/utils/overrides.d.ts.map +1 -1
  14. package/dist/cjs/utils/overrides.js +32 -15
  15. package/dist/esm/basic-chart/basic-chart.d.ts +1 -1
  16. package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
  17. package/dist/esm/basic-chart/basic-chart.js +64 -45
  18. package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
  19. package/dist/esm/components/editors/chart-editor.js +5 -1
  20. package/dist/esm/plotly/basic-chart/basic-chart.d.ts +1 -1
  21. package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  22. package/dist/esm/plotly/basic-chart/basic-chart.js +55 -12
  23. package/dist/esm/utils/axis-number-format.d.ts +26 -7
  24. package/dist/esm/utils/axis-number-format.d.ts.map +1 -1
  25. package/dist/esm/utils/axis-number-format.js +83 -13
  26. package/dist/esm/utils/overrides.d.ts +3 -3
  27. package/dist/esm/utils/overrides.d.ts.map +1 -1
  28. package/dist/esm/utils/overrides.js +33 -16
  29. package/package.json +3 -3
@@ -183,7 +183,7 @@ const defaultLegendConfig = {
183
183
  };
184
184
  /** Category-axis title gap: clears one row of tick labels (#986). */
185
185
  const CATEGORY_AXIS_NAME_GAP = categoryAxisNameGap();
186
- export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, }) => {
186
+ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, locale, }) => {
187
187
  const spec = chart.spec;
188
188
  const explicitChartTitle = chart.spec.title ?? undefined;
189
189
  const hierarchyTitleRef = useRef(explicitChartTitle);
@@ -454,7 +454,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
454
454
  ? "rgba(255,255,255,0.08)"
455
455
  : "rgba(0,0,0,0.06)";
456
456
  const borderColor = isDarkMode ? "rgba(255,255,255,0.3)" : "#FFFFFF";
457
- const regionSeriesLabel = buildSeriesLabelOption(spec.dataLabels);
457
+ const regionSeriesLabel = buildSeriesLabelOption(spec.dataLabels, undefined, locale);
458
458
  const seriesName = seriesEntry?.dataLabel && !isAFormula(seriesEntry.dataLabel)
459
459
  ? seriesEntry.dataLabel
460
460
  : "";
@@ -582,7 +582,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
582
582
  // Spec-level overrides — axis min/max/visibility/textFormat, legend
583
583
  // position/visibility, dataLabel toggles. Same helpers as the
584
584
  // non-bubble layout below.
585
- const bubbleSeriesLabel = buildSeriesLabelOption(spec.dataLabels);
585
+ const bubbleSeriesLabel = buildSeriesLabelOption(spec.dataLabels, undefined, locale);
586
586
  chartRef.current?.setOption({
587
587
  xAxis: [
588
588
  applyAxisOverrides({ ...xAxisConfig }, spec.categoryAxisOptions),
@@ -593,7 +593,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
593
593
  name: spec.verticalAxisTitle ?? "",
594
594
  nameLocation: "middle",
595
595
  nameGap: 45,
596
- }, spec.valueAxisOptions),
596
+ }, spec.valueAxisOptions, undefined, locale),
597
597
  ],
598
598
  legend: applyLegendOverrides({
599
599
  ...legend,
@@ -635,15 +635,20 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
635
635
  scatterStyle === "smoothMarker" ||
636
636
  !scatterStyle);
637
637
  const smooth = scatterStyle === "smooth" || scatterStyle === "smoothMarker";
638
+ // Labels hang off the point symbols: a marker-less line keeps
639
+ // an invisible 0-size symbol per point when they show (#1049).
640
+ const labelsWithoutMarkers = !wantsMarkers && Boolean(spec.dataLabels?.show);
638
641
  return wantsLine
639
642
  ? {
640
643
  type: "line",
641
644
  name: entry.name,
642
645
  data: entry.points,
643
- showSymbol: wantsMarkers,
646
+ showSymbol: wantsMarkers || labelsWithoutMarkers,
644
647
  smooth,
645
648
  symbol: mapMarkerSymbolToEcharts(symbol) ?? "circle",
646
- symbolSize: perMarker?.size ?? 6,
649
+ symbolSize: labelsWithoutMarkers
650
+ ? 0
651
+ : perMarker?.size ?? 6,
647
652
  ...(seriesColor
648
653
  ? {
649
654
  itemStyle: { color: seriesColor },
@@ -715,14 +720,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
715
720
  const value = Array.isArray(params.value)
716
721
  ? params.value[params.value.length - 1]
717
722
  : params.value ?? "";
718
- return `${params.name}: ${formatAxisValue(sizeNumberFormat, value)}`;
723
+ return `${params.name}: ${formatAxisValue(sizeNumberFormat, value, locale)}`;
719
724
  };
720
725
  // Spec-level overrides — treemap/sunburst default to no legend,
721
726
  // but an authored legend (visibility/position) still wins.
722
727
  const hierarchyDataLabels = spec.dataLabels;
723
728
  const hierarchySeriesLabel = buildSeriesLabelOption(hierarchyDataLabels && !hierarchyDataLabels.numberFormatPattern
724
729
  ? { ...hierarchyDataLabels, numberFormatPattern: sizeNumberFormat }
725
- : hierarchyDataLabels);
730
+ : hierarchyDataLabels, undefined, locale);
726
731
  chartRef.current?.setOption({
727
732
  xAxis: [
728
733
  {
@@ -818,7 +823,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
818
823
  const [zMin, zMax] = getValueExtent(contourPoints.filter((point) => typeof point[2] === "number"));
819
824
  // Values format like the cells of the series (row) they came from.
820
825
  const contourFormats = resolveSeriesNumberFormats(spec.series, getFormattingFromRange, spec.hiddenDimensionStrategy);
821
- const contourLabel = buildSeriesLabelOption(spec.dataLabels);
826
+ const contourLabel = buildSeriesLabelOption(spec.dataLabels, undefined, locale);
822
827
  if (!renderedAsContour.current && chartRef.current) {
823
828
  chartRef.current.dispose();
824
829
  chartRef.current = undefined;
@@ -835,7 +840,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
835
840
  const [x, y, z] = (params?.value ?? []);
836
841
  const value = z === "-" || z === undefined
837
842
  ? ""
838
- : formatAxisValue(contourFormats[y], z);
843
+ : formatAxisValue(contourFormats[y], z, locale);
839
844
  return `${seriesNames[y] ?? ""}<br/>${categories[x] ?? ""}: ${value}`;
840
845
  },
841
846
  },
@@ -871,7 +876,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
871
876
  right: 0,
872
877
  top: "center",
873
878
  inRange: { color: [...SURFACE_COLOR_RAMP] },
874
- formatter: (value) => formatAxisValue(contourFormats[0], value),
879
+ formatter: (value) => formatAxisValue(contourFormats[0], value, locale),
875
880
  },
876
881
  ],
877
882
  series: [
@@ -888,7 +893,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
888
893
  const [, y, z] = (params?.value ?? []);
889
894
  return z === "-" || z === undefined
890
895
  ? ""
891
- : formatAxisValue(contourFormats[y], z);
896
+ : formatAxisValue(contourFormats[y], z, locale);
892
897
  },
893
898
  },
894
899
  }
@@ -980,7 +985,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
980
985
  : seriesNames[Math.round(value[1] ?? 0)] ?? params?.seriesName ?? "";
981
986
  const valueLabel = spec.stackedType === "PERCENT_STACKED" && stackedBar3D
982
987
  ? `${Math.round((value[2] ?? 0) * 10) / 10}%`
983
- : formatAxisValue(threeDFormats[seriesIndex], value[2]);
988
+ : formatAxisValue(threeDFormats[seriesIndex], value[2], locale);
984
989
  return `${seriesLabel ? `${seriesLabel}<br/>` : ""}${categoryLabel}: ${valueLabel}`;
985
990
  };
986
991
  let threeDSeries;
@@ -1152,11 +1157,11 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1152
1157
  ...radarDataLabels,
1153
1158
  numberFormatPattern: radarFormats[seriesIndex],
1154
1159
  }
1155
- : radarDataLabels);
1160
+ : radarDataLabels, undefined, locale);
1156
1161
  const radarTooltipFormatter = (params) => {
1157
1162
  const values = Array.isArray(params?.value) ? params.value : [];
1158
1163
  const pattern = radarFormats[params?.dataIndex ?? 0];
1159
- const lines = indicators.map((indicator, i) => `${indicator.name}: ${formatAxisValue(pattern, values[i])}`);
1164
+ const lines = indicators.map((indicator, i) => `${indicator.name}: ${formatAxisValue(pattern, values[i], locale)}`);
1160
1165
  return [params?.name ?? "", ...lines].filter(Boolean).join("<br/>");
1161
1166
  };
1162
1167
  chartRef.current?.setOption({
@@ -1230,7 +1235,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1230
1235
  const stockDataLabels = spec.dataLabels;
1231
1236
  const stockSeriesLabelFor = (role) => buildSeriesLabelOption(stockDataLabels && !stockDataLabels.numberFormatPattern
1232
1237
  ? { ...stockDataLabels, numberFormatPattern: stockFormatFor(role) }
1233
- : stockDataLabels);
1238
+ : stockDataLabels, undefined, locale);
1234
1239
  // V-variants (VHLC / VOHLC) carry a volume series that renders as
1235
1240
  // a column sub-pane under the price plot: two grids stacked
1236
1241
  // vertically (price ~70% of the plot, volume below on its own
@@ -1295,10 +1300,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1295
1300
  value: p.value,
1296
1301
  itemStyle: { color: p.up ? upColor : downColor },
1297
1302
  })),
1298
- ...(tooltipValueFormatter(stockFormatFor("volume"))
1303
+ ...(tooltipValueFormatter(stockFormatFor("volume"), locale)
1299
1304
  ? {
1300
1305
  tooltip: {
1301
- valueFormatter: tooltipValueFormatter(stockFormatFor("volume")),
1306
+ valueFormatter: tooltipValueFormatter(stockFormatFor("volume"), locale),
1302
1307
  },
1303
1308
  }
1304
1309
  : {}),
@@ -1326,7 +1331,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1326
1331
  nameLocation: "middle",
1327
1332
  nameGap: 50,
1328
1333
  gridIndex: 0,
1329
- }, spec.valueAxisOptions),
1334
+ }, spec.valueAxisOptions, undefined, locale),
1330
1335
  ...(hasVolume ? [volumeYAxis] : []),
1331
1336
  ],
1332
1337
  legend: applyLegendOverrides({ ...legend, show: false }, spec.legend),
@@ -1344,10 +1349,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1344
1349
  borderColor: upColor,
1345
1350
  borderColor0: downColor,
1346
1351
  },
1347
- ...(tooltipValueFormatter(stockFormatFor("close"))
1352
+ ...(tooltipValueFormatter(stockFormatFor("close"), locale)
1348
1353
  ? {
1349
1354
  tooltip: {
1350
- valueFormatter: tooltipValueFormatter(stockFormatFor("close")),
1355
+ valueFormatter: tooltipValueFormatter(stockFormatFor("close"), locale),
1351
1356
  },
1352
1357
  }
1353
1358
  : {}),
@@ -1385,7 +1390,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1385
1390
  nameLocation: "middle",
1386
1391
  nameGap: 50,
1387
1392
  gridIndex: 0,
1388
- }, spec.valueAxisOptions),
1393
+ }, spec.valueAxisOptions, undefined, locale),
1389
1394
  ...(hasVolume ? [volumeYAxis] : []),
1390
1395
  ],
1391
1396
  legend: applyLegendOverrides({
@@ -1407,10 +1412,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1407
1412
  ...(stockSeriesLabelFor(s.role)
1408
1413
  ? { label: stockSeriesLabelFor(s.role) }
1409
1414
  : {}),
1410
- ...(tooltipValueFormatter(stockFormatFor(s.role))
1415
+ ...(tooltipValueFormatter(stockFormatFor(s.role), locale)
1411
1416
  ? {
1412
1417
  tooltip: {
1413
- valueFormatter: tooltipValueFormatter(stockFormatFor(s.role)),
1418
+ valueFormatter: tooltipValueFormatter(stockFormatFor(s.role), locale),
1414
1419
  },
1415
1420
  }
1416
1421
  : {}),
@@ -1779,26 +1784,38 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1779
1784
  const wantsMarkers = markerSymbol === "none"
1780
1785
  ? false
1781
1786
  : Boolean(spec.showMarkers) || !isNil(markerSymbol);
1782
- seriesEntry.showSymbol = wantsMarkers;
1787
+ // echarts draws a line's data labels on its point symbols, so a
1788
+ // marker-less line with labels (Excel's default "Line" with values
1789
+ // shown) keeps an invisible 0-size symbol per point for the label
1790
+ // to hang off (#1049).
1791
+ const labelsWithoutMarkers = !wantsMarkers && Boolean(spec.dataLabels?.show);
1792
+ seriesEntry.showSymbol = wantsMarkers || labelsWithoutMarkers;
1783
1793
  if (wantsMarkers) {
1784
1794
  seriesEntry.symbol =
1785
1795
  mapMarkerSymbolToEcharts(markerSymbol) ?? "circle";
1786
1796
  seriesEntry.symbolSize = seriesAny.marker?.size ?? 6;
1787
1797
  }
1788
- else if (Array.isArray(data)) {
1789
- // A marker-less line draws nothing for a point with a gap on both
1790
- // sides (a data row followed by a blank row), so that row vanishes
1791
- // from the chart. Excel plots an isolated marker there: keep the
1792
- // series symbol-less and mark only those points.
1793
- const isolated = isolatedPointIndexes(data, connectsAcrossEmptyCells(spec, lineLike));
1794
- if (isolated.length) {
1795
- seriesEntry.showSymbol = true;
1796
- seriesEntry.symbol = "none";
1797
- const marked = [...data];
1798
- for (const i of isolated) {
1799
- marked[i] = { value: marked[i], symbol: "circle", symbolSize: 6 };
1798
+ else {
1799
+ if (labelsWithoutMarkers) {
1800
+ seriesEntry.symbol = "circle";
1801
+ seriesEntry.symbolSize = 0;
1802
+ }
1803
+ if (Array.isArray(data)) {
1804
+ // A marker-less line draws nothing for a point with a gap on both
1805
+ // sides (a data row followed by a blank row), so that row vanishes
1806
+ // from the chart. Excel plots an isolated marker there: keep the
1807
+ // series symbol-less and mark only those points.
1808
+ const isolated = isolatedPointIndexes(data, connectsAcrossEmptyCells(spec, lineLike));
1809
+ if (isolated.length) {
1810
+ seriesEntry.showSymbol = true;
1811
+ if (!labelsWithoutMarkers)
1812
+ seriesEntry.symbol = "none";
1813
+ const marked = [...data];
1814
+ for (const i of isolated) {
1815
+ marked[i] = { value: marked[i], symbol: "circle", symbolSize: 6 };
1816
+ }
1817
+ seriesEntry.data = marked;
1800
1818
  }
1801
- seriesEntry.data = marked;
1802
1819
  }
1803
1820
  }
1804
1821
  }
@@ -2389,7 +2406,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2389
2406
  trigger: isCircularChart ? "item" : "axis",
2390
2407
  formatter: isCircularChart
2391
2408
  ? primaryAxisNumberFormat
2392
- ? circularTooltipFormatter(primaryAxisNumberFormat)
2409
+ ? circularTooltipFormatter(primaryAxisNumberFormat, locale)
2393
2410
  : "{b}: {c} ({d}%)"
2394
2411
  : undefined,
2395
2412
  };
@@ -2446,7 +2463,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2446
2463
  ...dataLabelOptions,
2447
2464
  numberFormatPattern: seriesNumberFormatFor(s),
2448
2465
  }
2449
- : dataLabelOptions);
2466
+ : dataLabelOptions, s?.type, locale);
2450
2467
  // For doughnut, surface the inner-radius hole on each pie series.
2451
2468
  // Excel persists `holeSize` as a 0-90 percentage; we normalize to a
2452
2469
  // 0-1 fraction (doughnutHoleSize). Default to 0.5 when unset.
@@ -2505,7 +2522,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2505
2522
  // Tooltip values of the value-axis series (a boxplot / candlestick
2506
2523
  // tooltip lists its own statistics and keeps echarts' default).
2507
2524
  const seriesTooltipValueFormatter = VALUE_TOOLTIP_SERIES_TYPES.has(s?.type)
2508
- ? valueAxisLabelFormatter(seriesNumberFormatFor(s))
2525
+ ? valueAxisLabelFormatter(seriesNumberFormatFor(s), locale)
2509
2526
  : undefined;
2510
2527
  if (seriesTooltipValueFormatter && s?.tooltip?.show !== false) {
2511
2528
  next.tooltip = {
@@ -2518,7 +2535,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2518
2535
  if (pieNumberFormat && s?.tooltip?.show !== false) {
2519
2536
  next.tooltip = {
2520
2537
  ...(s?.tooltip ?? {}),
2521
- formatter: circularTooltipFormatter(pieNumberFormat),
2538
+ formatter: circularTooltipFormatter(pieNumberFormat, locale),
2522
2539
  };
2523
2540
  }
2524
2541
  if (explosionOffset > 0 && Array.isArray(next.data)) {
@@ -2584,7 +2601,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2584
2601
  applyAxisOverrides({
2585
2602
  ...valueAxisBase,
2586
2603
  name: spec.horizontalAxisTitle ?? "",
2587
- }, spec.valueAxisOptions, primaryAxisNumberFormat),
2604
+ }, spec.valueAxisOptions, primaryAxisNumberFormat, locale),
2588
2605
  ];
2589
2606
  }
2590
2607
  const base = chartDomains.length > 0
@@ -2671,8 +2688,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2671
2688
  ? s.data.map((d) => d !== null && typeof d === "object" ? d.value : d)
2672
2689
  : []),
2673
2690
  pattern: primaryAxisNumberFormat,
2691
+ locale,
2674
2692
  }),
2675
- }, spec.valueAxisOptions, primaryAxisNumberFormat),
2693
+ }, spec.valueAxisOptions, primaryAxisNumberFormat, locale),
2676
2694
  ];
2677
2695
  if (hasSecondaryAxis) {
2678
2696
  axes.push(applyAxisOverrides({
@@ -2687,7 +2705,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2687
2705
  axisLabel: { formatter: "{value}%" },
2688
2706
  }
2689
2707
  : {}),
2690
- }, spec.secondaryValueAxisOptions, secondaryAxisNumberFormat));
2708
+ }, spec.secondaryValueAxisOptions, secondaryAxisNumberFormat, locale));
2691
2709
  }
2692
2710
  return axes;
2693
2711
  })(),
@@ -2835,6 +2853,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2835
2853
  getDomainValuesFromRange,
2836
2854
  getSeriesValuesFromRange,
2837
2855
  getFormattingFromRange,
2856
+ locale,
2838
2857
  glUpgradeTick,
2839
2858
  ]);
2840
2859
  // Resize chart
@@ -1 +1 @@
1
- {"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,+BAA+B,CAAC;AA4CvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,sEAMzB,gBAAgB,sBAo6DlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,+BAA+B,CAAC;AA4CvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,sEAMzB,gBAAgB,sBAw6DlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -622,7 +622,11 @@ export const ChartEditor = ({ chart, sheetId, onSubmit, onRequestMoveChart, getF
622
622
  React.createElement("option", { value: "outside" }, "Outside"),
623
623
  React.createElement("option", { value: "insideEnd" }, "Inside end"),
624
624
  React.createElement("option", { value: "outsideEnd" }, "Outside end"),
625
- React.createElement("option", { value: "bestFit" }, "Best fit")),
625
+ React.createElement("option", { value: "bestFit" }, "Best fit"),
626
+ React.createElement("option", { value: "above" }, "Above"),
627
+ React.createElement("option", { value: "below" }, "Below"),
628
+ React.createElement("option", { value: "left" }, "Left"),
629
+ React.createElement("option", { value: "right" }, "Right")),
626
630
  React.createElement("label", { className: "font-system text-xs" }, "Number format pattern"),
627
631
  React.createElement(Input, { value: values?.spec.dataLabels?.numberFormatPattern ?? "", type: "text", onChange: (e) => setFieldValue("spec.dataLabels.numberFormatPattern", e.target.value || undefined), className: "text-xs w-32", placeholder: "#,##0.00" }))) : null)),
628
632
  basicSpec && showChartOptions ? (React.createElement(Section, { title: "Chart options" },
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
2
  import type { EChartComponentProps } from "../../types";
3
3
  export type BasicChartProps = EChartComponentProps;
4
- export declare const BasicChart: ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, }: BasicChartProps) => React.JSX.Element;
4
+ export declare const BasicChart: ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, locale, }: BasicChartProps) => React.JSX.Element;
5
5
  //# sourceMappingURL=basic-chart.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAgXxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBA8zEjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAuZxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBA00EjB,CAAC"}
@@ -5,7 +5,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal
5
5
  import { chartPaletteColorAt, debug, expandChartPalette, isAFormula, isNil, ssfFormat, } from "@rowsncolumns/utils";
6
6
  import React, { useCallback, useMemo, useRef, useState } from "react";
7
7
  import { aggregateSeriesByDomain, getDomainValuesForAxis, sanitizeDomainValues, shouldAggregateSeries, } from "../../utils/aggregation";
8
- import { formatAxisValue, numberFormatToPlotlyTicks, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
8
+ import { formatAxisValue, numberFormatToPlotlyTicks, plotlySeparators, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
9
9
  import { computeBoxplotSummary } from "../../utils/boxplot";
10
10
  import { createBubbleSizeScale, prepareBubbleSeriesData, toLabelString, } from "../../utils/bubble";
11
11
  import { canSwitchRowColumn, cellLabelGetterFromRangeReader, switchRowColumn, } from "../../utils/chart-orientation";
@@ -179,14 +179,44 @@ const PLOTLY_DLBL_POS_BAR = {
179
179
  insideEnd: "inside",
180
180
  outsideEnd: "outside",
181
181
  bestFit: "outside",
182
+ above: "outside",
183
+ below: "outside",
184
+ left: "outside",
185
+ right: "outside",
182
186
  };
183
- const applyDataLabelsToTracePlotly = (trace, opts, chartType, sourceNumberFormat) => {
187
+ // A scatter trace (line / area / scatter) places its text with the compass
188
+ // positions, and only draws it when `mode` carries `text`. Excel's line
189
+ // placements are centre / left / right / above / below; the bar-only ones
190
+ // land on Excel's default for a line, above the point (#1049).
191
+ const PLOTLY_DLBL_POS_POINT = {
192
+ center: "middle center",
193
+ inside: "middle center",
194
+ outside: "top center",
195
+ insideEnd: "top center",
196
+ outsideEnd: "top center",
197
+ bestFit: "top center",
198
+ above: "top center",
199
+ below: "bottom center",
200
+ left: "middle left",
201
+ right: "middle right",
202
+ };
203
+ const withTextMode = (mode) => {
204
+ const base = typeof mode === "string" && mode ? mode : "lines+markers";
205
+ return base.split("+").includes("text") ? base : `${base}+text`;
206
+ };
207
+ const applyDataLabelsToTracePlotly = (trace, opts, chartType, sourceNumberFormat, locale) => {
184
208
  if (!opts?.show)
185
209
  return trace;
186
210
  const next = { ...trace };
187
211
  const isCircular = chartType === "pie" || chartType === "doughnut";
188
- const posMap = isCircular ? PLOTLY_DLBL_POS_PIE : PLOTLY_DLBL_POS_BAR;
189
- const position = opts.position ? posMap[opts.position] ?? "inside" : "inside";
212
+ const isPoint = !isCircular && next.type === "scatter";
213
+ const posMap = isCircular
214
+ ? PLOTLY_DLBL_POS_PIE
215
+ : isPoint
216
+ ? PLOTLY_DLBL_POS_POINT
217
+ : PLOTLY_DLBL_POS_BAR;
218
+ const fallback = isPoint ? "top center" : "inside";
219
+ const position = opts.position ? posMap[opts.position] ?? fallback : fallback;
190
220
  if (isCircular) {
191
221
  // Plotly's pie trace uses `textinfo` to control which fields render.
192
222
  const parts = [];
@@ -204,7 +234,7 @@ const applyDataLabelsToTracePlotly = (trace, opts, chartType, sourceNumberFormat
204
234
  const pattern = opts.numberFormatPattern ?? sourceNumberFormat;
205
235
  if (pattern) {
206
236
  const values = Array.isArray(next.values) ? next.values : [];
207
- next.text = values.map((v) => formatAxisValue(pattern, v));
237
+ next.text = values.map((v) => formatAxisValue(pattern, v, locale));
208
238
  next.texttemplate = next.textinfo
209
239
  .split("+")
210
240
  .map((part) => (part === "value" ? "%{text}" : `%{${part}}`))
@@ -223,9 +253,13 @@ const applyDataLabelsToTracePlotly = (trace, opts, chartType, sourceNumberFormat
223
253
  const values = next.orientation === "h" ? next.x : next.y;
224
254
  const vals = Array.isArray(values) ? values : [];
225
255
  next.text = pattern
226
- ? vals.map((v) => (v === null || v === undefined ? "" : ssfFormat(pattern, v)))
227
- : values;
256
+ ? vals.map((v) => v === null || v === undefined ? "" : ssfFormat(pattern, v, locale))
257
+ : locale
258
+ ? vals.map((v) => formatAxisValue(undefined, v, locale))
259
+ : values;
228
260
  next.textposition = position;
261
+ if (isPoint)
262
+ next.mode = withTextMode(next.mode);
229
263
  }
230
264
  return next;
231
265
  };
@@ -345,7 +379,7 @@ const addAlphaToColor = (color, alpha) => {
345
379
  }
346
380
  return color;
347
381
  };
348
- export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, }) => {
382
+ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, readonly, getDomainValuesFromRange, getSeriesValuesFromRange, getFormattingFromRange, onDeleteChart, onUpdateChart, onRequestEdit, onRequestCalculate, isSelected, fieldButtons, locale, }) => {
349
383
  const spec = chart.spec;
350
384
  const hierarchyTitleRef = useRef(undefined);
351
385
  const explicitChartTitle = chart.spec.title ?? undefined;
@@ -1833,6 +1867,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1833
1867
  : valueAxisNameGap({
1834
1868
  values: primaryValues,
1835
1869
  pattern: primaryAxisNumberFormat,
1870
+ locale,
1836
1871
  fontSize: axisFontSize,
1837
1872
  minimum: 0,
1838
1873
  }) -
@@ -1848,6 +1883,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1848
1883
  ? trace.y
1849
1884
  : []),
1850
1885
  pattern: secondaryAxisNumberFormat,
1886
+ locale,
1851
1887
  fontSize: axisFontSize,
1852
1888
  minimum: 0,
1853
1889
  }) -
@@ -2028,14 +2064,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2028
2064
  const piePull = isOfPie ? undefined : explosionToPlotlyPull(resolveExplosion(spec));
2029
2065
  const formattedTraces = traces.map((trace) => {
2030
2066
  const pattern = traceNumberFormat(trace);
2031
- let next = applyDataLabelsToTracePlotly(trace, dlOpts, spec.chartType, pattern);
2067
+ let next = applyDataLabelsToTracePlotly(trace, dlOpts, spec.chartType, pattern, locale);
2032
2068
  if (next.type === "pie") {
2033
2069
  // Hover values format like the slice's source cell.
2034
2070
  if (pattern && !next.text) {
2035
2071
  const values = Array.isArray(next.values) ? next.values : [];
2036
2072
  next = {
2037
2073
  ...next,
2038
- text: values.map((v) => formatAxisValue(pattern, v)),
2074
+ text: values.map((v) => formatAxisValue(pattern, v, locale)),
2039
2075
  hoverinfo: "label+text+percent+name",
2040
2076
  };
2041
2077
  }
@@ -2062,7 +2098,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2062
2098
  if (seriesPattern && Array.isArray(values)) {
2063
2099
  next = {
2064
2100
  ...next,
2065
- customdata: values.map((v) => formatAxisValue(seriesPattern, v)),
2101
+ customdata: values.map((v) => formatAxisValue(seriesPattern, v, locale)),
2066
2102
  hovertemplate: `${horizontal ? "%{y}" : "%{x}"}<br>%{customdata}<extra>%{fullData.name}</extra>`,
2067
2103
  };
2068
2104
  }
@@ -2104,6 +2140,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2104
2140
  getDomainValuesFromRange,
2105
2141
  getSeriesValuesFromRange,
2106
2142
  getFormattingFromRange,
2143
+ locale,
2107
2144
  ]);
2108
2145
  // Update theme
2109
2146
  useIsomorphicLayoutEffect(() => {
@@ -2141,7 +2178,13 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2141
2178
  scrollZoom: false,
2142
2179
  doubleClick: false,
2143
2180
  };
2144
- const plotLayout = useMemo(() => ({ ...layout, dragmode: false }), [layout]);
2181
+ // Ticks and hover values plotly formats itself use the sheet's separators.
2182
+ const separators = useMemo(() => plotlySeparators(locale), [locale]);
2183
+ const plotLayout = useMemo(() => ({
2184
+ ...layout,
2185
+ dragmode: false,
2186
+ ...(separators ? { separators } : {}),
2187
+ }), [layout, separators]);
2145
2188
  // Excel's "Rounded Corners" chart frame (`<c:roundedCorners val="1"/>`
2146
2189
  // at the chartSpace root). Default per OOXML §21.2.2.183 is square,
2147
2190
  // so only opt in when the workbook explicitly set the flag.
@@ -26,17 +26,28 @@ export declare const resolveValueAxisNumberFormat: ({ axisOptions, series, getFo
26
26
  getFormattingFromRange: RangeFormatReader | undefined;
27
27
  hiddenDimensionStrategy?: HIDDEN_DIMENSION_STRATEGY | null;
28
28
  }) => string | undefined;
29
- /** Format one numeric value through the resolved pattern; non-numbers pass through. */
30
- export declare const formatAxisValue: (pattern: string | undefined, value: unknown) => string;
31
- /** echarts `axisLabel.formatter` / `tooltip.valueFormatter` for a value axis. */
32
- export declare const valueAxisLabelFormatter: (pattern: string | undefined) => ((value: unknown) => string) | undefined;
29
+ export declare const formatPlainNumber: (value: number, locale: string | undefined, grouping?: boolean) => string;
30
+ /**
31
+ * Format one numeric value through the resolved pattern; non-numbers pass
32
+ * through. `locale` is the spreadsheet locale the cells format with: it
33
+ * picks the pattern's separators, and a number without a pattern reads
34
+ * like a `General` cell in that locale.
35
+ */
36
+ export declare const formatAxisValue: (pattern: string | undefined, value: unknown, locale?: string) => string;
37
+ /**
38
+ * echarts `axisLabel.formatter` / `tooltip.valueFormatter` for a value
39
+ * axis. Without a pattern the ticks keep echarts' own labels unless a
40
+ * locale is given, in which case they group thousands the way echarts
41
+ * does but with the locale's separators (#1050).
42
+ */
43
+ export declare const valueAxisLabelFormatter: (pattern: string | undefined, locale?: string) => ((value: unknown) => string) | undefined;
33
44
  /**
34
45
  * echarts `tooltip.valueFormatter` for a series whose data items are
35
46
  * tuples (candlestick, 3-D points): every number formats through the
36
47
  * pattern; `undefined` when there is no pattern so echarts keeps its
37
48
  * default.
38
49
  */
39
- export declare const tooltipValueFormatter: (pattern: string | undefined) => ((value: unknown) => string | string[]) | undefined;
50
+ export declare const tooltipValueFormatter: (pattern: string | undefined, locale?: string) => ((value: unknown) => string | string[]) | undefined;
40
51
  /**
41
52
  * Excel's data labels and tooltips are linked to *each series' own* source
42
53
  * cells, not to the axis: a revenue series formatted `$#,##0` next to a
@@ -45,11 +56,18 @@ export declare const tooltipValueFormatter: (pattern: string | undefined) => ((v
45
56
  */
46
57
  export declare const resolveSeriesNumberFormats: (series: Pick<ChartData, "sources">[] | undefined, getFormattingFromRange: RangeFormatReader | undefined, hiddenDimensionStrategy?: HIDDEN_DIMENSION_STRATEGY | null) => (string | undefined)[];
47
58
  /** echarts pie / doughnut tooltip: `name: value (percent%)` with the value formatted. */
48
- export declare const circularTooltipFormatter: (pattern: string | undefined) => (params: {
59
+ export declare const circularTooltipFormatter: (pattern: string | undefined, locale?: string) => (params: {
49
60
  name?: string;
50
61
  value?: unknown;
51
62
  percent?: number;
52
63
  }) => string;
64
+ /**
65
+ * plotly `layout.separators` for the spreadsheet locale: the decimal
66
+ * separator followed by the thousands separator, so ticks and hover
67
+ * values plotly formats itself read like the sheet's cells (#1050).
68
+ * `undefined` without a locale keeps plotly's default (`.,`).
69
+ */
70
+ export declare const plotlySeparators: (locale: string | undefined) => string | undefined;
53
71
  export type PlotlyTickFormat = {
54
72
  tickformat?: string;
55
73
  tickprefix?: string;
@@ -73,9 +91,10 @@ export declare const numberFormatToPlotlyTicks: (pattern: string | undefined) =>
73
91
  * measured; the fixed default of 50px only fits labels up to ~4 digits and
74
92
  * lets a currency axis title paint over its own tick labels.
75
93
  */
76
- export declare const valueAxisNameGap: ({ values, pattern, fontSize, minimum, }: {
94
+ export declare const valueAxisNameGap: ({ values, pattern, locale, fontSize, minimum, }: {
77
95
  values: readonly unknown[];
78
96
  pattern: string | undefined;
97
+ locale?: string;
79
98
  fontSize?: number;
80
99
  minimum?: number;
81
100
  }) => number;
@@ -1 +1 @@
1
- {"version":3,"file":"axis-number-format.d.ts","sourceRoot":"","sources":["../../../utils/axis-number-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,yBAAyB,EACzB,KAAK,EACL,UAAU,EACX,MAAM,2BAA2B,CAAC;AAWnC,KAAK,iBAAiB,GAAG,CACvB,UAAU,EAAE,UAAU,EACtB,uBAAuB,CAAC,EAAE,yBAAyB,KAChD,OAAO,EAAE,CAAC;AAMf;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,YAGjC,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,UAAU,EAAE,GAAG,SAAS,EACjC,wBAAwB,iBAAiB,GAAG,SAAS,EACrD,0BAA0B,yBAAyB,GAAG,IAAI,KACzD,MAAM,GAAG,SAWX,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GAAI,2EAK1C;IACD,WAAW,EAAE,KAAK,CAAC;QAAE,mBAAmB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IACxE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;IACrC,sBAAsB,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACtD,uBAAuB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC5D,KAAG,MAAM,GAAG,SAQZ,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,GAAG,SAAS,EAC3B,OAAO,OAAO,KACb,MAIF,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,GAAI,SAAS,MAAM,GAAG,SAAS,cAC/C,OAAO,wBAAgD,CAAC;AAE5E;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,MAAM,GAAG,SAAS,cAEnD,OAAO,mCAIN,CAAC;AAEhB;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GACrC,QAAQ,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,GAAG,SAAS,EAChD,wBAAwB,iBAAiB,GAAG,SAAS,EACrD,0BAA0B,yBAAyB,GAAG,IAAI,KACzD,CAAC,MAAM,GAAG,SAAS,CAAC,EAOpB,CAAC;AAEJ,yFAAyF;AACzF,eAAO,MAAM,wBAAwB,GAClC,SAAS,MAAM,GAAG,SAAS,MAC3B,QAAQ;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,WAGvD,CAAC;AAET,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,GAAG,SAAS,KAC1B,gBAAgB,GAAG,SA4DrB,CAAC;AA2BF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,yCAK9B;IACD,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KAAG,MAgBH,CAAC"}
1
+ {"version":3,"file":"axis-number-format.d.ts","sourceRoot":"","sources":["../../../utils/axis-number-format.ts"],"names":[],"mappings":"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"}