@rowsncolumns/charts 28.1.11 → 28.1.13

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 (35) hide show
  1. package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
  2. package/dist/cjs/basic-chart/basic-chart.js +462 -286
  3. package/dist/cjs/basic-chart/helpers.d.ts.map +1 -1
  4. package/dist/cjs/basic-chart/helpers.js +2 -0
  5. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  6. package/dist/cjs/plotly/basic-chart/basic-chart.js +198 -149
  7. package/dist/cjs/plotly/basic-chart/helpers.d.ts.map +1 -1
  8. package/dist/cjs/plotly/basic-chart/helpers.js +2 -0
  9. package/dist/cjs/utils/hierarchy.d.ts +6 -0
  10. package/dist/cjs/utils/hierarchy.d.ts.map +1 -1
  11. package/dist/cjs/utils/hierarchy.js +23 -1
  12. package/dist/cjs/utils/histogram.d.ts +42 -3
  13. package/dist/cjs/utils/histogram.d.ts.map +1 -1
  14. package/dist/cjs/utils/histogram.js +193 -5
  15. package/dist/cjs/utils/overrides.d.ts +1 -1
  16. package/dist/cjs/utils/overrides.d.ts.map +1 -1
  17. package/dist/cjs/utils/overrides.js +44 -39
  18. package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
  19. package/dist/esm/basic-chart/basic-chart.js +297 -109
  20. package/dist/esm/basic-chart/helpers.d.ts.map +1 -1
  21. package/dist/esm/basic-chart/helpers.js +2 -0
  22. package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  23. package/dist/esm/plotly/basic-chart/basic-chart.js +132 -70
  24. package/dist/esm/plotly/basic-chart/helpers.d.ts.map +1 -1
  25. package/dist/esm/plotly/basic-chart/helpers.js +2 -0
  26. package/dist/esm/utils/hierarchy.d.ts +6 -0
  27. package/dist/esm/utils/hierarchy.d.ts.map +1 -1
  28. package/dist/esm/utils/hierarchy.js +21 -0
  29. package/dist/esm/utils/histogram.d.ts +42 -3
  30. package/dist/esm/utils/histogram.d.ts.map +1 -1
  31. package/dist/esm/utils/histogram.js +171 -4
  32. package/dist/esm/utils/overrides.d.ts +1 -1
  33. package/dist/esm/utils/overrides.d.ts.map +1 -1
  34. package/dist/esm/utils/overrides.js +4 -2
  35. package/package.json +2 -2
@@ -6,7 +6,6 @@ import { chartPaletteColorAt, debug, expandChartPalette, isAFormula, isNil, ssfF
6
6
  import React, { useCallback, useMemo, useRef, useState } from "react";
7
7
  import { aggregateSeriesByDomain, getDomainValuesForAxis, sanitizeDomainValues, shouldAggregateSeries, } from "../../utils/aggregation";
8
8
  import { formatAxisValue, numberFormatToPlotlyTicks, plotlySeparators, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
9
- import { computeBoxplotSummary } from "../../utils/boxplot";
10
9
  import { createBubbleSizeScale, prepareBubbleSeriesData, toLabelString, } from "../../utils/bubble";
11
10
  import { canSwitchRowColumn, cellLabelGetterFromRangeReader, switchRowColumn, } from "../../utils/chart-orientation";
12
11
  import { dataUrlToBlob } from "../../utils/chart-image";
@@ -25,7 +24,7 @@ import { resolvePlotlyClickSelection, wasDragged, } from "../../utils/plotly-cli
25
24
  import { buildPlotlySurfaceTrace } from "../../utils/plotly-surface";
26
25
  import { normalize3DSourceType, } from "../../utils/three-d";
27
26
  import { extractHierarchyRows, getHierarchyHeaderTitle, hierarchyNodeColors, toPlotlyHierarchy, } from "../../utils/hierarchy";
28
- import { binHistogram, computePareto, isParetoSpec, } from "../../utils/histogram";
27
+ import { aggregateByCategory, binHistogram, computePareto, hasExcelBinning, isParetoSpec, } from "../../utils/histogram";
29
28
  import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../../utils/of-pie";
30
29
  import { buildRadarIndicators } from "../../utils/radar";
31
30
  import { buildSequentialColorRamp, isRegionMapSpec, resolveGeoScope, WORLD_GEO_SCOPE, } from "../../utils/region-map";
@@ -736,6 +735,29 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
736
735
  const xAxisFmt = spec.categoryAxisOptions?.textFormat;
737
736
  const yAxisFmt = spec.valueAxisOptions?.textFormat;
738
737
  const legendFmt = spec.legend?.textFormat;
738
+ const bubbleLegendOverrides = applyLegendOverridesPlotly({
739
+ font: {
740
+ color: legendFmt?.color ?? textColor,
741
+ ...(legendFmt?.fontFamily ? { family: legendFmt.fontFamily } : {}),
742
+ ...(legendFmt?.fontSize ? { size: legendFmt.fontSize } : {}),
743
+ },
744
+ }, spec.legend);
745
+ const bubbleBand = reservePlotlyLegendBand({
746
+ position: spec.legend?.position,
747
+ visible: (bubbleLegendOverrides.showlegend ?? preparedSeries.length > 1) !==
748
+ false,
749
+ labels: preparedSeries.map((entry) => entry.name),
750
+ legendFontSize: legendFmt?.fontSize ?? 12,
751
+ width: Math.max(0, (width ?? 0) - 2),
752
+ height: Math.max(0, (height ?? 0) - 2),
753
+ hasTitle: Boolean(title),
754
+ titleFontSize: titleFmt?.fontSize ?? 16,
755
+ hasBottomAxisTitle: Boolean(spec.horizontalAxisTitle),
756
+ hasLeftAxisTitle: Boolean(spec.verticalAxisTitle),
757
+ leftAxisDepth: 60,
758
+ rightAxisDepth: hasBubbleSecondaryAxis ? 60 : 0,
759
+ axisFontSize: 12,
760
+ });
739
761
  const bubbleLayout = {
740
762
  title: {
741
763
  text: plotlyTitleText(title, spec.titleTextFormat),
@@ -789,16 +811,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
789
811
  }
790
812
  : {}),
791
813
  legend: {
792
- font: {
793
- color: legendFmt?.color ?? textColor,
794
- ...(legendFmt?.fontFamily ? { family: legendFmt.fontFamily } : {}),
795
- ...(legendFmt?.fontSize ? { size: legendFmt.fontSize } : {}),
796
- },
814
+ ...bubbleLegendOverrides.legend,
815
+ ...(bubbleBand.legend ?? {}),
797
816
  },
798
817
  paper_bgcolor: bgColor,
799
818
  plot_bgcolor: bgColor,
800
- showlegend: preparedSeries.length > 1,
801
- margin: { l: 60, r: hasBubbleSecondaryAxis ? 60 : 20, t: 50, b: 50 },
819
+ showlegend: bubbleLegendOverrides.showlegend ?? preparedSeries.length > 1,
820
+ // The plot shrinks to leave the legend its own band (#1089).
821
+ margin: bubbleBand.margin,
802
822
  };
803
823
  setPlotData(traces);
804
824
  setLayout(bubbleLayout);
@@ -851,9 +871,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
851
871
  ...(isSunburst ? { line: { width: 1 } } : {}),
852
872
  },
