@rowsncolumns/charts 28.1.10 → 28.1.12

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.
@@ -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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hierarchyNodeColors = exports.toPlotlyHierarchy = exports.buildHierarchyTree = exports.extractHierarchyRows = exports.getHierarchyHeaderTitle = void 0;
3
+ exports.contrastTextColor = exports.hierarchyNodeColors = exports.toPlotlyHierarchy = exports.buildHierarchyTree = exports.extractHierarchyRows = exports.getHierarchyHeaderTitle = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var flattenChartData = function (chartData, extractor, hiddenStrategy, skipFirstRow) {
6
6
  if (skipFirstRow === void 0) { skipFirstRow = false; }
@@ -308,3 +308,25 @@ var hierarchyNodeColors = function (hierarchy, palette) {
308
308
  });
309
309
  };
310
310
  exports.hierarchyNodeColors = hierarchyNodeColors;
311
+ /**
312
+ * Black or white, whichever reads on `background` (a `#rgb` / `#rrggbb`
313
+ * colour; anything else gets white) — for a treemap banner filled with
314
+ * its category's colour (rowsncolumns/spreadsheet#1086).
315
+ */
316
+ var contrastTextColor = function (background) {
317
+ var hex = (background !== null && background !== void 0 ? background : "").trim().replace(/^#/, "");
318
+ var full = hex.length === 3
319
+ ? hex
320
+ .split("")
321
+ .map(function (c) { return c + c; })
322
+ .join("")
323
+ : hex;
324
+ if (!/^[0-9a-f]{6}$/i.test(full))
325
+ return "#ffffff";
326
+ var r = parseInt(full.slice(0, 2), 16);
327
+ var g = parseInt(full.slice(2, 4), 16);
328
+ var b = parseInt(full.slice(4, 6), 16);
329
+ var luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
330
+ return luminance > 0.6 ? "#000000" : "#ffffff";
331
+ };
332
+ exports.contrastTextColor = contrastTextColor;
@@ -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"}
@@ -7,7 +7,7 @@
7
7
  * here and emits a bar series with the bin labels as the x-axis category.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.binHistogram = exports.computePareto = exports.isParetoSpec = void 0;
10
+ exports.aggregateByCategory = exports.binHistogram = exports.excelAutoBinWidth = exports.hasExcelBinning = exports.computePareto = exports.isParetoSpec = void 0;
11
11
  var tslib_1 = require("tslib");
12
12
  /**
13
13
  * True when a chart spec should render as a Pareto chart: either a
@@ -53,18 +53,65 @@ exports.computePareto = computePareto;
53
53
  var formatBinBound = function (value) {
54
54
  if (!Number.isFinite(value))
55
55
  return String(value);
56
+ if (value === 0)
57
+ return "0";
56
58
  var abs = Math.abs(value);
57
59
  if (abs >= 1000 || abs < 0.01)
58
60
  return value.toExponential(2);
59
61
  return Number.parseFloat(value.toFixed(2)).toString();
60
62
  };
63
+ var isFinite_ = function (v) {
64
+ return typeof v === "number" && Number.isFinite(v);
65
+ };
66
+ /** True when the spec authored any Excel binning option. */
67
+ var hasExcelBinning = function (options) {
68
+ return Boolean(options &&
69
+ (isFinite_(options.binSize) ||
70
+ options.intervalClosed === "l" ||
71
+ options.intervalClosed === "r" ||
72
+ isFinite_(options.overflow) ||
73
+ isFinite_(options.underflow)));
74
+ };
75
+ exports.hasExcelBinning = hasExcelBinning;
76
+ /** Round up to two significant digits (31 for 30.77, 0.038 for 0.0377). */
77
+ var ceilToTwoSignificant = function (value) {
78
+ if (!(value > 0))
79
+ return value;
80
+ var magnitude = Math.pow(10, (Math.floor(Math.log10(value)) - 1));
81
+ return Math.ceil(value / magnitude - 1e-9) * magnitude;
82
+ };
61
83
  /**
62
- * Bin a set of numeric values into `binCount` equal-width bins.
63
- * When `binCount` is omitted, uses Sturges' rule: ceil(log2(n) + 1).
84
+ * Excel's automatic bin width: Scott's normal reference rule,
85
+ * 3.5 · σ / ∛n with the sample standard deviation, rounded up to two
86
+ * significant digits. For the 20 values 12 … 95 of #1087 (σ ≈ 23.86) that
87
+ * is 30.77 → 31, i.e. Excel's three bins [12, 43], (43, 74], (74, 105].
64
88
  */
65
- var binHistogram = function (values, binCount) {
89
+ var excelAutoBinWidth = function (numeric) {
90
+ var n = numeric.length;
91
+ if (n < 2)
92
+ return 1;
93
+ var mean = numeric.reduce(function (sum, v) { return sum + v; }, 0) / n;
94
+ var variance = numeric.reduce(function (sum, v) { return sum + Math.pow((v - mean), 2); }, 0) / (n - 1);
95
+ var sigma = Math.sqrt(variance);
96
+ if (!(sigma > 0))
97
+ return 1;
98
+ return ceilToTwoSignificant((3.5 * sigma) / Math.cbrt(n));
99
+ };
100
+ exports.excelAutoBinWidth = excelAutoBinWidth;
101
+ /**
102
+ * Bin a set of numeric values into equal-width bins.
103
+ *
104
+ * Default (no Excel options): `binCount` bins over [min, max], closed on
105
+ * the left — or Sturges' rule, ceil(log2(n) + 1), when `binCount` is
106
+ * omitted. With Excel binning options (#1087): bins start at the minimum
107
+ * (or the underflow bound), are `binSize` wide — else (max − min) /
108
+ * `binCount`, else Excel's automatic width — closed on the right unless
109
+ * `intervalClosed` is `l`, and values beyond `overflow` / `underflow`
110
+ * collect in their own end bins.
111
+ */
112
+ var binHistogram = function (values, binCount, options) {
66
113
  var e_1, _a, e_2, _b;
67
- var numeric = values.filter(function (v) { return typeof v === "number" && Number.isFinite(v); });
114
+ var numeric = values.filter(isFinite_);
68
115
  if (numeric.length === 0) {
69
116
  return { labels: [], counts: [] };
70
117
  }
@@ -86,6 +133,9 @@ var binHistogram = function (values, binCount) {
86
133
  }
87
134
  finally { if (e_1) throw e_1.error; }
88
135
  }
136
+ if ((0, exports.hasExcelBinning)(options)) {
137
+ return binExcel(numeric, min, max, binCount, options);
138
+ }
89
139
  var sturges = Math.max(1, Math.ceil(Math.log2(numeric.length) + 1));
90
140
  var bins = typeof binCount === "number" && binCount > 0
91
141
  ? Math.floor(binCount)
@@ -123,3 +173,141 @@ var binHistogram = function (values, binCount) {
123
173
  return { labels: labels, counts: counts };
124
174
  };
125
175
  exports.binHistogram = binHistogram;
176
+ var binExcel = function (numeric, min, max, binCount, options) {
177
+ var e_3, _a;
178
+ var rightClosed = options.intervalClosed !== "l";
179
+ var underflow = isFinite_(options.underflow) ? options.underflow : null;
180
+ var overflow = isFinite_(options.overflow) ? options.overflow : null;
181
+ // The regular bins span the values between the end bins.
182
+ var inRange = numeric.filter(function (v) {
183
+ return (underflow === null || v >= underflow) &&
184
+ (overflow === null || v <= overflow);
185
+ });
186
+ var start = underflow !== null && underflow !== void 0 ? underflow : (inRange.length ? Math.min.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(inRange), false)) : min);
187
+ var end = overflow !== null && overflow !== void 0 ? overflow : (inRange.length ? Math.max.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(inRange), false)) : max);
188
+ var span = end - start;
189
+ var width;
190
+ if (isFinite_(options.binSize) && options.binSize > 0) {
191
+ width = options.binSize;
192
+ }
193
+ else if (typeof binCount === "number" && binCount > 0) {
194
+ width = span > 0 ? span / Math.floor(binCount) : 1;
195
+ }
196
+ else {
197
+ width = (0, exports.excelAutoBinWidth)(inRange.length ? inRange : numeric);
198
+ }
199
+ // Enough bins to reach the last value; a right-closed layout needs one
200
+ // more when the span is an exact multiple (the boundary value belongs to
201
+ // the bin below, so the top bin stays).
202
+ var bins = span > 0 ? Math.ceil(span / width - 1e-9) : 1;
203
+ bins = Math.max(1, bins);
204
+ var counts = new Array(bins).fill(0);
205
+ var edges = Array.from({ length: bins + 1 }, function (_, i) { return start + width * i; });
206
+ var under = 0;
207
+ var over = 0;
208
+ try {
209
+ for (var numeric_3 = tslib_1.__values(numeric), numeric_3_1 = numeric_3.next(); !numeric_3_1.done; numeric_3_1 = numeric_3.next()) {
210
+ var v = numeric_3_1.value;
211
+ if (underflow !== null && v < underflow) {
212
+ under++;
213
+ continue;
214
+ }
215
+ if (overflow !== null && v > overflow) {
216
+ over++;
217
+ continue;
218
+ }
219
+ var idx = void 0;
220
+ if (rightClosed) {
221
+ // (lo, hi]: a value on a boundary belongs to the bin below it; the
222
+ // first bin also takes its own lower bound.
223
+ idx = Math.ceil((v - start) / width - 1e-9) - 1;
224
+ if (idx < 0)
225
+ idx = 0;
226
+ }
227
+ else {
228
+ idx = Math.floor((v - start) / width + 1e-9);
229
+ }
230
+ if (idx >= bins)
231
+ idx = bins - 1;
232
+ counts[idx]++;
233
+ }
234
+ }
235
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
236
+ finally {
237
+ try {
238
+ if (numeric_3_1 && !numeric_3_1.done && (_a = numeric_3.return)) _a.call(numeric_3);
239
+ }
240
+ finally { if (e_3) throw e_3.error; }
241
+ }
242
+ var labels = edges.slice(0, -1).map(function (lo, i) {
243
+ var hi = edges[i + 1];
244
+ if (rightClosed) {
245
+ var opening = i === 0 ? "[" : "(";
246
+ return "".concat(opening).concat(formatBinBound(lo), ", ").concat(formatBinBound(hi), "]");
247
+ }
248
+ var closing = i === bins - 1 ? "]" : ")";
249
+ return "[".concat(formatBinBound(lo), ", ").concat(formatBinBound(hi)).concat(closing);
250
+ });
251
+ if (underflow !== null) {
252
+ labels.unshift("< ".concat(formatBinBound(underflow)));
253
+ counts.unshift(under);
254
+ }
255
+ if (overflow !== null) {
256
+ labels.push("> ".concat(formatBinBound(overflow)));
257
+ counts.push(over);
258
+ }
259
+ return { labels: labels, counts: counts };
260
+ };
261
+ /**
262
+ * Excel's histogram "By Category" / Pareto over categories
263
+ * (`<cx:aggregation/>`, #1087): one column per distinct category in order
264
+ * of first appearance, its value the aggregate (sum by default) of the
265
+ * series values of that category — instead of binning the values.
266
+ */
267
+ var aggregateByCategory = function (categories, values, aggregateType) {
268
+ if (aggregateType === void 0) { aggregateType = "SUM"; }
269
+ var groups = new Map();
270
+ var order = [];
271
+ var count = Math.max(categories.length, values.length);
272
+ for (var i = 0; i < count; i++) {
273
+ var raw = categories[i];
274
+ var label = raw === null || raw === undefined ? "" : "".concat(raw).trim();
275
+ if (label === "")
276
+ continue;
277
+ if (!groups.has(label)) {
278
+ groups.set(label, []);
279
+ order.push(label);
280
+ }
281
+ var v = values[i];
282
+ if (isFinite_(v))
283
+ groups.get(label).push(v);
284
+ }
285
+ var reduce = function (nums) {
286
+ if (nums.length === 0)
287
+ return 0;
288
+ switch (aggregateType !== null && aggregateType !== void 0 ? aggregateType : "SUM") {
289
+ case "COUNT":
290
+ return nums.length;
291
+ case "AVERAGE":
292
+ return nums.reduce(function (a, b) { return a + b; }, 0) / nums.length;
293
+ case "MAX":
294
+ return Math.max.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(nums), false));
295
+ case "MIN":
296
+ return Math.min.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(nums), false));
297
+ case "MEDIAN": {
298
+ var sorted = tslib_1.__spreadArray([], tslib_1.__read(nums), false).sort(function (a, b) { return a - b; });
299
+ var mid = Math.floor(sorted.length / 2);
300
+ return sorted.length % 2
301
+ ? sorted[mid]
302
+ : (sorted[mid - 1] + sorted[mid]) / 2;
303
+ }
304
+ default:
305
+ return nums.reduce(function (a, b) { return a + b; }, 0);
306
+ }
307
+ };
308
+ return {
309
+ labels: order,
310
+ counts: order.map(function (label) { var _a; return reduce((_a = groups.get(label)) !== null && _a !== void 0 ? _a : []); }),
311
+ };
312
+ };
313
+ exports.aggregateByCategory = aggregateByCategory;
@@ -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,WA+C7E,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;;;iCA7F0D,GAAG;aA0G7E,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"}
@@ -126,40 +126,50 @@ exports.applyAxisOverrides = applyAxisOverrides;
126
126
  * — Excel's behaviour.