853
873
  name: seriesName,
854
- textinfo: "label+value",
874
+ // `dataLabels: { show: false }` turns the labels off (#1086).
875
+ textinfo: spec.dataLabels?.show === false ? "none" : "label+value",
855
876
  branchvalues: "total",
856
- ...(isSunburst
877
+ ...(isSunburst || spec.dataLabels?.show === false
857
878
  ? {}
858
879
  : {
859
880
  textposition: "bottom left",
@@ -1075,20 +1096,43 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1075
1096
  });
1076
1097
  }
1077
1098
  const radarScale = indicators[0] ?? { min: 0, max: 1 };
1099
+ // The legend gets its own band so it never covers the circle (#1089).
1100
+ const radarLegendOverrides = applyLegendOverridesPlotly({ font: { color: textColor } }, spec.legend);
1101
+ const radarBand = reservePlotlyLegendBand({
1102
+ position: spec.legend?.position,
1103
+ visible: (radarLegendOverrides.showlegend ?? radarTraces.length > 1) !== false,
1104
+ labels: radarInputs.map((input) => input.name),
1105
+ legendFontSize: spec.legend?.textFormat?.fontSize ?? 12,
1106
+ width: Math.max(0, (width ?? 0) - 2),
1107
+ height: Math.max(0, (height ?? 0) - 2),
1108
+ hasTitle: Boolean(title),
1109
+ titleFontSize: spec.titleTextFormat?.fontSize ?? 16,
1110
+ hasBottomAxisTitle: false,
1111
+ hasLeftAxisTitle: false,
1112
+ leftAxisDepth: 50,
1113
+ rightAxisDepth: 50,
1114
+ axisFontSize: 12,
1115
+ });
1078
1116
  setPlotData(radarTraces);
1079
1117
  setLayout({
1080
1118
  title: { text: plotlyTitleText(title, spec.titleTextFormat) },
1081
1119
  font: { color: textColor },
1082
1120
  paper_bgcolor: bgColor,
1083
1121
  plot_bgcolor: bgColor,
1084
- showlegend: radarTraces.length > 1,
1122
+ showlegend: radarLegendOverrides.showlegend ?? radarTraces.length > 1,
1123
+ legend: { ...radarLegendOverrides.legend, ...(radarBand.legend ?? {}) },
1085
1124
  polar: {
1086
1125
  radialaxis: {
1087
1126
  visible: radarAxisOptions?.visible !== false,
1088
1127
  range: [radarScale.min, radarScale.max],
1089
1128
  },
1090
1129
  },
1091
- margin: { l: 50, r: 50, t: 50, b: 50 },
1130
+ margin: {
1131
+ l: Math.max(50, radarBand.margin.l),
1132
+ r: Math.max(50, radarBand.margin.r),
1133
+ t: Math.max(50, radarBand.margin.t),
1134
+ b: Math.max(50, radarBand.margin.b),
1135
+ },
1092
1136
  autosize: true,
1093
1137
  });
1094
1138
  return;
@@ -1619,12 +1663,29 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1619
1663
  if (effectiveChartType === "histogram") {
1620
1664
  const rawValues = seriesValuesOf(seriesData);
1621
1665
  const binCount = spec.binCount;
1666
+ const binningOptions = {
1667
+ binSize: spec.binSize,
1668
+ intervalClosed: spec.intervalClosed,
1669
+ overflow: spec.overflow,
1670
+ underflow: spec.underflow,
1671
+ };
1672
+ // A domain names a category column: aggregate per category (Excel's
1673
+ // "By Category" / Pareto over categories) instead of binning
1674
+ // (#1087). Excel binning options also pre-bin with the shared util,
1675
+ // since plotly's native histogram cannot close intervals on the
1676
+ // right or add overflow bins.
1677
+ const categories = domainData;
1678
+ const prebinned = categories.length
1679
+ ? aggregateByCategory(categories, rawValues, series.aggregateType ?? "SUM")
1680
+ : hasExcelBinning(binningOptions)
1681
+ ? binHistogram(rawValues, binCount, binningOptions)
1682
+ : null;
1622
1683
  if (isPareto) {
1623
1684
  // Plotly's native histogram trace bins in axis order and
1624
1685
  // can't reorder bins, so Pareto pre-bins with the shared
1625
1686
  // util, sorts descending, and renders a bar trace plus the
1626
1687
  // cumulative-% line pointed at the y2 overlay axis.
1627
- const { labels, counts, cumulativePercents } = computePareto(binHistogram(rawValues, binCount));
1688
+ const { labels, counts, cumulativePercents } = computePareto(prebinned ?? binHistogram(rawValues, binCount));
1628
1689
  const barTrace = {
1629
1690
  type: "bar",
1630
1691
  x: labels,
@@ -1638,16 +1699,34 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1638
1699
  effectiveChartType,
1639
1700
  });
1640
1701
  traces.push(barTrace);
1702
+ const paretoLineColor = spec.paretoLineColor;
1703
+ // Excel draws the Pareto line without markers.
1641
1704
  traces.push({
1642
1705
  type: "scatter",
1643
- mode: "lines+markers",
1706
+ mode: "lines",
1644
1707
  x: labels,
1645
1708
  y: cumulativePercents,
1646
1709
  name: "Cumulative %",
1647
1710
  yaxis: "y2",
1711
+ ...(paretoLineColor ? { line: { color: paretoLineColor } } : {}),
1648
1712
  });
1649
1713
  hasSecondaryAxis = true;
1650
1714
  }