127
127
  */
128
128
  var formatLabelValue = function (rawValue, originalValue, pattern, locale) { return (0, axis_number_format_1.formatAxisValue)(pattern, originalValue !== null && originalValue !== void 0 ? originalValue : rawValue, locale); };
129
- var dataLabelFormatter = function (opts, locale) { return function (params) {
130
- var parts = [];
131
- if (opts.showSeriesName && params.seriesName)
132
- parts.push(params.seriesName);
133
- if (opts.showCategoryName && params.name)
134
- parts.push(params.name);
135
- if (opts.showPercent && params.percent !== undefined) {
136
- parts.push("".concat(params.percent, "%"));
137
- }
138
- var showVal = opts.showValue !== false &&
139
- !opts.showCategoryName &&
140
- !opts.showPercent &&
141
- !opts.showSeriesName
142
- ? true
143
- : !!opts.showValue;
144
- // A scatter / bubble point's value is its [x, y, size] tuple: the label's
145
- // value is Y and the bubble size is the third entry (#1068).
146
- var isPointTuple = Array.isArray(params.value);
147
- var pointValue = isPointTuple ? params.value[1] : params.value;
148
- if (showVal && pointValue !== undefined) {
149
- // PERCENT_STACKED stores the raw value on the data object so the
150
- // label can still surface the dollar amount instead of the
151
- // normalized percentage. Plain stacked / clustered have just a
152
- // scalar `value`.
153
- var originalValue = typeof params.data === "object" && params.data
154
- ? params.data.originalValue
155
- : undefined;
156
- parts.push(formatLabelValue(pointValue, originalValue, opts.numberFormatPattern, locale));
157
- }
158
- if (opts.showBubbleSize && isPointTuple && params.value.length > 2) {
159
- parts.push(formatLabelValue(params.value[2], undefined, opts.numberFormatPattern, locale));
160
- }
161
- return parts.join(": ");
162
- }; };
129
+ var dataLabelFormatter = function (opts, locale,
130
+ // A treemap block stacks the parts (name, value) on their own lines.
131
+ joiner) {
132
+ if (joiner === void 0) { joiner = ": "; }
133
+ return function (params) {
134
+ var parts = [];
135
+ if (opts.showSeriesName && params.seriesName)
136
+ parts.push(params.seriesName);
137
+ if (opts.showCategoryName && params.name)
138
+ parts.push(params.name);
139
+ if (opts.showPercent && params.percent !== undefined) {
140
+ parts.push("".concat(params.percent, "%"));
141
+ }
142
+ // The value shows by default unless another field was asked for instead:
143
+ // an importer records only the flags that are ON, so `<c:showVal val="0"/>`
144
+ // + `<c:showBubbleSize val="1"/>` arrives as `{ showBubbleSize: true }` and
145
+ // must label the bubble with its size alone (#1068 / #1079).
146
+ var showVal = opts.showValue !== false &&
147
+ !opts.showCategoryName &&
148
+ !opts.showPercent &&
149
+ !opts.showSeriesName &&
150
+ !opts.showBubbleSize
151
+ ? true
152
+ : !!opts.showValue;
153
+ // A scatter / bubble point's value is its [x, y, size] tuple: the label's
154
+ // value is Y and the bubble size is the third entry (#1068).
155
+ var isPointTuple = Array.isArray(params.value);
156
+ var pointValue = isPointTuple ? params.value[1] : params.value;
157
+ if (showVal && pointValue !== undefined) {
158
+ // PERCENT_STACKED stores the raw value on the data object so the
159
+ // label can still surface the dollar amount instead of the
160
+ // normalized percentage. Plain stacked / clustered have just a
161
+ // scalar `value`.
162
+ var originalValue = typeof params.data === "object" && params.data
163
+ ? params.data.originalValue
164
+ : undefined;
165
+ parts.push(formatLabelValue(pointValue, originalValue, opts.numberFormatPattern, locale));
166
+ }
167
+ if (opts.showBubbleSize && isPointTuple && params.value.length > 2) {
168
+ parts.push(formatLabelValue(params.value[2], undefined, opts.numberFormatPattern, locale));
169
+ }
170
+ return parts.join(joiner);
171
+ };
172
+ };
163
173
  exports.dataLabelFormatter = dataLabelFormatter;
164
174
  var ECHARTS_DLBL_POS = {
165
175
  center: "inside",
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAkEA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmRrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAgFnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBA4+GjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAkEA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAsTrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAiGnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBA8kHjB,CAAC"}