1715
+ else if (prebinned) {
1716
+ const barTrace = {
1717
+ type: "bar",
1718
+ x: prebinned.labels,
1719
+ y: prebinned.counts,
1720
+ name: dataLabel,
1721
+ };
1722
+ applyTraceColor(barTrace, series.color ?? undefined, {
1723
+ noFill: series.noFill,
1724
+ dataPointColors: series.dataPointColors,
1725
+ seriesIndex: currentSeriesIndex,
1726
+ effectiveChartType,
1727
+ });
1728
+ traces.push(barTrace);
1729
+ }
1651
1730
  else {
1652
1731
  const trace = {
1653
1732
  type: "histogram",
@@ -1669,62 +1748,34 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1669
1748
  else if (effectiveChartType === "boxplot") {
1670
1749
  const rawValues = seriesValuesOf(seriesData);
1671
1750
  const quartileMethod = spec.quartileMethod;
1672
- const showOutliers = spec.showOutliers;
1751
+ const showOutliers = spec.showOutliers !== false;
1673
1752
  const showMeanMarker = spec.showMeanMarker === true;
1674
- // Plotly's box trace computes quartiles/fences itself from
1675
- // raw values, so a spec-pinned quartile method (or Excel's
1676
- // "no outliers → whiskers span min/max" semantics) requires
1677
- // switching to plotly's precomputed-statistics signature
1678
- // (q1/median/q3/lowerfence/upperfence arrays). When neither
1679
- // option is set the raw-values trace is kept unchanged.
1680
- const usePrecomputed = quartileMethod != null || showOutliers === false;
1681
- let trace;
1682
- if (usePrecomputed) {
1683
- const summary = computeBoxplotSummary(rawValues, {
1684
- quartileMethod,
1685
- });
1686
- if (!summary)
1687
- continue;
1688
- const hideOutliers = showOutliers === false;
1689
- trace = {
1690
- type: "box",
1691
- name: dataLabel,
1692
- // Precomputed boxes need an explicit category so each
1693
- // series lands on its own slot (raw mode derives it from
1694
- // the trace name).
1695
- x: [dataLabel || `trace ${currentSeriesIndex}`],
1696
- q1: [summary.q1],
1697
- median: [summary.median],
1698
- q3: [summary.q3],
1699
- // Excel: hiding outlier points extends the whiskers to
1700
- // the full min/max; with outliers shown they stop at the
1701
- // most extreme points inside the 1.5×IQR fences.
1702
- lowerfence: [hideOutliers ? summary.min : summary.lowerWhisker],
1703
- upperfence: [hideOutliers ? summary.max : summary.upperWhisker],
1704
- ...(hideOutliers
1705
- ? { boxpoints: false }
1706
- : {
1707
- // Sample points ride along so plotly can still draw
1708
- // the outlier dots against the precomputed fences.
1709
- y: [rawValues.filter((v) => v != null)],
1710
- boxpoints: "outliers",
1711
- }),
1712
- ...(showMeanMarker
1713
- ? { mean: [summary.mean], boxmean: true }
1714
- : {}),
1715
- };
1716
- }
1717
- else {
1718
- trace = {
1719
- type: "box",
1720
- y: rawValues.map((v) => (v ?? null)),
1721
- name: dataLabel,
1722
- // Raw mode is used when outliers are visible (today's
1723
- // default and `showOutliers: true` alike).
1724
- boxpoints: "outliers",
1725
- ...(showMeanMarker ? { boxmean: true } : {}),
1726
- };
1727
- }
1753
+ const showInnerPoints = spec.showInnerPoints === true;
1754
+ const showMeanLine = spec.showMeanLine === true;
1755
+ // A category domain groups the series by its values (one box per
1756
+ // category per series, `boxmode: "group"` in the layout); without
1757
+ // one each series is a box on its own slot (#1092). Plotly's box
1758
+ // trace computes the quartiles (Excel's inclusive / exclusive
1759
+ // methods are native), keeps the whiskers at the 1.5×IQR fences
1760
+ // and only hides the points when outliers are off.
1761
+ const boxDomainSource = spec.domains?.[0]?.sources?.[0];
1762
+ const boxCategories = boxDomainSource
1763
+ ? (getDomainValuesFromRange(boxDomainSource, spec.hiddenDimensionStrategy) ?? []).map((v) => (v === null || v === undefined ? "" : `${v}`.trim()))
1764
+ : [];
1765
+ const grouped = boxCategories.some((c) => c !== "");
1766
+ const values = rawValues.map((v) => (v ?? null));
1767
+ const trace = {
1768
+ type: "box",
1769
+ name: dataLabel,
1770
+ y: values,
1771
+ ...(grouped
1772
+ ? { x: values.map((_, i) => boxCategories[i] ?? "") }
1773
+ : {}),
1774
+ ...(quartileMethod ? { quartilemethod: quartileMethod } : {}),
1775
+ boxpoints: showInnerPoints ? "all" : showOutliers ? "outliers" : false,
1776
+ ...(showInnerPoints ? { jitter: 0, pointpos: 0 } : {}),
1777
+ ...(showMeanMarker || showMeanLine ? { boxmean: true } : {}),
1778
+ };
1728
1779
  applyTraceColor(trace, series.color ?? undefined, {
1729
1780
  noFill: series.noFill,
1730
1781
  dataPointColors: series.dataPointColors,
@@ -2131,6 +2182,17 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2131
2182
  // gapWidth=150 (default) → ~0.4 bargap.
2132
2183
  ...(typeof spec.gapWidth === "number"
2133
2184
  ? { bargap: Math.max(0, Math.min(0.95, spec.gapWidth / 400)) }
2185
+ : spec.chartType === "histogram"
2186
+ ? // Excel's histogram columns touch by default (#1087).
2187
+ { bargap: 0 }
2188
+ : {}),
2189
+ // Box & whisker: boxes grouped by category, `gapWidth` as for columns
2190
+ // (#1092).
2191
+ ...(spec.chartType === "boxplot"
2192
+ ? {
2193
+ boxmode: "group",
2194
+ boxgap: Math.max(0, Math.min(0.95, (typeof spec.gapWidth === "number" ? spec.gapWidth : 150) / 400)),
2195
+ }
2134
2196
  : {}),
2135
2197
  font: {
2136
2198
  family: "Untitled Sans, apple-system, sans-serif",
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,eAAO,MAAM,qBAAqB,GAChC,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KACvC,MAmEF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC;;;;;;;;;CAgBzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,GAAG,SAAS,GAAG,IAAI,KAChC,MAAM,GAAG,SA0BX,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,YAiBjE,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,eAAO,MAAM,qBAAqB,GAChC,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KACvC,MAmEF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC;;;;;;;;;CAgBzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,GAAG,SAAS,GAAG,IAAI,KAChC,MAAM,GAAG,SA0BX,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,YAmBjE,CAAC"}
@@ -103,6 +103,8 @@ export const showXAxis = (type) => {
103
103
  type === "histogram" ||
104
104
  // A waterfall's steps are categories (Opening, Sales, …) (#1070).
105
105
  type === "waterfall" ||
106
+ // A box & whisker's slots are categories (or the series names) (#1092).
107
+ type === "boxplot" ||
106
108
  // Stock is line-derived on a category x-axis. Radar is polar and
107
109
  // does not use the cartesian x-axis.
108
110
  type === "stock") {
@@ -46,5 +46,11 @@ export declare const toPlotlyHierarchy: (rows: HierarchyRow[]) => PlotlyHierarch
46
46
  * Returns the colour per node of `toPlotlyHierarchy`'s flat arrays.
47
47
  */
48
48
  export declare const hierarchyNodeColors: (hierarchy: Pick<PlotlyHierarchy, "ids" | "parents">, palette: string[]) => string[];
49
+ /**
50
+ * Black or white, whichever reads on `background` (a `#rgb` / `#rrggbb`
51
+ * colour; anything else gets white) — for a treemap banner filled with
52
+ * its category's colour (rowsncolumns/spreadsheet#1086).
53
+ */
54
+ export declare const contrastTextColor: (background: string | undefined) => string;
49
55
  export {};
50
56
  //# sourceMappingURL=hierarchy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../utils/hierarchy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,CACf,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,KAClD,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,wBAAwB,EAAE,SAAS,CAAC;IACpC,wBAAwB,EAAE,SAAS,CAAC;IACpC,uBAAuB,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,CAAC;CAChE,CAAC;AA0CF,eAAO,MAAM,uBAAuB,GAClC,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,MAAM,GAAG,SAgBX,CAAC;AAyCF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,YAAY,EAiFd,CAAC;AAiDF,eAAO,MAAM,kBAAkB,GAAI,MAAM,YAAY,EAAE,KAAG,aAAa,EAmDtE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,4BAA4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oCAAoC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,YAAY,EAAE,KAAG,eAwBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,IAAI,CAAC,eAAe,EAAE,KAAK,GAAG,SAAS,CAAC,EACnD,SAAS,MAAM,EAAE,KAChB,MAAM,EAYR,CAAC"}
1
+ {"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../utils/hierarchy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,CACf,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,KAClD,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,wBAAwB,EAAE,SAAS,CAAC;IACpC,wBAAwB,EAAE,SAAS,CAAC;IACpC,uBAAuB,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,CAAC;CAChE,CAAC;AA0CF,eAAO,MAAM,uBAAuB,GAClC,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,MAAM,GAAG,SAgBX,CAAC;AAyCF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,YAAY,EAiFd,CAAC;AAiDF,eAAO,MAAM,kBAAkB,GAAI,MAAM,YAAY,EAAE,KAAG,aAAa,EAmDtE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,4BAA4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oCAAoC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,YAAY,EAAE,KAAG,eAwBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,IAAI,CAAC,eAAe,EAAE,KAAK,GAAG,SAAS,CAAC,EACnD,SAAS,MAAM,EAAE,KAChB,MAAM,EAYR,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,GAAG,SAAS,KAAG,MAelE,CAAC"}
@@ -266,3 +266,24 @@ export const hierarchyNodeColors = (hierarchy, palette) => {
266
266
  return color;
267
267
  });
268
268
  };
269
+ /**
270
+ * Black or white, whichever reads on `background` (a `#rgb` / `#rrggbb`
271
+ * colour; anything else gets white) — for a treemap banner filled with
272
+ * its category's colour (rowsncolumns/spreadsheet#1086).
273
+ */
274
+ export const contrastTextColor = (background) => {
275
+ const hex = (background ?? "").trim().replace(/^#/, "");
276
+ const full = hex.length === 3
277
+ ? hex
278
+ .split("")
279
+ .map((c) => c + c)
280
+ .join("")
281
+ : hex;
282
+ if (!/^[0-9a-f]{6}$/i.test(full))
283
+ return "#ffffff";
284
+ const r = parseInt(full.slice(0, 2), 16);
285
+ const g = parseInt(full.slice(2, 4), 16);
286
+ const b = parseInt(full.slice(4, 6), 16);
287
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
288
+ return luminance > 0.6 ? "#000000" : "#ffffff";
289
+ };
@@ -39,8 +39,47 @@ export declare const isParetoSpec: (spec: {
39
39
  */
40
40
  export declare const computePareto: (bins: HistogramBins) => ParetoData;
41
41
  /**
42
- * Bin a set of numeric values into `binCount` equal-width bins.
43
- * When `binCount` is omitted, uses Sturges' rule: ceil(log2(n) + 1).
42
+ * Excel's `<cx:binning>` options (rowsncolumns/spreadsheet#1087). Any of
43
+ * them present switches the histogram to Excel's conventions: intervals
44
+ * closed on the right by default and automatic bins by Excel's rule.
44
45
  */
45
- export declare const binHistogram: (values: (number | null | undefined)[], binCount?: number | null) => HistogramBins;
46
+ export type HistogramBinningOptions = {
47
+ /** Fixed bin width (`<cx:binSize>`); wins over `binCount`. */
48
+ binSize?: number | null;
49
+ /** Which side of an interval is closed (`intervalClosed`); Excel's default is `r`. */
50
+ intervalClosed?: "l" | "r" | null;
51
+ /** Values above this collect in a final `> overflow` bin. */
52
+ overflow?: number | null;
53
+ /** Values below this collect in a first `< underflow` bin. */
54
+ underflow?: number | null;
55
+ };
56
+ /** True when the spec authored any Excel binning option. */
57
+ export declare const hasExcelBinning: (options: HistogramBinningOptions | null | undefined) => boolean;
58
+ /**
59
+ * Excel's automatic bin width: Scott's normal reference rule,
60
+ * 3.5 · σ / ∛n with the sample standard deviation, rounded up to two
61
+ * significant digits. For the 20 values 12 … 95 of #1087 (σ ≈ 23.86) that
62
+ * is 30.77 → 31, i.e. Excel's three bins [12, 43], (43, 74], (74, 105].
63
+ */
64
+ export declare const excelAutoBinWidth: (numeric: number[]) => number;
65
+ /**
66
+ * Bin a set of numeric values into equal-width bins.
67
+ *
68
+ * Default (no Excel options): `binCount` bins over [min, max], closed on
69
+ * the left — or Sturges' rule, ceil(log2(n) + 1), when `binCount` is
70
+ * omitted. With Excel binning options (#1087): bins start at the minimum
71
+ * (or the underflow bound), are `binSize` wide — else (max − min) /
72
+ * `binCount`, else Excel's automatic width — closed on the right unless
73
+ * `intervalClosed` is `l`, and values beyond `overflow` / `underflow`
74
+ * collect in their own end bins.
75
+ */
76
+ export declare const binHistogram: (values: (number | null | undefined)[], binCount?: number | null, options?: HistogramBinningOptions | null) => HistogramBins;
77
+ export type HistogramAggregateType = "SUM" | "AVERAGE" | "COUNT" | "MAX" | "MIN" | "MEDIAN";
78
+ /**
79
+ * Excel's histogram "By Category" / Pareto over categories
80
+ * (`<cx:aggregation/>`, #1087): one column per distinct category in order
81
+ * of first appearance, its value the aggregate (sum by default) of the
82
+ * series values of that category — instead of binning the values.
83
+ */
84
+ export declare const aggregateByCategory: (categories: (string | number | null | undefined)[], values: (number | null | undefined)[], aggregateType?: HistogramAggregateType | null | undefined) => HistogramBins;
46
85
  //# sourceMappingURL=histogram.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"histogram.d.ts","sourceRoot":"","sources":["../../../utils/histogram.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,gDAAgD;IAChD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,KAAG,OAGgD,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,aAAa,KAAG,UAmBnD,CAAC;AASF;;;GAGG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,WAAW,MAAM,GAAG,IAAI,KACvB,aA0CF,CAAC"}
1
+ {"version":3,"file":"histogram.d.ts","sourceRoot":"","sources":["../../../utils/histogram.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,gDAAgD;IAChD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,KAAG,OAGgD,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,aAAa,KAAG,UAmBnD,CAAC;AAUF;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sFAAsF;IACtF,cAAc,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAKF,4DAA4D;AAC5D,eAAO,MAAM,eAAe,GAC1B,SAAS,uBAAuB,GAAG,IAAI,GAAG,SAAS,KAClD,OAQA,CAAC;AASJ;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,KAAG,MASrD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,WAAW,MAAM,GAAG,IAAI,EACxB,UAAU,uBAAuB,GAAG,IAAI,KACvC,aA4CF,CAAC;AAiFF,MAAM,MAAM,sBAAsB,GAC9B,KAAK,GACL,SAAS,GACT,OAAO,GACP,KAAK,GACL,KAAK,GACL,QAAQ,CAAC;AAEb;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC9B,YAAY,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EAClD,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,gBAAe,sBAAsB,GAAG,IAAI,GAAG,SAAiB,KAC/D,aA0CF,CAAC"}
@@ -45,17 +45,58 @@ export const computePareto = (bins) => {
45
45
  const formatBinBound = (value) => {
46
46
  if (!Number.isFinite(value))
47
47
  return String(value);
48
+ if (value === 0)
49
+ return "0";
48
50
  const abs = Math.abs(value);
49
51
  if (abs >= 1000 || abs < 0.01)
50
52
  return value.toExponential(2);
51
53
  return Number.parseFloat(value.toFixed(2)).toString();
52
54
  };
55
+ const isFinite_ = (v) => typeof v === "number" && Number.isFinite(v);
56
+ /** True when the spec authored any Excel binning option. */
57
+ export const hasExcelBinning = (options) => Boolean(options &&
58
+ (isFinite_(options.binSize) ||
59
+ options.intervalClosed === "l" ||
60
+ options.intervalClosed === "r" ||
61
+ isFinite_(options.overflow) ||
62
+ isFinite_(options.underflow)));
63
+ /** Round up to two significant digits (31 for 30.77, 0.038 for 0.0377). */
64
+ const ceilToTwoSignificant = (value) => {
65
+ if (!(value > 0))
66
+ return value;
67
+ const magnitude = 10 ** (Math.floor(Math.log10(value)) - 1);
68
+ return Math.ceil(value / magnitude - 1e-9) * magnitude;
69
+ };
70
+ /**
71
+ * Excel's automatic bin width: Scott's normal reference rule,
72
+ * 3.5 · σ / ∛n with the sample standard deviation, rounded up to two
73
+ * significant digits. For the 20 values 12 … 95 of #1087 (σ ≈ 23.86) that
74
+ * is 30.77 → 31, i.e. Excel's three bins [12, 43], (43, 74], (74, 105].
75
+ */
76
+ export const excelAutoBinWidth = (numeric) => {
77
+ const n = numeric.length;
78
+ if (n < 2)
79
+ return 1;
80
+ const mean = numeric.reduce((sum, v) => sum + v, 0) / n;
81
+ const variance = numeric.reduce((sum, v) => sum + (v - mean) ** 2, 0) / (n - 1);
82
+ const sigma = Math.sqrt(variance);
83
+ if (!(sigma > 0))
84
+ return 1;
85
+ return ceilToTwoSignificant((3.5 * sigma) / Math.cbrt(n));
86
+ };
53
87
  /**
54
- * Bin a set of numeric values into `binCount` equal-width bins.
55
- * When `binCount` is omitted, uses Sturges' rule: ceil(log2(n) + 1).
88
+ * Bin a set of numeric values into equal-width bins.
89
+ *
90
+ * Default (no Excel options): `binCount` bins over [min, max], closed on
91
+ * the left — or Sturges' rule, ceil(log2(n) + 1), when `binCount` is
92
+ * omitted. With Excel binning options (#1087): bins start at the minimum
93
+ * (or the underflow bound), are `binSize` wide — else (max − min) /
94
+ * `binCount`, else Excel's automatic width — closed on the right unless
95
+ * `intervalClosed` is `l`, and values beyond `overflow` / `underflow`
96
+ * collect in their own end bins.
56
97
  */
57
- export const binHistogram = (values, binCount) => {
58
- const numeric = values.filter((v) => typeof v === "number" && Number.isFinite(v));
98
+ export const binHistogram = (values, binCount, options) => {
99
+ const numeric = values.filter(isFinite_);
59
100
  if (numeric.length === 0) {
60
101
  return { labels: [], counts: [] };
61
102
  }
@@ -67,6 +108,9 @@ export const binHistogram = (values, binCount) => {
67
108
  if (v > max)
68
109
  max = v;
69
110
  }
111
+ if (hasExcelBinning(options)) {
112
+ return binExcel(numeric, min, max, binCount, options);
113
+ }
70
114
  const sturges = Math.max(1, Math.ceil(Math.log2(numeric.length) + 1));
71
115
  const bins = typeof binCount === "number" && binCount > 0
72
116
  ? Math.floor(binCount)
@@ -93,3 +137,126 @@ export const binHistogram = (values, binCount) => {
93
137
  }
94
138
  return { labels, counts };
95
139
  };
140
+ const binExcel = (numeric, min, max, binCount, options) => {
141
+ const rightClosed = options.intervalClosed !== "l";
142
+ const underflow = isFinite_(options.underflow) ? options.underflow : null;
143
+ const overflow = isFinite_(options.overflow) ? options.overflow : null;
144
+ // The regular bins span the values between the end bins.
145
+ const inRange = numeric.filter((v) => (underflow === null || v >= underflow) &&
146
+ (overflow === null || v <= overflow));
147
+ const start = underflow ?? (inRange.length ? Math.min(...inRange) : min);
148
+ const end = overflow ?? (inRange.length ? Math.max(...inRange) : max);
149
+ const span = end - start;
150
+ let width;
151
+ if (isFinite_(options.binSize) && options.binSize > 0) {
152
+ width = options.binSize;
153
+ }
154
+ else if (typeof binCount === "number" && binCount > 0) {
155
+ width = span > 0 ? span / Math.floor(binCount) : 1;
156
+ }
157
+ else {
158
+ width = excelAutoBinWidth(inRange.length ? inRange : numeric);
159
+ }
160
+ // Enough bins to reach the last value; a right-closed layout needs one
161
+ // more when the span is an exact multiple (the boundary value belongs to
162
+ // the bin below, so the top bin stays).
163
+ let bins = span > 0 ? Math.ceil(span / width - 1e-9) : 1;
164
+ bins = Math.max(1, bins);
165
+ const counts = new Array(bins).fill(0);
166
+ const edges = Array.from({ length: bins + 1 }, (_, i) => start + width * i);
167
+ let under = 0;
168
+ let over = 0;
169
+ for (const v of numeric) {
170
+ if (underflow !== null && v < underflow) {
171
+ under++;
172
+ continue;
173
+ }
174
+ if (overflow !== null && v > overflow) {
175
+ over++;
176
+ continue;
177
+ }
178
+ let idx;
179
+ if (rightClosed) {
180
+ // (lo, hi]: a value on a boundary belongs to the bin below it; the
181
+ // first bin also takes its own lower bound.
182
+ idx = Math.ceil((v - start) / width - 1e-9) - 1;
183
+ if (idx < 0)
184
+ idx = 0;
185
+ }
186
+ else {
187
+ idx = Math.floor((v - start) / width + 1e-9);
188
+ }
189
+ if (idx >= bins)
190
+ idx = bins - 1;
191
+ counts[idx]++;
192
+ }
193
+ const labels = edges.slice(0, -1).map((lo, i) => {
194
+ const hi = edges[i + 1];
195
+ if (rightClosed) {
196
+ const opening = i === 0 ? "[" : "(";
197
+ return `${opening}${formatBinBound(lo)}, ${formatBinBound(hi)}]`;
198
+ }
199
+ const closing = i === bins - 1 ? "]" : ")";
200
+ return `[${formatBinBound(lo)}, ${formatBinBound(hi)}${closing}`;
201
+ });
202
+ if (underflow !== null) {
203
+ labels.unshift(`< ${formatBinBound(underflow)}`);
204
+ counts.unshift(under);
205
+ }
206
+ if (overflow !== null) {
207
+ labels.push(`> ${formatBinBound(overflow)}`);
208
+ counts.push(over);
209
+ }
210
+ return { labels, counts };
211
+ };
212
+ /**
213
+ * Excel's histogram "By Category" / Pareto over categories
214
+ * (`<cx:aggregation/>`, #1087): one column per distinct category in order
215
+ * of first appearance, its value the aggregate (sum by default) of the
216
+ * series values of that category — instead of binning the values.
217
+ */
218
+ export const aggregateByCategory = (categories, values, aggregateType = "SUM") => {
219
+ const groups = new Map();
220
+ const order = [];
221
+ const count = Math.max(categories.length, values.length);
222
+ for (let i = 0; i < count; i++) {
223
+ const raw = categories[i];
224
+ const label = raw === null || raw === undefined ? "" : `${raw}`.trim();
225
+ if (label === "")
226
+ continue;
227
+ if (!groups.has(label)) {
228
+ groups.set(label, []);
229
+ order.push(label);
230
+ }
231
+ const v = values[i];
232
+ if (isFinite_(v))
233
+ groups.get(label).push(v);
234
+ }
235
+ const reduce = (nums) => {
236
+ if (nums.length === 0)
237
+ return 0;
238
+ switch (aggregateType ?? "SUM") {
239
+ case "COUNT":
240
+ return nums.length;
241
+ case "AVERAGE":
242
+ return nums.reduce((a, b) => a + b, 0) / nums.length;
243
+ case "MAX":
244
+ return Math.max(...nums);
245
+ case "MIN":
246
+ return Math.min(...nums);
247
+ case "MEDIAN": {
248
+ const sorted = [...nums].sort((a, b) => a - b);
249
+ const mid = Math.floor(sorted.length / 2);
250
+ return sorted.length % 2
251
+ ? sorted[mid]
252
+ : (sorted[mid - 1] + sorted[mid]) / 2;
253
+ }
254
+ default:
255
+ return nums.reduce((a, b) => a + b, 0);
256
+ }
257
+ };
258
+ return {
259
+ labels: order,
260
+ counts: order.map((label) => reduce(groups.get(label) ?? [])),
261
+ };
262
+ };
@@ -8,7 +8,7 @@ export declare const applyLegendOverrides: (legend: LegendComponentOption, opts:
8
8
  * becomes the tick-label formatter.
9
9
  */
10
10
  export declare const applyAxisOverrides: (axis: any, opts: any, numberFormatPattern?: string, locale?: string) => any;
11
- export declare const dataLabelFormatter: (opts: any, locale?: string) => (params: any) => string;
11
+ export declare const dataLabelFormatter: (opts: any, locale?: string, joiner?: string) => (params: any) => string;
12
12
  /**
13
13
  * The data-label options one series renders with: its own
14
14
  * `ChartData.dataLabels` when it has them (OOXML's `<c:ser><c:dLbls>`
@@ -1 +1 @@
1
- {"version":3,"file":"overrides.d.ts","sourceRoot":"","sources":["../../../utils/overrides.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAWrD,oEAAoE;AACpE,eAAO,MAAM,4BAA4B,GAAI,KAAK,GAAG,oCASpD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,qBAAqB,EAC7B,MAAM,GAAG,KACR,qBA6CF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,GAAG,EACT,MAAM,GAAG,EACT,sBAAsB,MAAM,EAC5B,SAAS,MAAM,QA4BhB,CAAC;AAgBF,eAAO,MAAM,kBAAkB,GAAI,MAAM,GAAG,EAAE,SAAS,MAAM,MAAM,QAAQ,GAAG,WAoD7E,CAAC;AAgCF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,CAAC,EACvC,YAAY,CAAC,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,KACnD,CAAC,GAAG,IAAI,GAAG,SAA6C,CAAC;AAE5D,eAAO,MAAM,sBAAsB,GACjC,MAAM,GAAG,EACT,aAAa,MAAM,EACnB,SAAS,MAAM;;;iCAlG0D,GAAG;aA+G7E,CAAC"}
1
+ {"version":3,"file":"overrides.d.ts","sourceRoot":"","sources":["../../../utils/overrides.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAWrD,oEAAoE;AACpE,eAAO,MAAM,4BAA4B,GAAI,KAAK,GAAG,oCASpD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,qBAAqB,EAC7B,MAAM,GAAG,KACR,qBA6CF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,GAAG,EACT,MAAM,GAAG,EACT,sBAAsB,MAAM,EAC5B,SAAS,MAAM,QA4BhB,CAAC;AAgBF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,GAAG,EACT,SAAS,MAAM,EAEf,eAAa,MACT,QAAQ,GAAG,WAoDhB,CAAC;AAgCF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,CAAC,EACvC,YAAY,CAAC,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,KACnD,CAAC,GAAG,IAAI,GAAG,SAA6C,CAAC;AAE5D,eAAO,MAAM,sBAAsB,GACjC,MAAM,GAAG,EACT,aAAa,MAAM,EACnB,SAAS,MAAM;;;iCAlGH,GAAG;aA+GhB,CAAC"}