@rowsncolumns/charts 28.0.0 → 28.1.0

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 (193) hide show
  1. package/dist/cjs/atoms/pivot-chart.atom.d.ts +14 -0
  2. package/dist/cjs/atoms/pivot-chart.atom.d.ts.map +1 -0
  3. package/dist/cjs/atoms/pivot-chart.atom.js +9 -0
  4. package/dist/cjs/basic-chart/basic-chart.d.ts +1 -1
  5. package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
  6. package/dist/cjs/basic-chart/basic-chart.js +863 -371
  7. package/dist/cjs/components/dialogs/pivot-chart-dialog.d.ts +39 -0
  8. package/dist/cjs/components/dialogs/pivot-chart-dialog.d.ts.map +1 -0
  9. package/dist/cjs/components/dialogs/pivot-chart-dialog.js +100 -0
  10. package/dist/cjs/components/editors/chart-editor.d.ts +13 -1
  11. package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
  12. package/dist/cjs/components/editors/chart-editor.js +225 -59
  13. package/dist/cjs/config.d.ts.map +1 -1
  14. package/dist/cjs/config.js +149 -12
  15. package/dist/cjs/hooks/use-charts.d.ts +21 -6
  16. package/dist/cjs/hooks/use-charts.d.ts.map +1 -1
  17. package/dist/cjs/hooks/use-charts.js +13 -1
  18. package/dist/cjs/hooks/use-on-create-chart.d.ts.map +1 -1
  19. package/dist/cjs/hooks/use-on-create-chart.js +7 -1
  20. package/dist/cjs/hooks/use-on-move-chart-to-sheet.d.ts +12 -0
  21. package/dist/cjs/hooks/use-on-move-chart-to-sheet.d.ts.map +1 -0
  22. package/dist/cjs/hooks/use-on-move-chart-to-sheet.js +26 -0
  23. package/dist/cjs/hooks/use-on-move-chart.d.ts +1 -1
  24. package/dist/cjs/hooks/use-on-move-chart.d.ts.map +1 -1
  25. package/dist/cjs/hooks/use-on-move-chart.js +2 -2
  26. package/dist/cjs/hooks/use-on-resize-chart.d.ts +1 -1
  27. package/dist/cjs/hooks/use-on-resize-chart.d.ts.map +1 -1
  28. package/dist/cjs/hooks/use-on-resize-chart.js +2 -2
  29. package/dist/cjs/index.d.ts +11 -0
  30. package/dist/cjs/index.d.ts.map +1 -1
  31. package/dist/cjs/index.js +34 -1
  32. package/dist/cjs/interface/create-chart.d.ts.map +1 -1
  33. package/dist/cjs/interface/create-chart.js +33 -42
  34. package/dist/cjs/interface/delete-chart.d.ts.map +1 -1
  35. package/dist/cjs/interface/delete-chart.js +4 -0
  36. package/dist/cjs/interface/move-chart-to-sheet.d.ts +13 -0
  37. package/dist/cjs/interface/move-chart-to-sheet.d.ts.map +1 -0
  38. package/dist/cjs/interface/move-chart-to-sheet.js +136 -0
  39. package/dist/cjs/interface/move-chart.d.ts +2 -2
  40. package/dist/cjs/interface/move-chart.d.ts.map +1 -1
  41. package/dist/cjs/interface/move-chart.js +7 -1
  42. package/dist/cjs/interface/resize-chart.d.ts +2 -2
  43. package/dist/cjs/interface/resize-chart.d.ts.map +1 -1
  44. package/dist/cjs/interface/resize-chart.js +7 -1
  45. package/dist/cjs/interface/update-chart.d.ts.map +1 -1
  46. package/dist/cjs/interface/update-chart.js +4 -0
  47. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts +1 -1
  48. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  49. package/dist/cjs/plotly/basic-chart/basic-chart.js +970 -585
  50. package/dist/cjs/plotly/basic-chart/helpers.d.ts.map +1 -1
  51. package/dist/cjs/plotly/basic-chart/helpers.js +3 -0
  52. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  53. package/dist/cjs/types.d.ts +7 -0
  54. package/dist/cjs/types.d.ts.map +1 -1
  55. package/dist/cjs/utils/axis-number-format.d.ts +69 -0
  56. package/dist/cjs/utils/axis-number-format.d.ts.map +1 -0
  57. package/dist/cjs/utils/axis-number-format.js +217 -0
  58. package/dist/cjs/utils/category-levels.d.ts +27 -0
  59. package/dist/cjs/utils/category-levels.d.ts.map +1 -0
  60. package/dist/cjs/utils/category-levels.js +80 -0
  61. package/dist/cjs/utils/chart-image.d.ts +8 -0
  62. package/dist/cjs/utils/chart-image.d.ts.map +1 -0
  63. package/dist/cjs/utils/chart-image.js +28 -0
  64. package/dist/cjs/utils/chart-orientation.d.ts +67 -0
  65. package/dist/cjs/utils/chart-orientation.d.ts.map +1 -0
  66. package/dist/cjs/utils/chart-orientation.js +265 -0
  67. package/dist/cjs/utils/chart-spec-utils.d.ts +3 -0
  68. package/dist/cjs/utils/chart-spec-utils.d.ts.map +1 -1
  69. package/dist/cjs/utils/chart-spec-utils.js +12 -4
  70. package/dist/cjs/utils/chart-styles.d.ts +75 -0
  71. package/dist/cjs/utils/chart-styles.d.ts.map +1 -0
  72. package/dist/cjs/utils/chart-styles.js +283 -0
  73. package/dist/cjs/utils/empty-cells.d.ts +30 -0
  74. package/dist/cjs/utils/empty-cells.d.ts.map +1 -0
  75. package/dist/cjs/utils/empty-cells.js +91 -0
  76. package/dist/cjs/utils/overrides.d.ts +6 -1
  77. package/dist/cjs/utils/overrides.d.ts.map +1 -1
  78. package/dist/cjs/utils/overrides.js +19 -7
  79. package/dist/cjs/utils/pie-explosion.d.ts +30 -0
  80. package/dist/cjs/utils/pie-explosion.d.ts.map +1 -0
  81. package/dist/cjs/utils/pie-explosion.js +55 -0
  82. package/dist/cjs/utils/plotly-click.d.ts +34 -0
  83. package/dist/cjs/utils/plotly-click.d.ts.map +1 -0
  84. package/dist/cjs/utils/plotly-click.js +49 -0
  85. package/dist/cjs/utils/plotly-surface.d.ts +14 -0
  86. package/dist/cjs/utils/plotly-surface.d.ts.map +1 -0
  87. package/dist/cjs/utils/plotly-surface.js +64 -0
  88. package/dist/cjs/utils/plotly-title.d.ts +12 -0
  89. package/dist/cjs/utils/plotly-title.d.ts.map +1 -0
  90. package/dist/cjs/utils/plotly-title.js +24 -0
  91. package/dist/cjs/utils/series-click.d.ts +39 -0
  92. package/dist/cjs/utils/series-click.d.ts.map +1 -0
  93. package/dist/cjs/utils/series-click.js +75 -0
  94. package/dist/cjs/utils/three-d.d.ts +17 -1
  95. package/dist/cjs/utils/three-d.d.ts.map +1 -1
  96. package/dist/cjs/utils/three-d.js +32 -4
  97. package/dist/esm/atoms/pivot-chart.atom.d.ts +14 -0
  98. package/dist/esm/atoms/pivot-chart.atom.d.ts.map +1 -0
  99. package/dist/esm/atoms/pivot-chart.atom.js +4 -0
  100. package/dist/esm/basic-chart/basic-chart.d.ts +1 -1
  101. package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
  102. package/dist/esm/basic-chart/basic-chart.js +680 -178
  103. package/dist/esm/components/dialogs/pivot-chart-dialog.d.ts +39 -0
  104. package/dist/esm/components/dialogs/pivot-chart-dialog.d.ts.map +1 -0
  105. package/dist/esm/components/dialogs/pivot-chart-dialog.js +89 -0
  106. package/dist/esm/components/editors/chart-editor.d.ts +13 -1
  107. package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
  108. package/dist/esm/components/editors/chart-editor.js +164 -20
  109. package/dist/esm/config.d.ts.map +1 -1
  110. package/dist/esm/config.js +149 -12
  111. package/dist/esm/hooks/use-charts.d.ts +21 -6
  112. package/dist/esm/hooks/use-charts.d.ts.map +1 -1
  113. package/dist/esm/hooks/use-charts.js +13 -1
  114. package/dist/esm/hooks/use-on-create-chart.d.ts.map +1 -1
  115. package/dist/esm/hooks/use-on-create-chart.js +7 -1
  116. package/dist/esm/hooks/use-on-move-chart-to-sheet.d.ts +12 -0
  117. package/dist/esm/hooks/use-on-move-chart-to-sheet.d.ts.map +1 -0
  118. package/dist/esm/hooks/use-on-move-chart-to-sheet.js +19 -0
  119. package/dist/esm/hooks/use-on-move-chart.d.ts +1 -1
  120. package/dist/esm/hooks/use-on-move-chart.d.ts.map +1 -1
  121. package/dist/esm/hooks/use-on-move-chart.js +2 -2
  122. package/dist/esm/hooks/use-on-resize-chart.d.ts +1 -1
  123. package/dist/esm/hooks/use-on-resize-chart.d.ts.map +1 -1
  124. package/dist/esm/hooks/use-on-resize-chart.js +2 -2
  125. package/dist/esm/index.d.ts +11 -0
  126. package/dist/esm/index.d.ts.map +1 -1
  127. package/dist/esm/index.js +14 -0
  128. package/dist/esm/interface/create-chart.d.ts.map +1 -1
  129. package/dist/esm/interface/create-chart.js +36 -58
  130. package/dist/esm/interface/delete-chart.d.ts.map +1 -1
  131. package/dist/esm/interface/delete-chart.js +4 -0
  132. package/dist/esm/interface/move-chart-to-sheet.d.ts +13 -0
  133. package/dist/esm/interface/move-chart-to-sheet.d.ts.map +1 -0
  134. package/dist/esm/interface/move-chart-to-sheet.js +126 -0
  135. package/dist/esm/interface/move-chart.d.ts +2 -2
  136. package/dist/esm/interface/move-chart.d.ts.map +1 -1
  137. package/dist/esm/interface/move-chart.js +7 -1
  138. package/dist/esm/interface/resize-chart.d.ts +2 -2
  139. package/dist/esm/interface/resize-chart.d.ts.map +1 -1
  140. package/dist/esm/interface/resize-chart.js +7 -1
  141. package/dist/esm/interface/update-chart.d.ts.map +1 -1
  142. package/dist/esm/interface/update-chart.js +4 -0
  143. package/dist/esm/plotly/basic-chart/basic-chart.d.ts +1 -1
  144. package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  145. package/dist/esm/plotly/basic-chart/basic-chart.js +858 -463
  146. package/dist/esm/plotly/basic-chart/helpers.d.ts.map +1 -1
  147. package/dist/esm/plotly/basic-chart/helpers.js +3 -0
  148. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  149. package/dist/esm/types.d.ts +7 -0
  150. package/dist/esm/types.d.ts.map +1 -1
  151. package/dist/esm/utils/axis-number-format.d.ts +69 -0
  152. package/dist/esm/utils/axis-number-format.d.ts.map +1 -0
  153. package/dist/esm/utils/axis-number-format.js +170 -0
  154. package/dist/esm/utils/category-levels.d.ts +27 -0
  155. package/dist/esm/utils/category-levels.d.ts.map +1 -0
  156. package/dist/esm/utils/category-levels.js +65 -0
  157. package/dist/esm/utils/chart-image.d.ts +8 -0
  158. package/dist/esm/utils/chart-image.d.ts.map +1 -0
  159. package/dist/esm/utils/chart-image.js +24 -0
  160. package/dist/esm/utils/chart-orientation.d.ts +67 -0
  161. package/dist/esm/utils/chart-orientation.d.ts.map +1 -0
  162. package/dist/esm/utils/chart-orientation.js +234 -0
  163. package/dist/esm/utils/chart-spec-utils.d.ts +3 -0
  164. package/dist/esm/utils/chart-spec-utils.d.ts.map +1 -1
  165. package/dist/esm/utils/chart-spec-utils.js +10 -2
  166. package/dist/esm/utils/chart-styles.d.ts +75 -0
  167. package/dist/esm/utils/chart-styles.d.ts.map +1 -0
  168. package/dist/esm/utils/chart-styles.js +357 -0
  169. package/dist/esm/utils/empty-cells.d.ts +30 -0
  170. package/dist/esm/utils/empty-cells.d.ts.map +1 -0
  171. package/dist/esm/utils/empty-cells.js +67 -0
  172. package/dist/esm/utils/overrides.d.ts +6 -1
  173. package/dist/esm/utils/overrides.d.ts.map +1 -1
  174. package/dist/esm/utils/overrides.js +14 -2
  175. package/dist/esm/utils/pie-explosion.d.ts +30 -0
  176. package/dist/esm/utils/pie-explosion.d.ts.map +1 -0
  177. package/dist/esm/utils/pie-explosion.js +43 -0
  178. package/dist/esm/utils/plotly-click.d.ts +34 -0
  179. package/dist/esm/utils/plotly-click.d.ts.map +1 -0
  180. package/dist/esm/utils/plotly-click.js +44 -0
  181. package/dist/esm/utils/plotly-surface.d.ts +14 -0
  182. package/dist/esm/utils/plotly-surface.d.ts.map +1 -0
  183. package/dist/esm/utils/plotly-surface.js +45 -0
  184. package/dist/esm/utils/plotly-title.d.ts +12 -0
  185. package/dist/esm/utils/plotly-title.d.ts.map +1 -0
  186. package/dist/esm/utils/plotly-title.js +20 -0
  187. package/dist/esm/utils/series-click.d.ts +39 -0
  188. package/dist/esm/utils/series-click.d.ts.map +1 -0
  189. package/dist/esm/utils/series-click.js +66 -0
  190. package/dist/esm/utils/three-d.d.ts +17 -1
  191. package/dist/esm/utils/three-d.d.ts.map +1 -1
  192. package/dist/esm/utils/three-d.js +29 -3
  193. package/package.json +10 -6
@@ -10,11 +10,22 @@ var utils_1 = require("@rowsncolumns/utils");
10
10
  var react_1 = tslib_1.__importStar(require("react"));
11
11
  var react_plotly_js_1 = tslib_1.__importDefault(require("react-plotly.js"));
12
12
  var aggregation_1 = require("../../utils/aggregation");
13
+ var axis_number_format_1 = require("../../utils/axis-number-format");
13
14
  var boxplot_1 = require("../../utils/boxplot");
14
15
  var bubble_1 = require("../../utils/bubble");
16
+ var chart_orientation_1 = require("../../utils/chart-orientation");
17
+ var chart_image_1 = require("../../utils/chart-image");
18
+ var chart_styles_1 = require("../../utils/chart-styles");
15
19
  var chart_spec_utils_1 = require("../../utils/chart-spec-utils");
20
+ var empty_cells_1 = require("../../utils/empty-cells");
16
21
  var error_bars_1 = require("../../utils/error-bars");
22
+ var category_levels_1 = require("../../utils/category-levels");
17
23
  var gradient_1 = require("../../utils/gradient");
24
+ var plotly_title_1 = require("../../utils/plotly-title");
25
+ var pie_explosion_1 = require("../../utils/pie-explosion");
26
+ var plotly_click_1 = require("../../utils/plotly-click");
27
+ var plotly_surface_1 = require("../../utils/plotly-surface");
28
+ var three_d_1 = require("../../utils/three-d");
18
29
  var hierarchy_1 = require("../../utils/hierarchy");
19
30
  var histogram_1 = require("../../utils/histogram");
20
31
  var of_pie_1 = require("../../utils/of-pie");
@@ -108,11 +119,21 @@ var applyLegendOverridesPlotly = function (legend, opts) {
108
119
  next.font = applyTextFormatToFont(next.font, opts.textFormat);
109
120
  return { legend: next, showlegend: true };
110
121
  };
111
- var applyAxisOverridesPlotly = function (axis, opts) {
122
+ /**
123
+ * `numberFormatPattern` is the axis' RESOLVED format (explicit pattern or
124
+ * the linked source-cell format). Plotly formats ticks AND hover values
125
+ * through the axis `tickformat` / prefix / suffix, so converting the
126
+ * pattern once covers both; patterns outside the d3 subset keep plotly's
127
+ * default labels.
128
+ */
129
+ var applyAxisOverridesPlotly = function (axis, opts, numberFormatPattern) {
112
130
  var _a, _b, _c, _d;
113
- if (!opts)
131
+ var ticks = (0, axis_number_format_1.numberFormatToPlotlyTicks)(numberFormatPattern);
132
+ if (!opts && !ticks)
114
133
  return axis;
115
- var next = tslib_1.__assign({}, (axis !== null && axis !== void 0 ? axis : {}));
134
+ var next = tslib_1.__assign(tslib_1.__assign({}, (axis !== null && axis !== void 0 ? axis : {})), (ticks !== null && ticks !== void 0 ? ticks : {}));
135
+ if (!opts)
136
+ return next;
116
137
  if (opts.logarithmic)
117
138
  next.type = "log";
118
139
  if (opts.reverse)
@@ -150,8 +171,8 @@ var PLOTLY_DLBL_POS_BAR = {
150
171
  outsideEnd: "outside",
151
172
  bestFit: "outside",
152
173
  };
153
- var applyDataLabelsToTracePlotly = function (trace, opts, chartType) {
154
- var _a;
174
+ var applyDataLabelsToTracePlotly = function (trace, opts, chartType, sourceNumberFormat) {
175
+ var _a, _b, _c;
155
176
  if (!(opts === null || opts === void 0 ? void 0 : opts.show))
156
177
  return trace;
157
178
  var next = tslib_1.__assign({}, trace);
@@ -169,18 +190,33 @@ var applyDataLabelsToTracePlotly = function (trace, opts, chartType) {
169
190
  parts.push("percent");
170
191
  next.textinfo = parts.length ? parts.join("+") : "value";
171
192
  next.textposition = position;
193
+ // Values format like their source cells (or the authored `<c:numFmt>`):
194
+ // plotly's own `%{value}` is a raw number, so the formatted strings
195
+ // ride on `text` and a `texttemplate` mirrors the textinfo parts.
196
+ var pattern_1 = (_b = opts.numberFormatPattern) !== null && _b !== void 0 ? _b : sourceNumberFormat;
197
+ if (pattern_1) {
198
+ var values = Array.isArray(next.values) ? next.values : [];
199
+ next.text = values.map(function (v) { return (0, axis_number_format_1.formatAxisValue)(pattern_1, v); });
200
+ next.texttemplate = next.textinfo
201
+ .split("+")
202
+ .map(function (part) { return (part === "value" ? "%{text}" : "%{".concat(part, "}")); })
203
+ .join("<br>");
204
+ }
172
205
  }
173
206
  else {
174
207
  // <c:dLbls><c:numFmt formatCode=…> — when authored, run each value
175
208
  // through the same numfmt grammar the spreadsheet uses (`"$"#,##0`
176
209
  // → `$1,831`). Plotly supports this natively via `texttemplate`
177
210
  // with the d3-format mini-language, but our patterns are
178
- // SpreadsheetML — easier to pre-format the strings.
179
- var pattern_1 = opts.numberFormatPattern;
180
- var yVals = Array.isArray(next.y) ? next.y : [];
181
- next.text = pattern_1
182
- ? yVals.map(function (v) { return (v === null || v === undefined ? "" : (0, utils_1.ssfFormat)(pattern_1, v)); })
183
- : next.y;
211
+ // SpreadsheetML — easier to pre-format the strings. Without an
212
+ // authored pattern the labels link to the source-cell format.
213
+ var pattern_2 = (_c = opts.numberFormatPattern) !== null && _c !== void 0 ? _c : sourceNumberFormat;
214
+ // Horizontal bars carry their values on `x`.
215
+ var values = next.orientation === "h" ? next.x : next.y;
216
+ var vals = Array.isArray(values) ? values : [];
217
+ next.text = pattern_2
218
+ ? vals.map(function (v) { return (v === null || v === undefined ? "" : (0, utils_1.ssfFormat)(pattern_2, v)); })
219
+ : values;
184
220
  next.textposition = position;
185
221
  }
186
222
  return next;
@@ -262,6 +298,41 @@ var sanitizeChartValue = function (value) {
262
298
  }
263
299
  return undefined;
264
300
  };
301
+ /**
302
+ * A series drawn from several ranges is ONE series over their union
303
+ * (Excel): every range's points in sequence. A single range passes through
304
+ * untouched so the common path renders exactly as before.
305
+ */
306
+ var mergeSeriesData = function (parts) {
307
+ var e_1, _a;
308
+ if (parts.length === 1)
309
+ return parts[0];
310
+ if (parts.some(function (part) { return !Array.isArray(part); })) {
311
+ var values = [];
312
+ var labels = [];
313
+ try {
314
+ for (var parts_1 = tslib_1.__values(parts), parts_1_1 = parts_1.next(); !parts_1_1.done; parts_1_1 = parts_1.next()) {
315
+ var part = parts_1_1.value;
316
+ if (Array.isArray(part)) {
317
+ values.push.apply(values, tslib_1.__spreadArray([], tslib_1.__read(part), false));
318
+ }
319
+ else {
320
+ values.push.apply(values, tslib_1.__spreadArray([], tslib_1.__read(part.values), false));
321
+ labels.push.apply(labels, tslib_1.__spreadArray([], tslib_1.__read(part.labels), false));
322
+ }
323
+ }
324
+ }
325
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
326
+ finally {
327
+ try {
328
+ if (parts_1_1 && !parts_1_1.done && (_a = parts_1.return)) _a.call(parts_1);
329
+ }
330
+ finally { if (e_1) throw e_1.error; }
331
+ }
332
+ return { values: values, labels: labels };
333
+ }
334
+ return parts.flatMap(function (part) { return part; });
335
+ };
265
336
  /**
266
337
  * Add alpha transparency to a color (hex or rgb)
267
338
  */
@@ -287,13 +358,37 @@ var addAlphaToColor = function (color, alpha) {
287
358
  };
288
359
  var BasicChart = function (_a) {
289
360
  var _b;
290
- var width = _a.width, height = _a.height, chart = _a.chart, theme = _a.theme, isDarkMode = _a.isDarkMode, sheetId = _a.sheetId, readonly = _a.readonly, getDomainValuesFromRange = _a.getDomainValuesFromRange, getSeriesValuesFromRange = _a.getSeriesValuesFromRange, onDeleteChart = _a.onDeleteChart, onRequestEdit = _a.onRequestEdit, onRequestCalculate = _a.onRequestCalculate, isSelected = _a.isSelected;
361
+ var width = _a.width, height = _a.height, chart = _a.chart, theme = _a.theme, isDarkMode = _a.isDarkMode, sheetId = _a.sheetId, readonly = _a.readonly, getDomainValuesFromRange = _a.getDomainValuesFromRange, getSeriesValuesFromRange = _a.getSeriesValuesFromRange, getFormattingFromRange = _a.getFormattingFromRange, onDeleteChart = _a.onDeleteChart, onUpdateChart = _a.onUpdateChart, onRequestEdit = _a.onRequestEdit, onRequestCalculate = _a.onRequestCalculate, isSelected = _a.isSelected, fieldButtons = _a.fieldButtons;
291
362
  var spec = chart.spec;
292
363
  var hierarchyTitleRef = (0, react_1.useRef)(undefined);
293
364
  var explicitChartTitle = (_b = chart.spec.title) !== null && _b !== void 0 ? _b : undefined;
294
365
  var title = explicitChartTitle !== null && explicitChartTitle !== void 0 ? explicitChartTitle : hierarchyTitleRef.current;
295
366
  var plotRef = (0, react_1.useRef)(null);
367
+ // The plotted `<div>` plotly hands back on init — what `Plotly.toImage`
368
+ // rasterises for Copy as Picture and the print preview.
369
+ var graphDivRef = (0, react_1.useRef)(null);
296
370
  var focusSheet = (0, spreadsheet_1.useFocusSheet)();
371
+ // Excel selects a data series (or one data point) when it is clicked
372
+ // inside the chart and the grid highlights its source cells. The plot
373
+ // is interactive with `dragmode: false`, so plotly reports the click but
374
+ // never starts its own drag — a body drag still moves the frame. plotly
375
+ // does not see that drag either, so its mouseup still counts as a click:
376
+ // the pointer-down position tells the two apart.
377
+ var setSelectedChartSeries = (0, spreadsheet_1.useSetSelectedChartSeries)();
378
+ var pointerDownRef = (0, react_1.useRef)(undefined);
379
+ var handlePointerDownCapture = (0, react_1.useCallback)(function (event) {
380
+ pointerDownRef.current = { x: event.clientX, y: event.clientY };
381
+ }, []);
382
+ var handlePlotClick = (0, react_1.useCallback)(function (event) {
383
+ var _a, _b;
384
+ if ((0, plotly_click_1.wasDragged)(pointerDownRef.current, event.event)) {
385
+ return;
386
+ }
387
+ var selection = (0, plotly_click_1.resolvePlotlyClickSelection)(event.points, (_b = (_a = chart.spec.series) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
388
+ if (!selection)
389
+ return;
390
+ setSelectedChartSeries(tslib_1.__assign({ chartId: chart.chartId }, selection));
391
+ }, [chart, setSelectedChartSeries]);
297
392
  var shouldFocusSheetRef = (0, react_1.useRef)(false);
298
393
  var _c = tslib_1.__read((0, react_1.useState)([]), 2), plotData = _c[0], setPlotData = _c[1];
299
394
  var _d = tslib_1.__read((0, react_1.useState)({}), 2), layout = _d[0], setLayout = _d[1];
@@ -321,6 +416,15 @@ var BasicChart = function (_a) {
321
416
  // Use sanitized values - errors like #N/A become undefined
322
417
  var seriesValues = sanitizedValues;
323
418
  if ((spec.chartType === "pie" || spec.chartType === "doughnut")) {
419
+ if (options.pieLabels) {
420
+ var _b = options.pieLabels, domainLabels = _b.domainLabels, offset = _b.offset;
421
+ return {
422
+ values: seriesValues,
423
+ labels: offset === undefined
424
+ ? domainLabels
425
+ : domainLabels.slice(offset, offset + seriesValues.length),
426
+ };
427
+ }
324
428
  var domainSheetRange = (_a = spec.domains[0]) === null || _a === void 0 ? void 0 : _a.sources[0];
325
429
  if (!domainSheetRange) {
326
430
  return { values: [], labels: [] };
@@ -331,17 +435,19 @@ var BasicChart = function (_a) {
331
435
  labels: domainValues,
332
436
  };
333
437
  }
334
- return seriesValues;
438
+ // Excel's "Hidden and Empty Cells": gaps / zero / connect, and
439
+ // whether #N/A counts as empty.
440
+ return (0, empty_cells_1.applyEmptyCellsPolicy)(seriesValues, rawSeriesValues, spec, options.lineLike);
335
441
  }, [getSeriesValuesFromRange, getDomainValuesFromRange]);
336
442
  /**
337
443
  * Triggers a chart update
338
444
  */
339
445
  var updateChart = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
340
- var traces, chartType, position, isBubble, isHierarchy, textColor, bgColor, gridColor, skipHeaders_1, labels, perSeriesX, perSeriesSize, seriesInputs, i, seriesEntry, resolvedLabel, _a, xValues, sizeValues_1, sharedXValues, sharedSizeValues, _b, categories_1, preparedSeries, sizeValues, sizeScale_1, hasStringX_1, palette_1, isScatter_1, scatterStyle_1, plotlyModeForScatterStyle_1, lineShapeFor_1, traces_1, titleFmt, xAxisFmt, yAxisFmt, legendFmt, bubbleLayout, hierarchyRows, headerTitle, hierarchyData, seriesName, hierarchyTrace, layoutForHierarchy, labels, seriesEntry, rawValues_1, locations_1, z_1, ramp_1, colorscale, geoScope, regionTrace, categories, radarStyle, radarTraces, radarInputs, _c, _d, seriesEntry, label, values, indicators, _loop_1, i, maxR, variant, categories, seriesValues, volumePoints_1, hasVolume, buildVolumeTrace, volumeLayout, priceYAxisDomain, roles, xs_1, candleTrace, lineSeries, stockPalette_1, xs_2, stockTraces, isStacked, isHorizontalBarChart, shouldAggregate, primaryDomainSource, rawPrimaryDomainValues, domainData, assignCartesianData, themeColorPalette, applyTraceColor, hasSecondaryAxis, isPareto, isOfPie, ofPieHandled, ofPieExtras, decorateCartesianTrace, seriesIndex, _e, _f, series, currentSeriesIndex, dataLabel, _g, _h, _loop_2, _j, _k, sheetRange, e_1_1, authoredTitleFmt, newLayout, dlOpts, doughnutHole, formattedTraces, sortedTraces;
341
- var e_2, _l, e_1, _m, e_3, _o;
342
- var _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52;
343
- return tslib_1.__generator(this, function (_53) {
344
- switch (_53.label) {
446
+ var traces, chartType, position, isBubble, isHierarchy, textColor, bgColor, gridColor, skipHeaders_1, labels, perSeriesX, perSeriesSize, seriesInputs, i, seriesEntry, resolvedLabel, _a, xValues, sizeValues_1, sharedXValues, sharedSizeValues, _b, categories_1, preparedSeries, sizeValues, sizeScale_1, hasStringX_1, palette_1, isScatter_1, scatterStyle_1, plotlyModeForScatterStyle_1, lineShapeFor_1, traces_1, titleFmt, xAxisFmt, yAxisFmt, legendFmt, bubbleLayout, hierarchyRows, headerTitle, hierarchyData, seriesName, hierarchyTrace, layoutForHierarchy, labels, seriesEntry, rawValues_1, locations_1, z_1, ramp_1, colorscale, geoScope, regionTrace, surfaceToken, categories, surfaceSeriesInputs, _c, _d, seriesEntry, dataLabel, _e, _f, values, e_2_1, seriesNames, surfaceTrace, surfaceLayout, categories, radarStyle, radarTraces, radarInputs, _g, _h, seriesEntry, label, values, indicators, _loop_1, i, maxR, variant, categories, seriesValues, volumePoints_1, hasVolume, buildVolumeTrace, volumeLayout, priceYAxisDomain, roles, xs_1, candleTrace, lineSeries, stockPalette_1, xs_2, stockTraces, isStacked, isHorizontalBarChart, lineTraceVariant, shouldAggregate, primaryDomainSource, rawPrimaryDomainValues, domainData, categoryLevels, multicategoryX, aggregateDomainValues, domainAxisData, secondaryDomainData, categoriesFor, assignCartesianData, themeColorPalette, applyTraceColor, hasSecondaryAxis, hasSecondaryCategoryAxis, valueAxisKey, categoryAxisKey, secondaryValueAxisRef, secondaryCategoryAxisRef, isPareto, isOfPie, ofPieHandled, ofPieExtras, decorateCartesianTrace, domainSources, seriesIndex, _loop_2, _j, _k, series, e_3_1, authoredTitleFmt, isPercentStackedBars, primaryAxisNumberFormat, secondaryAxisNumberFormat, newLayout, dlOpts, doughnutHole, seriesNumberFormats, traceNumberFormat, piePull, formattedTraces, sortedTraces;
447
+ var e_2, _l, e_4, _m, e_3, _o, _p, _q;
448
+ var _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68;
449
+ return tslib_1.__generator(this, function (_69) {
450
+ switch (_69.label) {
345
451
  case 0:
346
452
  (0, utils_1.debug)("Updating chart", chart);
347
453
  traces = [];
@@ -353,41 +459,41 @@ var BasicChart = function (_a) {
353
459
  theme: 1,
354
460
  tint: isDarkMode ? 1 : 0,
355
461
  }, theme);
356
- bgColor = (0, spreadsheet_1.getStringifiedColor)({ theme: 0, tint: isDarkMode ? -1 : 1 }, theme);
462
+ bgColor = (_r = spec.backgroundColor) !== null && _r !== void 0 ? _r : (0, spreadsheet_1.getStringifiedColor)({ theme: 0, tint: isDarkMode ? -1 : 1 }, theme);
357
463
  gridColor = isDarkMode ? "rgba(255,255,255,0.3)" : "#CCCCCC";
358
464
  if (!isBubble) return [3 /*break*/, 6];
359
465
  skipHeaders_1 = spec.useFirstRowAsHeaders !== false;
360
466
  labels = flattenChartDataValues(spec.bubbleLabels, getDomainValuesFromRange, spec.hiddenDimensionStrategy, skipHeaders_1).map(bubble_1.toLabelString);
361
- perSeriesX = ((_p = spec.domains) !== null && _p !== void 0 ? _p : []).map(function (dom) {
467
+ perSeriesX = ((_s = spec.domains) !== null && _s !== void 0 ? _s : []).map(function (dom) {
362
468
  return flattenChartDataValues([dom], getSeriesValuesFromRange, spec.hiddenDimensionStrategy, skipHeaders_1);
363
469
  });
364
- perSeriesSize = ((_q = spec.bubbleSizes) !== null && _q !== void 0 ? _q : []).map(function (sz) {
470
+ perSeriesSize = ((_t = spec.bubbleSizes) !== null && _t !== void 0 ? _t : []).map(function (sz) {
365
471
  return flattenChartDataValues([sz], getSeriesValuesFromRange, spec.hiddenDimensionStrategy, skipHeaders_1);
366
472
  });
367
473
  seriesInputs = [];
368
474
  i = 0;
369
- _53.label = 1;
475
+ _69.label = 1;
370
476
  case 1:
371
477
  if (!(i < spec.series.length)) return [3 /*break*/, 5];
372
478
  seriesEntry = spec.series[i];
373
- resolvedLabel = (_r = seriesEntry.dataLabel) !== null && _r !== void 0 ? _r : "";
479
+ resolvedLabel = (_u = seriesEntry.dataLabel) !== null && _u !== void 0 ? _u : "";
374
480
  if (!(resolvedLabel && (0, utils_1.isAFormula)(resolvedLabel))) return [3 /*break*/, 3];
375
481
  _a = chart_spec_utils_1.coerceCalculatedLabel;
376
- return [4 /*yield*/, onRequestCalculate(resolvedLabel, (_s = chart.position.sheetId) !== null && _s !== void 0 ? _s : sheetId, chart.position.overlayPosition.anchorCell.rowIndex, chart.position.overlayPosition.anchorCell.columnIndex)];
482
+ return [4 /*yield*/, onRequestCalculate(resolvedLabel, (_v = chart.position.sheetId) !== null && _v !== void 0 ? _v : sheetId, chart.position.overlayPosition.anchorCell.rowIndex, chart.position.overlayPosition.anchorCell.columnIndex)];
377
483
  case 2:
378
- resolvedLabel = _a.apply(void 0, [_53.sent()]);
379
- _53.label = 3;
484
+ resolvedLabel = _a.apply(void 0, [_69.sent()]);
485
+ _69.label = 3;
380
486
  case 3:
381
- xValues = (_t = perSeriesX[i]) !== null && _t !== void 0 ? _t : perSeriesX[0];
382
- sizeValues_1 = (_u = perSeriesSize[i]) !== null && _u !== void 0 ? _u : perSeriesSize[0];
487
+ xValues = (_w = perSeriesX[i]) !== null && _w !== void 0 ? _w : perSeriesX[0];
488
+ sizeValues_1 = (_x = perSeriesSize[i]) !== null && _x !== void 0 ? _x : perSeriesSize[0];
383
489
  seriesInputs.push(tslib_1.__assign(tslib_1.__assign({ name: resolvedLabel, values: flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy, skipHeaders_1) }, (xValues ? { xValues: xValues } : {})), (sizeValues_1 ? { sizeValues: sizeValues_1 } : {})));
384
- _53.label = 4;
490
+ _69.label = 4;
385
491
  case 4:
386
492
  i++;
387
493
  return [3 /*break*/, 1];
388
494
  case 5:
389
- sharedXValues = (_v = perSeriesX[0]) !== null && _v !== void 0 ? _v : [];
390
- sharedSizeValues = (_w = perSeriesSize[0]) !== null && _w !== void 0 ? _w : [];
495
+ sharedXValues = (_y = perSeriesX[0]) !== null && _y !== void 0 ? _y : [];
496
+ sharedSizeValues = (_z = perSeriesSize[0]) !== null && _z !== void 0 ? _z : [];
391
497
  _b = (0, bubble_1.prepareBubbleSeriesData)({
392
498
  xValues: sharedXValues,
393
499
  labelValues: labels,
@@ -396,16 +502,16 @@ var BasicChart = function (_a) {
396
502
  }), categories_1 = _b.categories, preparedSeries = _b.series, sizeValues = _b.sizeValues;
397
503
  sizeScale_1 = (0, bubble_1.createBubbleSizeScale)(sizeValues);
398
504
  hasStringX_1 = categories_1.length > 0;
399
- palette_1 = [
505
+ palette_1 = (0, chart_styles_1.getChartPalette)(spec, [
400
506
  theme.themeColors.accent1,
401
507
  theme.themeColors.accent2,
402
508
  theme.themeColors.accent3,
403
509
  theme.themeColors.accent4,
404
510
  theme.themeColors.accent5,
405
511
  theme.themeColors.accent6,
406
- ];
512
+ ]);
407
513
  isScatter_1 = spec.chartType === "scatter";
408
- scatterStyle_1 = (_x = spec.scatterStyle) !== null && _x !== void 0 ? _x : (isScatter_1 ? "lineMarker" : undefined);
514
+ scatterStyle_1 = (_0 = spec.scatterStyle) !== null && _0 !== void 0 ? _0 : (isScatter_1 ? "lineMarker" : undefined);
409
515
  plotlyModeForScatterStyle_1 = function (style) {
410
516
  switch (style) {
411
517
  case "line":
@@ -484,39 +590,39 @@ var BasicChart = function (_a) {
484
590
  };
485
591
  });
486
592
  titleFmt = spec.titleTextFormat;
487
- xAxisFmt = (_y = spec.categoryAxisOptions) === null || _y === void 0 ? void 0 : _y.textFormat;
488
- yAxisFmt = (_z = spec.valueAxisOptions) === null || _z === void 0 ? void 0 : _z.textFormat;
489
- legendFmt = (_0 = spec.legend) === null || _0 === void 0 ? void 0 : _0.textFormat;
593
+ xAxisFmt = (_1 = spec.categoryAxisOptions) === null || _1 === void 0 ? void 0 : _1.textFormat;
594
+ yAxisFmt = (_2 = spec.valueAxisOptions) === null || _2 === void 0 ? void 0 : _2.textFormat;
595
+ legendFmt = (_3 = spec.legend) === null || _3 === void 0 ? void 0 : _3.textFormat;
490
596
  bubbleLayout = {
491
597
  title: {
492
- text: title !== null && title !== void 0 ? title : undefined,
598
+ text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat),
493
599
  font: {
494
- family: (_1 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.fontFamily) !== null && _1 !== void 0 ? _1 : "Untitled Sans, apple-system, sans-serif",
495
- size: (_2 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.fontSize) !== null && _2 !== void 0 ? _2 : 16,
496
- color: (_3 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.color) !== null && _3 !== void 0 ? _3 : textColor,
600
+ family: (_4 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.fontFamily) !== null && _4 !== void 0 ? _4 : "Untitled Sans, apple-system, sans-serif",
601
+ size: (_5 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.fontSize) !== null && _5 !== void 0 ? _5 : 16,
602
+ color: (_6 = titleFmt === null || titleFmt === void 0 ? void 0 : titleFmt.color) !== null && _6 !== void 0 ? _6 : textColor,
497
603
  },
498
604
  x: 0.02,
499
605
  xanchor: "left",
500
606
  },
501
607
  xaxis: {
502
608
  title: {
503
- text: (_4 = spec.horizontalAxisTitle) !== null && _4 !== void 0 ? _4 : "",
504
- font: { color: (_5 = xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.color) !== null && _5 !== void 0 ? _5 : textColor },
609
+ text: (_7 = spec.horizontalAxisTitle) !== null && _7 !== void 0 ? _7 : "",
610
+ font: { color: (_8 = xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.color) !== null && _8 !== void 0 ? _8 : textColor },
505
611
  },
506
612
  gridcolor: gridColor,
507
- tickfont: tslib_1.__assign(tslib_1.__assign({ color: (_6 = xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.color) !== null && _6 !== void 0 ? _6 : textColor }, ((xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.fontFamily) ? { family: xAxisFmt.fontFamily } : {})), ((xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.fontSize) ? { size: xAxisFmt.fontSize } : {})),
613
+ tickfont: tslib_1.__assign(tslib_1.__assign({ color: (_9 = xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.color) !== null && _9 !== void 0 ? _9 : textColor }, ((xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.fontFamily) ? { family: xAxisFmt.fontFamily } : {})), ((xAxisFmt === null || xAxisFmt === void 0 ? void 0 : xAxisFmt.fontSize) ? { size: xAxisFmt.fontSize } : {})),
508
614
  type: hasStringX_1 ? "category" : "linear",
509
615
  },
510
616
  yaxis: {
511
617
  title: {
512
- text: (_7 = spec.verticalAxisTitle) !== null && _7 !== void 0 ? _7 : "",
513
- font: { color: (_8 = yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.color) !== null && _8 !== void 0 ? _8 : textColor },
618
+ text: (_10 = spec.verticalAxisTitle) !== null && _10 !== void 0 ? _10 : "",
619
+ font: { color: (_11 = yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.color) !== null && _11 !== void 0 ? _11 : textColor },
514
620
  },
515
621
  gridcolor: gridColor,
516
- tickfont: tslib_1.__assign(tslib_1.__assign({ color: (_9 = yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.color) !== null && _9 !== void 0 ? _9 : textColor }, ((yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.fontFamily) ? { family: yAxisFmt.fontFamily } : {})), ((yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.fontSize) ? { size: yAxisFmt.fontSize } : {})),
622
+ tickfont: tslib_1.__assign(tslib_1.__assign({ color: (_12 = yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.color) !== null && _12 !== void 0 ? _12 : textColor }, ((yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.fontFamily) ? { family: yAxisFmt.fontFamily } : {})), ((yAxisFmt === null || yAxisFmt === void 0 ? void 0 : yAxisFmt.fontSize) ? { size: yAxisFmt.fontSize } : {})),
517
623
  },
518
624
  legend: {
519
- font: tslib_1.__assign(tslib_1.__assign({ color: (_10 = legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.color) !== null && _10 !== void 0 ? _10 : textColor }, ((legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.fontFamily) ? { family: legendFmt.fontFamily } : {})), ((legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.fontSize) ? { size: legendFmt.fontSize } : {})),
625
+ font: tslib_1.__assign(tslib_1.__assign({ color: (_13 = legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.color) !== null && _13 !== void 0 ? _13 : textColor }, ((legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.fontFamily) ? { family: legendFmt.fontFamily } : {})), ((legendFmt === null || legendFmt === void 0 ? void 0 : legendFmt.fontSize) ? { size: legendFmt.fontSize } : {})),
520
626
  },
521
627
  paper_bgcolor: bgColor,
522
628
  plot_bgcolor: bgColor,
@@ -541,8 +647,8 @@ var BasicChart = function (_a) {
541
647
  hierarchyTitleRef.current = explicitChartTitle !== null && explicitChartTitle !== void 0 ? explicitChartTitle : headerTitle;
542
648
  hierarchyData = (0, hierarchy_1.toPlotlyHierarchy)(hierarchyRows);
543
649
  seriesName = hierarchyData.labels.length === 1
544
- ? (_11 = hierarchyData.labels[0]) !== null && _11 !== void 0 ? _11 : ""
545
- : (_12 = explicitChartTitle !== null && explicitChartTitle !== void 0 ? explicitChartTitle : headerTitle) !== null && _12 !== void 0 ? _12 : "";
650
+ ? (_14 = hierarchyData.labels[0]) !== null && _14 !== void 0 ? _14 : ""
651
+ : (_15 = explicitChartTitle !== null && explicitChartTitle !== void 0 ? explicitChartTitle : headerTitle) !== null && _15 !== void 0 ? _15 : "";
546
652
  hierarchyTrace = {
547
653
  type: chartType,
548
654
  labels: hierarchyData.labels,
@@ -554,7 +660,7 @@ var BasicChart = function (_a) {
554
660
  };
555
661
  layoutForHierarchy = {
556
662
  title: {
557
- text: title !== null && title !== void 0 ? title : undefined,
663
+ text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat),
558
664
  font: {
559
665
  family: "Untitled Sans, apple-system, sans-serif",
560
666
  size: 16,
@@ -591,7 +697,7 @@ var BasicChart = function (_a) {
591
697
  // country-name matching and silently skips labels it can't place.
592
698
  if ((0, region_map_1.isRegionMapSpec)(spec)) {
593
699
  labels = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map(function (v) { return String(v !== null && v !== void 0 ? v : "").trim(); });
594
- seriesEntry = (_13 = spec.series) === null || _13 === void 0 ? void 0 : _13[0];
700
+ seriesEntry = (_16 = spec.series) === null || _16 === void 0 ? void 0 : _16[0];
595
701
  rawValues_1 = seriesEntry
596
702
  ? flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map(function (v) { return (typeof v === "number" ? v : Number(v)); })
597
703
  : [];
@@ -628,7 +734,7 @@ var BasicChart = function (_a) {
628
734
  };
629
735
  setPlotData([regionTrace]);
630
736
  setLayout({
631
- title: { text: title !== null && title !== void 0 ? title : undefined },
737
+ title: { text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat) },
632
738
  font: { color: textColor },
633
739
  paper_bgcolor: bgColor,
634
740
  plot_bgcolor: bgColor,
@@ -652,17 +758,97 @@ var BasicChart = function (_a) {
652
758
  });
653
759
  return [2 /*return*/];
654
760
  }
761
+ surfaceToken = (0, three_d_1.normalize3DSourceType)(spec.sourceChartType);
762
+ if (!(surfaceToken === "SURFACE" || surfaceToken === "SURFACE_3D")) return [3 /*break*/, 17];
763
+ categories = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map(function (v) { return String(v !== null && v !== void 0 ? v : ""); });
764
+ surfaceSeriesInputs = [];
765
+ _69.label = 7;
766
+ case 7:
767
+ _69.trys.push([7, 14, 15, 16]);
768
+ _c = tslib_1.__values((_17 = spec.series) !== null && _17 !== void 0 ? _17 : []), _d = _c.next();
769
+ _69.label = 8;
770
+ case 8:
771
+ if (!!_d.done) return [3 /*break*/, 13];
772
+ seriesEntry = _d.value;
773
+ if (!(!(0, utils_1.isNil)(seriesEntry.dataLabel) && (0, utils_1.isAFormula)(seriesEntry.dataLabel))) return [3 /*break*/, 10];
774
+ _f = chart_spec_utils_1.coerceCalculatedLabel;
775
+ return [4 /*yield*/, onRequestCalculate(seriesEntry.dataLabel, (_18 = position.sheetId) !== null && _18 !== void 0 ? _18 : sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex)];
776
+ case 9:
777
+ _e = _f.apply(void 0, [_69.sent()]);
778
+ return [3 /*break*/, 11];
779
+ case 10:
780
+ _e = (_19 = seriesEntry.dataLabel) !== null && _19 !== void 0 ? _19 : "";
781
+ _69.label = 11;
782
+ case 11:
783
+ dataLabel = _e;
784
+ values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map(function (v) { return (typeof v === "number" ? v : Number(v)); });
785
+ surfaceSeriesInputs.push({ name: dataLabel, values: values });
786
+ _69.label = 12;
787
+ case 12:
788
+ _d = _c.next();
789
+ return [3 /*break*/, 8];
790
+ case 13: return [3 /*break*/, 16];
791
+ case 14:
792
+ e_2_1 = _69.sent();
793
+ e_2 = { error: e_2_1 };
794
+ return [3 /*break*/, 16];
795
+ case 15:
796
+ try {
797
+ if (_d && !_d.done && (_l = _c.return)) _l.call(_c);
798
+ }
799
+ finally { if (e_2) throw e_2.error; }
800
+ return [7 /*endfinally*/];
801
+ case 16:
802
+ seriesNames = surfaceSeriesInputs.map(function (entry, index) { return entry.name || "Series ".concat(index + 1); });
803
+ surfaceTrace = (0, plotly_surface_1.buildPlotlySurfaceTrace)(surfaceToken, surfaceSeriesInputs, categories, seriesNames, (0, axis_number_format_1.resolveSeriesNumberFormats)(spec.series, getFormattingFromRange, spec.hiddenDimensionStrategy));
804
+ surfaceLayout = tslib_1.__assign({ title: {
805
+ text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat),
806
+ font: {
807
+ family: "Untitled Sans, apple-system, sans-serif",
808
+ size: 16,
809
+ color: textColor,
810
+ },
811
+ x: 0.02,
812
+ xanchor: "left",
813
+ }, font: {
814
+ family: "Untitled Sans, apple-system, sans-serif",
815
+ size: 12,
816
+ color: textColor,
817
+ }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, showlegend: false, margin: { l: 60, r: 20, t: 50, b: 50 } }, (surfaceToken === "SURFACE"
818
+ ? {
819
+ xaxis: {
820
+ title: { text: (_20 = spec.horizontalAxisTitle) !== null && _20 !== void 0 ? _20 : "" },
821
+ automargin: true,
822
+ color: textColor,
823
+ },
824
+ yaxis: {
825
+ title: { text: (_21 = spec.verticalAxisTitle) !== null && _21 !== void 0 ? _21 : "" },
826
+ automargin: true,
827
+ color: textColor,
828
+ },
829
+ }
830
+ : {
831
+ scene: {
832
+ xaxis: { title: { text: (_22 = spec.horizontalAxisTitle) !== null && _22 !== void 0 ? _22 : "" } },
833
+ yaxis: { title: { text: "" } },
834
+ zaxis: { title: { text: (_23 = spec.verticalAxisTitle) !== null && _23 !== void 0 ? _23 : "" } },
835
+ },
836
+ }));
837
+ setPlotData([surfaceTrace]);
838
+ setLayout(surfaceLayout);
839
+ return [2 /*return*/];
840
+ case 17:
655
841
  // ---------------------------- Radar ----------------------------
656
842
  // Plotly renders radar via `scatterpolar` traces: r = the values,
657
843
  // theta = the category names (closed by appending the first point).
658
844
  if (spec.chartType === "radar") {
659
845
  categories = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map(function (v) { return String(v !== null && v !== void 0 ? v : ""); });
660
- radarStyle = (_14 = spec.radarStyle) !== null && _14 !== void 0 ? _14 : "standard";
846
+ radarStyle = (_24 = spec.radarStyle) !== null && _24 !== void 0 ? _24 : "standard";
661
847
  radarTraces = [];
662
848
  radarInputs = [];
663
849
  try {
664
- for (_c = tslib_1.__values((_15 = spec.series) !== null && _15 !== void 0 ? _15 : []), _d = _c.next(); !_d.done; _d = _c.next()) {
665
- seriesEntry = _d.value;
850
+ for (_g = tslib_1.__values((_25 = spec.series) !== null && _25 !== void 0 ? _25 : []), _h = _g.next(); !_h.done; _h = _g.next()) {
851
+ seriesEntry = _h.value;
666
852
  label = seriesEntry.dataLabel && !(0, utils_1.isAFormula)(seriesEntry.dataLabel)
667
853
  ? seriesEntry.dataLabel
668
854
  : "";
@@ -670,17 +856,17 @@ var BasicChart = function (_a) {
670
856
  radarInputs.push({ name: label, values: values });
671
857
  }
672
858
  }
673
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
859
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
674
860
  finally {
675
861
  try {
676
- if (_d && !_d.done && (_l = _c.return)) _l.call(_c);
862
+ if (_h && !_h.done && (_m = _g.return)) _m.call(_g);
677
863
  }
678
- finally { if (e_2) throw e_2.error; }
864
+ finally { if (e_4) throw e_4.error; }
679
865
  }
680
866
  indicators = (0, radar_1.buildRadarIndicators)(categories, radarInputs);
681
867
  _loop_1 = function (i) {
682
868
  var input = radarInputs[i];
683
- var seriesColor = (_18 = (_17 = (_16 = spec.series) === null || _16 === void 0 ? void 0 : _16[i]) === null || _17 === void 0 ? void 0 : _17.color) !== null && _18 !== void 0 ? _18 : undefined;
869
+ var seriesColor = (_28 = (_27 = (_26 = spec.series) === null || _26 === void 0 ? void 0 : _26[i]) === null || _27 === void 0 ? void 0 : _27.color) !== null && _28 !== void 0 ? _28 : undefined;
684
870
  var r = indicators.map(function (_, idx) { var _a; return (_a = input.values[idx]) !== null && _a !== void 0 ? _a : 0; });
685
871
  var theta = indicators.map(function (ind) { return ind.name; });
686
872
  radarTraces.push(tslib_1.__assign(tslib_1.__assign({ type: "scatterpolar", r: r.length ? tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(r), false), [r[0]], false) : r, theta: theta.length ? tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(theta), false), [theta[0]], false) : theta, name: input.name, mode: radarStyle === "standard" ? "lines" : "lines+markers" }, (radarStyle === "filled" ? { fill: "toself" } : {})), (seriesColor ? { line: { color: seriesColor } } : {})));
@@ -691,7 +877,7 @@ var BasicChart = function (_a) {
691
877
  maxR = indicators.reduce(function (m, ind) { return Math.max(m, ind.max); }, 0);
692
878
  setPlotData(radarTraces);
693
879
  setLayout({
694
- title: { text: title !== null && title !== void 0 ? title : undefined },
880
+ title: { text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat) },
695
881
  font: { color: textColor },
696
882
  paper_bgcolor: bgColor,
697
883
  plot_bgcolor: bgColor,
@@ -712,13 +898,13 @@ var BasicChart = function (_a) {
712
898
  // V-variants additionally get a volume column sub-pane below the
713
899
  // price plot.
714
900
  if (spec.chartType === "stock") {
715
- variant = ((_19 = spec.stockVariant) !== null && _19 !== void 0 ? _19 : "HLC");
901
+ variant = ((_29 = spec.stockVariant) !== null && _29 !== void 0 ? _29 : "HLC");
716
902
  categories = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map(function (v) { return String(v !== null && v !== void 0 ? v : ""); });
717
- seriesValues = ((_20 = spec.series) !== null && _20 !== void 0 ? _20 : []).map(function (seriesEntry) {
903
+ seriesValues = ((_30 = spec.series) !== null && _30 !== void 0 ? _30 : []).map(function (seriesEntry) {
718
904
  return flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map(function (v) { return (typeof v === "number" ? v : Number(v)); });
719
905
  });
720
906
  volumePoints_1 = (0, stock_1.toVolumeSeries)(seriesValues, variant);
721
- hasVolume = ((_21 = volumePoints_1 === null || volumePoints_1 === void 0 ? void 0 : volumePoints_1.length) !== null && _21 !== void 0 ? _21 : 0) > 0;
907
+ hasVolume = ((_31 = volumePoints_1 === null || volumePoints_1 === void 0 ? void 0 : volumePoints_1.length) !== null && _31 !== void 0 ? _31 : 0) > 0;
722
908
  buildVolumeTrace = function (xs) {
723
909
  return ({
724
910
  type: "bar",
@@ -751,37 +937,37 @@ var BasicChart = function (_a) {
751
937
  roles = (0, stock_1.assignStockRoles)(seriesValues, variant);
752
938
  xs_1 = categories.length > 0
753
939
  ? categories
754
- : ((_22 = roles.close) !== null && _22 !== void 0 ? _22 : []).map(function (_, i) { return i + 1; });
940
+ : ((_32 = roles.close) !== null && _32 !== void 0 ? _32 : []).map(function (_, i) { return i + 1; });
755
941
  candleTrace = {
756
942
  type: "candlestick",
757
943
  x: xs_1,
758
- open: ((_23 = roles.open) !== null && _23 !== void 0 ? _23 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
759
- high: ((_24 = roles.high) !== null && _24 !== void 0 ? _24 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
760
- low: ((_25 = roles.low) !== null && _25 !== void 0 ? _25 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
761
- close: ((_26 = roles.close) !== null && _26 !== void 0 ? _26 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
944
+ open: ((_33 = roles.open) !== null && _33 !== void 0 ? _33 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
945
+ high: ((_34 = roles.high) !== null && _34 !== void 0 ? _34 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
946
+ low: ((_35 = roles.low) !== null && _35 !== void 0 ? _35 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
947
+ close: ((_36 = roles.close) !== null && _36 !== void 0 ? _36 : []).map(function (v) { return v !== null && v !== void 0 ? v : null; }),
762
948
  increasing: { line: { color: theme.themeColors.accent1 } },
763
949
  decreasing: { line: { color: theme.themeColors.accent2 } },
764
950
  };
765
951
  setPlotData(hasVolume ? [candleTrace, buildVolumeTrace(xs_1)] : [candleTrace]);
766
- setLayout(tslib_1.__assign(tslib_1.__assign({ title: { text: title !== null && title !== void 0 ? title : undefined }, font: { color: textColor }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, showlegend: false, xaxis: {
767
- title: { text: (_27 = spec.horizontalAxisTitle) !== null && _27 !== void 0 ? _27 : "" },
952
+ setLayout(tslib_1.__assign(tslib_1.__assign({ title: { text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat) }, font: { color: textColor }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, showlegend: false, xaxis: {
953
+ title: { text: (_37 = spec.horizontalAxisTitle) !== null && _37 !== void 0 ? _37 : "" },
768
954
  automargin: true,
769
955
  showgrid: true,
770
956
  gridcolor: gridColor,
771
957
  rangeslider: { visible: false },
772
- }, yaxis: tslib_1.__assign({ title: { text: (_28 = spec.verticalAxisTitle) !== null && _28 !== void 0 ? _28 : "" }, automargin: true, showgrid: true, gridcolor: gridColor }, priceYAxisDomain) }, volumeLayout), { margin: { l: 50, r: 50, t: 50, b: 50 }, autosize: true }));
958
+ }, yaxis: tslib_1.__assign({ title: { text: (_38 = spec.verticalAxisTitle) !== null && _38 !== void 0 ? _38 : "" }, automargin: true, showgrid: true, gridcolor: gridColor }, priceYAxisDomain) }, volumeLayout), { margin: { l: 50, r: 50, t: 50, b: 50 }, autosize: true }));
773
959
  return [2 /*return*/];
774
960
  }
775
961
  lineSeries = (0, stock_1.toLineSeries)(seriesValues, variant);
776
- stockPalette_1 = [
962
+ stockPalette_1 = (0, chart_styles_1.getChartPalette)(spec, [
777
963
  theme.themeColors.accent1,
778
964
  theme.themeColors.accent2,
779
965
  theme.themeColors.accent3,
780
966
  theme.themeColors.accent4,
781
- ];
967
+ ]);
782
968
  xs_2 = categories.length > 0
783
969
  ? categories
784
- : ((_30 = (_29 = lineSeries[0]) === null || _29 === void 0 ? void 0 : _29.values) !== null && _30 !== void 0 ? _30 : []).map(function (_, i) { return i + 1; });
970
+ : ((_40 = (_39 = lineSeries[0]) === null || _39 === void 0 ? void 0 : _39.values) !== null && _40 !== void 0 ? _40 : []).map(function (_, i) { return i + 1; });
785
971
  stockTraces = lineSeries.map(function (s, i) { return ({
786
972
  type: "scatter",
787
973
  mode: "lines",
@@ -791,42 +977,83 @@ var BasicChart = function (_a) {
791
977
  line: { color: stockPalette_1[i % stockPalette_1.length] },
792
978
  }); });
793
979
  setPlotData(hasVolume ? tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(stockTraces), false), [buildVolumeTrace(xs_2)], false) : stockTraces);
794
- setLayout(tslib_1.__assign(tslib_1.__assign({ title: { text: title !== null && title !== void 0 ? title : undefined }, font: { color: textColor }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, showlegend: stockTraces.length > 1, xaxis: {
795
- title: { text: (_31 = spec.horizontalAxisTitle) !== null && _31 !== void 0 ? _31 : "" },
980
+ setLayout(tslib_1.__assign(tslib_1.__assign({ title: { text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat) }, font: { color: textColor }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, showlegend: stockTraces.length > 1, xaxis: {
981
+ title: { text: (_41 = spec.horizontalAxisTitle) !== null && _41 !== void 0 ? _41 : "" },
796
982
  automargin: true,
797
983
  showgrid: true,
798
984
  gridcolor: gridColor,
799
- }, yaxis: tslib_1.__assign({ title: { text: (_32 = spec.verticalAxisTitle) !== null && _32 !== void 0 ? _32 : "" }, automargin: true, showgrid: true, gridcolor: gridColor }, priceYAxisDomain) }, volumeLayout), { margin: { l: 50, r: 50, t: 50, b: 50 }, autosize: true }));
985
+ }, yaxis: tslib_1.__assign({ title: { text: (_42 = spec.verticalAxisTitle) !== null && _42 !== void 0 ? _42 : "" }, automargin: true, showgrid: true, gridcolor: gridColor }, priceYAxisDomain) }, volumeLayout), { margin: { l: 50, r: 50, t: 50, b: 50 }, autosize: true }));
800
986
  return [2 /*return*/];
801
987
  }
802
988
  isStacked = spec.stackedType && spec.stackedType !== "UNSTACKED";
803
989
  isHorizontalBarChart = spec.chartType === "bar";
990
+ lineTraceVariant = function (series, effectiveChartType) {
991
+ var _a, _b;
992
+ if (effectiveChartType !== "line" && effectiveChartType !== "area") {
993
+ return {};
994
+ }
995
+ var extra = {};
996
+ if (isStacked && spec.stackedType === "PERCENT_STACKED") {
997
+ extra.groupnorm = "percent";
998
+ }
999
+ if (effectiveChartType === "line") {
1000
+ var marker = series.marker;
1001
+ var symbol = marker === null || marker === void 0 ? void 0 : marker.symbol;
1002
+ var wantsMarkers = symbol === "none"
1003
+ ? false
1004
+ : Boolean(spec.showMarkers) || !(0, utils_1.isNil)(symbol);
1005
+ if (wantsMarkers) {
1006
+ extra.mode = "lines+markers";
1007
+ extra.marker = {
1008
+ symbol: (_a = (0, helpers_1.mapMarkerSymbolToPlotly)(symbol)) !== null && _a !== void 0 ? _a : "circle",
1009
+ size: (_b = marker === null || marker === void 0 ? void 0 : marker.size) !== null && _b !== void 0 ? _b : 6,
1010
+ };
1011
+ }
1012
+ }
1013
+ return extra;
1014
+ };
804
1015
  shouldAggregate = (0, aggregation_1.shouldAggregateSeries)(spec.series);
805
- primaryDomainSource = (_35 = (_34 = (_33 = spec === null || spec === void 0 ? void 0 : spec.domains) === null || _33 === void 0 ? void 0 : _33[0]) === null || _34 === void 0 ? void 0 : _34.sources) === null || _35 === void 0 ? void 0 : _35[0];
1016
+ primaryDomainSource = (_45 = (_44 = (_43 = spec === null || spec === void 0 ? void 0 : spec.domains) === null || _43 === void 0 ? void 0 : _43[0]) === null || _44 === void 0 ? void 0 : _44.sources) === null || _45 === void 0 ? void 0 : _45[0];
806
1017
  rawPrimaryDomainValues = primaryDomainSource
807
- ? (0, aggregation_1.sanitizeDomainValues)((_36 = getDomainValuesFromRange(primaryDomainSource, spec.hiddenDimensionStrategy)) !== null && _36 !== void 0 ? _36 : [])
1018
+ ? (0, aggregation_1.sanitizeDomainValues)((_46 = getDomainValuesFromRange(primaryDomainSource, spec.hiddenDimensionStrategy)) !== null && _46 !== void 0 ? _46 : [])
808
1019
  : [];
809
1020
  domainData = (0, aggregation_1.getDomainValuesForAxis)(rawPrimaryDomainValues, shouldAggregate);
810
- (_37 = spec.domains) === null || _37 === void 0 ? void 0 : _37.forEach(function (domain, domainIndex) {
811
- domain.sources.forEach(function (sheetRange, sourceIndex) {
1021
+ categoryLevels = (0, category_levels_1.resolveCategoryLevels)((_47 = spec.categoryLevels) === null || _47 === void 0 ? void 0 : _47.map(function (level) {
1022
+ return flattenChartDataValues([level], getDomainValuesFromRange, spec.hiddenDimensionStrategy, false);
1023
+ }));
1024
+ multicategoryX = categoryLevels
1025
+ ? (0, category_levels_1.plotlyMulticategoryX)(categoryLevels)
1026
+ : undefined;
1027
+ if (categoryLevels) {
1028
+ domainData = categoryLevels.leaf;
1029
+ }
1030
+ aggregateDomainValues = domainData;
1031
+ domainAxisData = (categoryLevels ? [] : (_48 = spec.domains) !== null && _48 !== void 0 ? _48 : []).map(function (domain, domainIndex) {
1032
+ return domain.sources.flatMap(function (sheetRange, sourceIndex) {
812
1033
  var _a;
813
1034
  if (domainIndex === 0 && sourceIndex === 0) {
814
- domainData = (0, aggregation_1.getDomainValuesForAxis)(rawPrimaryDomainValues, shouldAggregate);
815
- }
816
- else {
817
- var rawValues = (0, aggregation_1.sanitizeDomainValues)((_a = getDomainValuesFromRange(sheetRange, spec.hiddenDimensionStrategy)) !== null && _a !== void 0 ? _a : []);
818
- domainData = (0, aggregation_1.getDomainValuesForAxis)(rawValues, shouldAggregate);
1035
+ return aggregateDomainValues;
819
1036
  }
1037
+ var rawValues = (0, aggregation_1.sanitizeDomainValues)((_a = getDomainValuesFromRange(sheetRange, spec.hiddenDimensionStrategy)) !== null && _a !== void 0 ? _a : []);
1038
+ return (0, aggregation_1.getDomainValuesForAxis)(rawValues, shouldAggregate);
820
1039
  });
821
1040
  });
1041
+ if (domainAxisData[0])
1042
+ domainData = domainAxisData[0];
1043
+ secondaryDomainData = domainAxisData[1];
1044
+ categoriesFor = function (series) {
1045
+ return series.useSecondaryAxis && secondaryDomainData
1046
+ ? secondaryDomainData
1047
+ : domainData;
1048
+ };
822
1049
  assignCartesianData = function (categories, values) {
823
1050
  // Convert undefined to null for Plotly (Datum type accepts null but not undefined)
824
1051
  var plotlyValues = values.map(function (v) { return v !== null && v !== void 0 ? v : null; });
825
1052
  // When categories is empty but we have values, generate index-based x values
826
1053
  // so Plotly can render the chart
827
- var effectiveCategories = categories.length === 0 && plotlyValues.length > 0
1054
+ var effectiveCategories = multicategoryX !== null && multicategoryX !== void 0 ? multicategoryX : (categories.length === 0 && plotlyValues.length > 0
828
1055
  ? Array.from({ length: plotlyValues.length }, function (_, i) { return i + 1; })
829
- : categories;
1056
+ : categories);
830
1057
  if (isHorizontalBarChart) {
831
1058
  return {
832
1059
  x: plotlyValues,
@@ -836,17 +1063,17 @@ var BasicChart = function (_a) {
836
1063
  }
837
1064
  return { x: effectiveCategories, y: plotlyValues, orientation: undefined };
838
1065
  };
839
- themeColorPalette = [
1066
+ themeColorPalette = (0, chart_styles_1.getChartPalette)(spec, [
840
1067
  theme.themeColors.accent1,
841
1068
  theme.themeColors.accent2,
842
1069
  theme.themeColors.accent3,
843
1070
  theme.themeColors.accent4,
844
1071
  theme.themeColors.accent5,
845
1072
  theme.themeColors.accent6,
846
- ];
1073
+ ]);
847
1074
  applyTraceColor = function (trace, seriesColor, options) {
848
- var e_4, _a;
849
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
1075
+ var e_5, _a;
1076
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
850
1077
  var target = trace;
851
1078
  var chartTypeForStyling = (_b = options === null || options === void 0 ? void 0 : options.effectiveChartType) !== null && _b !== void 0 ? _b : spec.chartType;
852
1079
  var isBarOrColumn = chartTypeForStyling === "bar" || chartTypeForStyling === "column";
@@ -866,24 +1093,41 @@ var BasicChart = function (_a) {
866
1093
  // give every task its own color. Build a per-point color array
867
1094
  // by category index, falling back to the series color for points
868
1095
  // without an override.
869
- if (isBarOrColumn &&
1096
+ var isPie = chartTypeForStyling === "pie";
1097
+ if ((isBarOrColumn || isPie) &&
870
1098
  Array.isArray(options === null || options === void 0 ? void 0 : options.dataPointColors) &&
871
1099
  (options === null || options === void 0 ? void 0 : options.dataPointColors.length)) {
872
1100
  var overrides_1 = new Map();
873
1101
  try {
874
- for (var _s = tslib_1.__values(options.dataPointColors), _t = _s.next(); !_t.done; _t = _s.next()) {
875
- var dp = _t.value;
1102
+ for (var _u = tslib_1.__values(options.dataPointColors), _v = _u.next(); !_v.done; _v = _u.next()) {
1103
+ var dp = _v.value;
876
1104
  if (typeof dp.idx === "number" && typeof dp.color === "string") {
877
1105
  overrides_1.set(dp.idx, dp.color);
878
1106
  }
879
1107
  }
880
1108
  }
881
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1109
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
882
1110
  finally {
883
1111
  try {
884
- if (_t && !_t.done && (_a = _s.return)) _a.call(_s);
1112
+ if (_v && !_v.done && (_a = _u.return)) _a.call(_u);
885
1113
  }
886
- finally { if (e_4) throw e_4.error; }
1114
+ finally { if (e_5) throw e_5.error; }
1115
+ }
1116
+ if (isPie) {
1117
+ // Per-slice colours (`<c:dPt>`): an authored slice colour wins,
1118
+ // the other slices keep the palette cycle the trace was built
1119
+ // with (or the series' own colour when one was authored).
1120
+ var existing_1 = Array.isArray((_h = target.marker) === null || _h === void 0 ? void 0 : _h.colors)
1121
+ ? target.marker.colors
1122
+ : themeColorPalette;
1123
+ var labelCount = Array.isArray(target.labels)
1124
+ ? target.labels.length
1125
+ : 0;
1126
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_j = target.marker) !== null && _j !== void 0 ? _j : {})), { colors: Array.from({ length: labelCount }, function (_, i) {
1127
+ var _a, _b;
1128
+ return (_b = (_a = overrides_1.get(i)) !== null && _a !== void 0 ? _a : seriesColor) !== null && _b !== void 0 ? _b : existing_1[i % Math.max(1, existing_1.length)];
1129
+ }) });
1130
+ return trace;
887
1131
  }
888
1132
  var fallback_1 = effectiveColor !== null && effectiveColor !== void 0 ? effectiveColor : "#4285F4";
889
1133
  var yArray = Array.isArray(target.y)
@@ -892,18 +1136,18 @@ var BasicChart = function (_a) {
892
1136
  ? target.x
893
1137
  : [];
894
1138
  var colors = yArray.map(function (_, i) { var _a; return (_a = overrides_1.get(i)) !== null && _a !== void 0 ? _a : fallback_1; });
895
- target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_h = target.marker) !== null && _h !== void 0 ? _h : {})), { color: colors });
1139
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_k = target.marker) !== null && _k !== void 0 ? _k : {})), { color: colors });
896
1140
  return trace;
897
1141
  }
898
1142
  // Handle invertIfNegative for bar/column charts
899
1143
  if (isBarOrColumn && (options === null || options === void 0 ? void 0 : options.invertIfNegative) && (options === null || options === void 0 ? void 0 : options.values)) {
900
1144
  var positiveColor_1 = effectiveColor !== null && effectiveColor !== void 0 ? effectiveColor : "#4285F4";
901
- var negColor_1 = (_j = options.negativeColor) !== null && _j !== void 0 ? _j : "#FF0000";
1145
+ var negColor_1 = (_l = options.negativeColor) !== null && _l !== void 0 ? _l : "#FF0000";
902
1146
  // Create array of colors based on value sign
903
1147
  var colors = options.values.map(function (v) {
904
1148
  return typeof v === "number" && v < 0 ? negColor_1 : positiveColor_1;
905
1149
  });
906
- target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_k = target.marker) !== null && _k !== void 0 ? _k : {})), { color: colors });
1150
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_m = target.marker) !== null && _m !== void 0 ? _m : {})), { color: colors });
907
1151
  return trace;
908
1152
  }
909
1153
  if (!effectiveColor) {
@@ -914,7 +1158,7 @@ var BasicChart = function (_a) {
914
1158
  // with (accent1..accent6) with a single repeated color. Only repeat
915
1159
  // a uniform color when the user explicitly authored a series color;
916
1160
  // otherwise keep the multi-color palette so each slice stays distinct.
917
- var existingColors = (_l = target.marker) === null || _l === void 0 ? void 0 : _l.colors;
1161
+ var existingColors = (_o = target.marker) === null || _o === void 0 ? void 0 : _o.colors;
918
1162
  if (!seriesColor &&
919
1163
  Array.isArray(existingColors) &&
920
1164
  existingColors.length > 1) {
@@ -925,17 +1169,17 @@ var BasicChart = function (_a) {
925
1169
  : Array.isArray(target.y)
926
1170
  ? target.y.length
927
1171
  : 0;
928
- target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_m = target.marker) !== null && _m !== void 0 ? _m : {})), { colors: labelCount > 0
1172
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_p = target.marker) !== null && _p !== void 0 ? _p : {})), { colors: labelCount > 0
929
1173
  ? Array.from({ length: labelCount }, function () { return effectiveColor; })
930
- : (_o = target.marker) === null || _o === void 0 ? void 0 : _o.colors, color: effectiveColor });
1174
+ : (_q = target.marker) === null || _q === void 0 ? void 0 : _q.colors, color: effectiveColor });
931
1175
  return trace;
932
1176
  }
933
1177
  if (isBarOrColumn) {
934
- target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_p = target.marker) !== null && _p !== void 0 ? _p : {})), { color: effectiveColor });
1178
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_r = target.marker) !== null && _r !== void 0 ? _r : {})), { color: effectiveColor });
935
1179
  return trace;
936
1180
  }
937
- target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_q = target.marker) !== null && _q !== void 0 ? _q : {})), { color: effectiveColor });
938
- target.line = tslib_1.__assign(tslib_1.__assign({}, ((_r = target.line) !== null && _r !== void 0 ? _r : {})), { color: effectiveColor });
1181
+ target.marker = tslib_1.__assign(tslib_1.__assign({}, ((_s = target.marker) !== null && _s !== void 0 ? _s : {})), { color: effectiveColor });
1182
+ target.line = tslib_1.__assign(tslib_1.__assign({}, ((_t = target.line) !== null && _t !== void 0 ? _t : {})), { color: effectiveColor });
939
1183
  if (target.fill && target.fill !== "none") {
940
1184
  // Add transparency to area fills so they don't cover other traces
941
1185
  target.fillcolor = addAlphaToColor(effectiveColor, 0.5);
@@ -943,19 +1187,29 @@ var BasicChart = function (_a) {
943
1187
  return trace;
944
1188
  };
945
1189
  hasSecondaryAxis = false;
1190
+ hasSecondaryCategoryAxis = false;
1191
+ valueAxisKey = isHorizontalBarChart ? "xaxis" : "yaxis";
1192
+ categoryAxisKey = isHorizontalBarChart ? "yaxis" : "xaxis";
1193
+ secondaryValueAxisRef = isHorizontalBarChart ? "x2" : "y2";
1194
+ secondaryCategoryAxisRef = isHorizontalBarChart ? "y2" : "x2";
946
1195
  isPareto = spec.chartType === "histogram" && (0, histogram_1.isParetoSpec)(spec);
947
1196
  isOfPie = spec.chartType === "pie" && (0, of_pie_1.isOfPieChartSpec)(spec);
948
1197
  ofPieHandled = false;
949
1198
  ofPieExtras = null;
950
1199
  decorateCartesianTrace = function (trace, series, values, dataLabel) {
951
- var e_5, _a;
1200
+ var e_6, _a;
952
1201
  var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
953
1202
  var target = trace;
954
- // Secondary value axis. Plotly overlays a second y-axis named
955
- // "y2" and the trace points at it via `yaxis: "y2"`.
1203
+ // Secondary value axis. Plotly overlays a second value axis ("y2",
1204
+ // or "x2" for a horizontal bar) and the trace points at it.
956
1205
  if (series.useSecondaryAxis) {
957
- target.yaxis = "y2";
1206
+ target[valueAxisKey] = secondaryValueAxisRef;
958
1207
  hasSecondaryAxis = true;
1208
+ // Secondary category axis for a second chart domain.
1209
+ if (secondaryDomainData) {
1210
+ target[categoryAxisKey] = secondaryCategoryAxisRef;
1211
+ hasSecondaryCategoryAxis = true;
1212
+ }
959
1213
  }
960
1214
  // Error bars — native plotly `error_y` / `error_x`. valueType
961
1215
  // "custom" reads per-point magnitudes from the spec's plus/minus
@@ -979,458 +1233,486 @@ var BasicChart = function (_a) {
979
1233
  // Trendlines — one overlay scatter trace per spec, reusing the
980
1234
  // shared regression util.
981
1235
  var seriesColor = (_g = series.color) !== null && _g !== void 0 ? _g : theme.themeColors.accent1;
1236
+ var _loop_3 = function (tl) {
1237
+ var _p, _q;
1238
+ var result = (0, trendline_1.computeTrendline)(values, {
1239
+ type: tl.type,
1240
+ order: tl.order,
1241
+ period: tl.period,
1242
+ forecastForward: tl.forecastForward,
1243
+ forecastBackward: tl.forecastBackward,
1244
+ });
1245
+ if (!result || result.points.length < 2)
1246
+ return "continue";
1247
+ var tlName = (_j = tl.name) !== null && _j !== void 0 ? _j : "".concat(dataLabel ? dataLabel + " " : "").concat((_k = tl.type) !== null && _k !== void 0 ? _k : "linear", " trend");
1248
+ // Map the fitted x (category index) back onto the category
1249
+ // labels where possible so the line aligns with the data.
1250
+ var categories = categoriesFor(series);
1251
+ var xs = result.points.map(function (p) {
1252
+ return p.x >= 0 && p.x < categories.length ? categories[p.x] : p.x;
1253
+ });
1254
+ var ys = result.points.map(function (p) { return p.y; });
1255
+ var overlay = tslib_1.__assign(tslib_1.__assign({ type: "scatter", mode: "lines", name: tlName, line: {
1256
+ color: (_l = tl.color) !== null && _l !== void 0 ? _l : seriesColor,
1257
+ dash: "dash",
1258
+ width: 2,
1259
+ }, hoverinfo: "skip" }, (series.useSecondaryAxis
1260
+ ? (_p = {}, _p[valueAxisKey] = secondaryValueAxisRef, _p) : {})), (series.useSecondaryAxis && secondaryDomainData
1261
+ ? (_q = {}, _q[categoryAxisKey] = secondaryCategoryAxisRef, _q) : {}));
1262
+ if (isHorizontalBarChart) {
1263
+ overlay.x = ys;
1264
+ overlay.y = xs;
1265
+ overlay.orientation = "h";
1266
+ }
1267
+ else {
1268
+ overlay.x = xs;
1269
+ overlay.y = ys;
1270
+ }
1271
+ traces.push(overlay);
1272
+ };
982
1273
  try {
983
1274
  for (var _m = tslib_1.__values((_h = series.trendlines) !== null && _h !== void 0 ? _h : []), _o = _m.next(); !_o.done; _o = _m.next()) {
984
1275
  var tl = _o.value;
985
- var result = (0, trendline_1.computeTrendline)(values, {
986
- type: tl.type,
987
- order: tl.order,
988
- period: tl.period,
989
- forecastForward: tl.forecastForward,
990
- forecastBackward: tl.forecastBackward,
991
- });
992
- if (!result || result.points.length < 2)
993
- continue;
994
- var tlName = (_j = tl.name) !== null && _j !== void 0 ? _j : "".concat(dataLabel ? dataLabel + " " : "").concat((_k = tl.type) !== null && _k !== void 0 ? _k : "linear", " trend");
995
- // Map the fitted x (category index) back onto the category
996
- // labels where possible so the line aligns with the data.
997
- var xs = result.points.map(function (p) {
998
- return p.x >= 0 && p.x < domainData.length ? domainData[p.x] : p.x;
999
- });
1000
- var ys = result.points.map(function (p) { return p.y; });
1001
- var overlay = tslib_1.__assign({ type: "scatter", mode: "lines", name: tlName, line: {
1002
- color: (_l = tl.color) !== null && _l !== void 0 ? _l : seriesColor,
1003
- dash: "dash",
1004
- width: 2,
1005
- }, hoverinfo: "skip" }, (series.useSecondaryAxis ? { yaxis: "y2" } : {}));
1006
- if (isHorizontalBarChart) {
1007
- overlay.x = ys;
1008
- overlay.y = xs;
1009
- overlay.orientation = "h";
1010
- }
1011
- else {
1012
- overlay.x = xs;
1013
- overlay.y = ys;
1014
- }
1015
- traces.push(overlay);
1276
+ _loop_3(tl);
1016
1277
  }
1017
1278
  }
1018
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1279
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
1019
1280
  finally {
1020
1281
  try {
1021
1282
  if (_o && !_o.done && (_a = _m.return)) _a.call(_m);
1022
1283
  }
1023
- finally { if (e_5) throw e_5.error; }
1284
+ finally { if (e_6) throw e_6.error; }
1024
1285
  }
1025
1286
  };
1287
+ domainSources = (_51 = (_50 = (_49 = spec.domains) === null || _49 === void 0 ? void 0 : _49[0]) === null || _50 === void 0 ? void 0 : _50.sources) !== null && _51 !== void 0 ? _51 : [];
1026
1288
  seriesIndex = 0;
1027
- _53.label = 7;
1028
- case 7:
1029
- _53.trys.push([7, 14, 15, 16]);
1030
- _e = tslib_1.__values((_38 = spec.series) !== null && _38 !== void 0 ? _38 : []), _f = _e.next();
1031
- _53.label = 8;
1032
- case 8:
1033
- if (!!_f.done) return [3 /*break*/, 13];
1034
- series = _f.value;
1035
- currentSeriesIndex = seriesIndex++;
1036
- if (!(!(0, utils_1.isNil)(series.dataLabel) && (0, utils_1.isAFormula)(series.dataLabel))) return [3 /*break*/, 10];
1037
- _h = chart_spec_utils_1.coerceCalculatedLabel;
1038
- return [4 /*yield*/, onRequestCalculate(series.dataLabel, (_39 = position.sheetId) !== null && _39 !== void 0 ? _39 : sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex)];
1039
- case 9:
1040
- _g = _h.apply(void 0, [_53.sent()]);
1041
- return [3 /*break*/, 11];
1042
- case 10:
1043
- _g = (_40 = series.dataLabel) !== null && _40 !== void 0 ? _40 : "";
1044
- _53.label = 11;
1045
- case 11:
1046
- dataLabel = _g;
1047
- _loop_2 = function (sheetRange) {
1048
- var seriesData = getSeriesData(spec, sheetRange, {
1049
- aggregateEnabled: shouldAggregate,
1050
- aggregateType: series.aggregateType,
1051
- rawDomainValues: rawPrimaryDomainValues,
1052
- orderedDomainValues: domainData,
1053
- });
1054
- // Support per-series chart type for combo charts
1055
- var effectiveChartType = (_41 = series.seriesChartType) !== null && _41 !== void 0 ? _41 : spec.chartType;
1056
- var seriesPlotlyType = (0, helpers_1.chartTypeToPlotlyType)(effectiveChartType);
1057
- var seriesTraceStyle = (0, helpers_1.getPlotlyTraceStyle)(effectiveChartType);
1058
- if (effectiveChartType === "histogram") {
1059
- var rawValues = "values" in seriesData
1060
- ? seriesData.values
1061
- : seriesData;
1062
- var binCount = spec.binCount;
1063
- if (isPareto) {
1064
- // Plotly's native histogram trace bins in axis order and
1065
- // can't reorder bins, so Pareto pre-bins with the shared
1066
- // util, sorts descending, and renders a bar trace plus the
1067
- // cumulative-% line pointed at the y2 overlay axis.
1068
- var _54 = (0, histogram_1.computePareto)((0, histogram_1.binHistogram)(rawValues, binCount)), labels = _54.labels, counts = _54.counts, cumulativePercents = _54.cumulativePercents;
1069
- var barTrace = {
1070
- type: "bar",
1071
- x: labels,
1072
- y: counts,
1073
- name: dataLabel,
1074
- };
1075
- applyTraceColor(barTrace, (_42 = series.color) !== null && _42 !== void 0 ? _42 : undefined, {
1076
- noFill: series.noFill,
1077
- dataPointColors: series.dataPointColors,
1078
- seriesIndex: currentSeriesIndex,
1079
- effectiveChartType: effectiveChartType,
1080
- });
1081
- traces.push(barTrace);
1082
- traces.push({
1083
- type: "scatter",
1084
- mode: "lines+markers",
1085
- x: labels,
1086
- y: cumulativePercents,
1087
- name: "Cumulative %",
1088
- yaxis: "y2",
1089
- });
1090
- hasSecondaryAxis = true;
1091
- }
1092
- else {
1093
- var trace = tslib_1.__assign({ type: "histogram", x: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }), name: dataLabel }, (typeof binCount === "number" && binCount > 0
1094
- ? { nbinsx: binCount }
1095
- : {}));
1096
- applyTraceColor(trace, (_43 = series.color) !== null && _43 !== void 0 ? _43 : undefined, {
1097
- noFill: series.noFill,
1098
- dataPointColors: series.dataPointColors,
1099
- seriesIndex: currentSeriesIndex,
1100
- effectiveChartType: effectiveChartType,
1101
- });
1102
- traces.push(trace);
1103
- }
1104
- }
1105
- else if (effectiveChartType === "boxplot") {
1106
- var rawValues = "values" in seriesData
1107
- ? seriesData.values
1108
- : seriesData;
1109
- var quartileMethod = spec.quartileMethod;
1110
- var showOutliers = spec.showOutliers;
1111
- var showMeanMarker = spec.showMeanMarker === true;
1112
- // Plotly's box trace computes quartiles/fences itself from
1113
- // raw values, so a spec-pinned quartile method (or Excel's
1114
- // "no outliers → whiskers span min/max" semantics) requires
1115
- // switching to plotly's precomputed-statistics signature
1116
- // (q1/median/q3/lowerfence/upperfence arrays). When neither
1117
- // option is set the raw-values trace is kept unchanged.
1118
- var usePrecomputed = quartileMethod != null || showOutliers === false;
1119
- var trace = void 0;
1120
- if (usePrecomputed) {
1121
- var summary = (0, boxplot_1.computeBoxplotSummary)(rawValues, {
1122
- quartileMethod: quartileMethod,
1123
- });
1124
- if (!summary)
1125
- return "continue";
1126
- var hideOutliers = showOutliers === false;
1127
- trace = tslib_1.__assign(tslib_1.__assign({ type: "box", name: dataLabel,
1128
- // Precomputed boxes need an explicit category so each
1129
- // series lands on its own slot (raw mode derives it from
1130
- // the trace name).
1131
- x: [dataLabel || "trace ".concat(currentSeriesIndex)], q1: [summary.q1], median: [summary.median], q3: [summary.q3],
1132
- // Excel: hiding outlier points extends the whiskers to
1133
- // the full min/max; with outliers shown they stop at the
1134
- // most extreme points inside the 1.5×IQR fences.
1135
- lowerfence: [hideOutliers ? summary.min : summary.lowerWhisker], upperfence: [hideOutliers ? summary.max : summary.upperWhisker] }, (hideOutliers
1136
- ? { boxpoints: false }
1137
- : {
1138
- // Sample points ride along so plotly can still draw
1139
- // the outlier dots against the precomputed fences.
1140
- y: [rawValues.filter(function (v) { return v != null; })],
1141
- boxpoints: "outliers",
1142
- })), (showMeanMarker
1143
- ? { mean: [summary.mean], boxmean: true }
1144
- : {}));
1145
- }
1146
- else {
1147
- trace = tslib_1.__assign({ type: "box", y: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }), name: dataLabel,
1148
- // Raw mode is used when outliers are visible (today's
1149
- // default and `showOutliers: true` alike).
1150
- boxpoints: "outliers" }, (showMeanMarker ? { boxmean: true } : {}));
1151
- }
1152
- applyTraceColor(trace, (_44 = series.color) !== null && _44 !== void 0 ? _44 : undefined, {
1153
- noFill: series.noFill,
1154
- dataPointColors: series.dataPointColors,
1155
- seriesIndex: currentSeriesIndex,
1156
- effectiveChartType: effectiveChartType,
1157
- });
1158
- traces.push(trace);
1159
- }
1160
- else if (effectiveChartType === "waterfall") {
1161
- var rawValues = "values" in seriesData
1162
- ? seriesData.values
1163
- : seriesData;
1164
- // Plotly's native waterfall draws connector lines itself and
1165
- // renders "total" measures from the zero baseline with its
1166
- // own distinct fill.
1167
- var totalIndices_1 = new Set((_45 = spec.totalIndices) !== null && _45 !== void 0 ? _45 : []);
1168
- var trace = {
1169
- type: "waterfall",
1170
- x: domainData,
1171
- y: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }),
1172
- measure: rawValues.map(function (_, i) {
1173
- return totalIndices_1.has(i) ? "total" : "relative";
1174
- }),
1175
- name: dataLabel,
1176
- };
1177
- applyTraceColor(trace, (_46 = series.color) !== null && _46 !== void 0 ? _46 : undefined, {
1178
- noFill: series.noFill,
1179
- dataPointColors: series.dataPointColors,
1180
- seriesIndex: currentSeriesIndex,
1181
- effectiveChartType: effectiveChartType,
1182
- });
1183
- traces.push(trace);
1184
- }
1185
- else if (effectiveChartType === "funnel") {
1186
- var rawValues = "values" in seriesData
1187
- ? seriesData.values
1188
- : seriesData;
1189
- var trace = {
1190
- type: "funnel",
1191
- y: domainData,
1192
- x: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }),
1193
- name: dataLabel,
1194
- };
1195
- applyTraceColor(trace, (_47 = series.color) !== null && _47 !== void 0 ? _47 : undefined, {
1196
- noFill: series.noFill,
1197
- dataPointColors: series.dataPointColors,
1198
- seriesIndex: currentSeriesIndex,
1199
- effectiveChartType: effectiveChartType,
1200
- });
1201
- traces.push(trace);
1202
- }
1203
- else if (effectiveChartType === "pie" && isOfPie) {
1204
- // Pie-of-pie / bar-of-pie — split the minor slices into a
1205
- // secondary pie or stacked bar beside the main pie, replace
1206
- // them with an aggregated "Other" slice, and join the two
1207
- // plots with connector-line shapes. Only the first pie series
1208
- // participates (of-pie is a single-series chart in Excel).
1209
- if (ofPieHandled)
1210
- return "continue";
1211
- ofPieHandled = true;
1212
- var pieData = seriesData;
1213
- var _55 = (0, of_pie_1.splitOfPie)(pieData.values, pieData.labels, {
1214
- splitType: spec.splitType,
1215
- splitPos: spec.splitPos,
1216
- }), main_1 = _55.main, secondary = _55.secondary, otherTotal = _55.otherTotal, total = _55.total;
1217
- var ofPieType = (0, of_pie_1.resolveOfPieType)(spec.ofPieType);
1218
- var secondScale = (0, of_pie_1.clampSecondPieSize)(spec.secondPieSize) / 100;
1219
- var halfAngle = (0, of_pie_1.otherSliceHalfAngle)(otherTotal, total);
1220
- var paletteAt_1 = function (index) {
1221
- return themeColorPalette[index % themeColorPalette.length];
1222
- };
1223
- // Layout in paper coordinates (0-1 across the plot area
1224
- // inside the margins). Main pie on the left, secondary plot
1225
- // on the right.
1226
- var MAIN_DOMAIN_X = [0, 0.55];
1227
- var CY = 0.5;
1228
- var SECONDARY_CX = 0.78;
1229
- var BAR_LEFT = 0.68;
1230
- var BAR_RIGHT = 0.88;
1231
- traces.push({
1232
- type: "pie",
1233
- values: main_1.map(function (s) { return s.value; }),
1234
- labels: main_1.map(function (s) { return s.label; }),
1235
- name: dataLabel,
1236
- domain: { x: MAIN_DOMAIN_X, y: [0, 1] },
1237
- sort: false,
1238
- direction: "clockwise",
1239
- // Rotate so the "Other" slice's angular midpoint faces the
1240
- // secondary plot (Excel's layout). Other is the last slice
1241
- // of a clockwise sweep starting at `rotation`° from 12
1242
- // o'clock, so its midpoint lands at 3 o'clock when the
1243
- // sweep starts 90° + halfAngle past the top.
1244
- rotation: (90 + (halfAngle * 180) / Math.PI) % 360,
1245
- marker: { colors: main_1.map(function (_, i) { return paletteAt_1(i); }) },
1246
- });
1247
- if (secondary.length > 0) {
1248
- // Paper coords are relative while the pie is circular in
1249
- // pixels — convert the main pie's pixel radius into
1250
- // separate x/y paper fractions to compensate for the
1251
- // aspect ratio. Falls back to fixed fractions when the
1252
- // container size isn't known yet.
1253
- var plotW = typeof width === "number" ? Math.max(1, width - 102) : 0;
1254
- var plotH = typeof height === "number" ? Math.max(1, height - 102) : 0;
1255
- var hasGeometry = plotW > 1 && plotH > 1;
1256
- var r = hasGeometry
1257
- ? Math.min((MAIN_DOMAIN_X[1] - MAIN_DOMAIN_X[0]) * plotW, plotH) / 2
1258
- : 0;
1259
- var r2 = r * secondScale;
1260
- var clampFrac = function (v, min, max) {
1261
- return Math.min(max, Math.max(min, v));
1262
- };
1263
- var rx2 = clampFrac(hasGeometry ? r2 / plotW : 0.14 * secondScale, 0.03, 0.19);
1264
- var ry2 = clampFrac(hasGeometry ? r2 / plotH : 0.28 * secondScale, 0.05, 0.45);
1265
- var barHalf = ry2;
1266
- if (ofPieType === "pie") {
1267
- traces.push({
1268
- type: "pie",
1269
- values: secondary.map(function (s) { return s.value; }),
1270
- labels: secondary.map(function (s) { return s.label; }),
1271
- name: dataLabel,
1272
- domain: {
1273
- x: [SECONDARY_CX - rx2, SECONDARY_CX + rx2],
1274
- y: [CY - ry2, CY + ry2],
1275
- },
1276
- sort: false,
1277
- direction: "clockwise",
1278
- marker: {
1279
- colors: secondary.map(function (_, i) { return paletteAt_1(main_1.length + i); }),
1280
- },
1281
- });
1282
- }
1283
- else {
1284
- // Bar-of-pie — a single-category stacked bar on hidden
1285
- // secondary axes; one trace per point so each segment
1286
- // keeps its own color and legend entry.
1287
- secondary.forEach(function (s, i) {
1289
+ _loop_2 = function (series) {
1290
+ var currentSeriesIndex, dataLabel, _70, _71, effectiveChartType, lineLike, pieDomainLabels, piePointOffset, seriesData, seriesPlotlyType, seriesTraceStyle, rawValues, binCount, _72, labels, counts, cumulativePercents, barTrace, trace, rawValues, quartileMethod, showOutliers, showMeanMarker, usePrecomputed, trace, summary, hideOutliers, rawValues, totalIndices_1, trace, rawValues, trace, pieData, _73, main_1, secondary, otherTotal, total, ofPieType, secondScale, halfAngle, paletteAt_1, MAIN_DOMAIN_X, CY, SECONDARY_CX, BAR_LEFT, BAR_RIGHT, plotW, plotH, hasGeometry, r, r2, clampFrac, rx2, ry2, barHalf, shapes, connectorColor, mainCx, px, pyTop, pyBottom, tx, half, line, pieData, trace, _74, x, y, orientation_1, trace, numericValues, _75, x, y, orientation_2, trace;
1291
+ return tslib_1.__generator(this, function (_76) {
1292
+ switch (_76.label) {
1293
+ case 0:
1294
+ currentSeriesIndex = seriesIndex++;
1295
+ if (!(!(0, utils_1.isNil)(series.dataLabel) && (0, utils_1.isAFormula)(series.dataLabel))) return [3 /*break*/, 2];
1296
+ _71 = chart_spec_utils_1.coerceCalculatedLabel;
1297
+ return [4 /*yield*/, onRequestCalculate(series.dataLabel, (_53 = position.sheetId) !== null && _53 !== void 0 ? _53 : sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex)];
1298
+ case 1:
1299
+ _70 = _71.apply(void 0, [_76.sent()]);
1300
+ return [3 /*break*/, 3];
1301
+ case 2:
1302
+ _70 = (_54 = series.dataLabel) !== null && _54 !== void 0 ? _54 : "";
1303
+ _76.label = 3;
1304
+ case 3:
1305
+ dataLabel = _70;
1306
+ // A series with no ranges draws nothing.
1307
+ if (series.sources.length === 0)
1308
+ return [2 /*return*/, "continue"];
1309
+ effectiveChartType = (_55 = series.seriesChartType) !== null && _55 !== void 0 ? _55 : spec.chartType;
1310
+ lineLike = (0, empty_cells_1.isLineLikeChartType)(effectiveChartType);
1311
+ pieDomainLabels = (spec.chartType === "pie" || spec.chartType === "doughnut") &&
1312
+ (domainSources.length > 1 || series.sources.length > 1)
1313
+ ? domainSources.flatMap(function (sheetRange) {
1314
+ var _a;
1315
+ return (_a = getDomainValuesFromRange(sheetRange, spec.hiddenDimensionStrategy)) !== null && _a !== void 0 ? _a : [];
1316
+ })
1317
+ : undefined;
1318
+ piePointOffset = 0;
1319
+ seriesData = mergeSeriesData(series.sources.map(function (sheetRange) {
1320
+ var part = getSeriesData(spec, sheetRange, {
1321
+ aggregateEnabled: shouldAggregate,
1322
+ aggregateType: series.aggregateType,
1323
+ rawDomainValues: rawPrimaryDomainValues,
1324
+ orderedDomainValues: aggregateDomainValues,
1325
+ lineLike: lineLike,
1326
+ pieLabels: pieDomainLabels
1327
+ ? {
1328
+ domainLabels: pieDomainLabels,
1329
+ offset: series.sources.length > 1 ? piePointOffset : undefined,
1330
+ }
1331
+ : undefined,
1332
+ });
1333
+ if (!Array.isArray(part))
1334
+ piePointOffset += part.values.length;
1335
+ return part;
1336
+ }));
1337
+ seriesPlotlyType = (0, helpers_1.chartTypeToPlotlyType)(effectiveChartType);
1338
+ seriesTraceStyle = tslib_1.__assign(tslib_1.__assign({}, (0, helpers_1.getPlotlyTraceStyle)(effectiveChartType)), ((0, empty_cells_1.connectsAcrossEmptyCells)(spec, lineLike)
1339
+ ? { connectgaps: true }
1340
+ : {}));
1341
+ if (effectiveChartType === "histogram") {
1342
+ rawValues = "values" in seriesData
1343
+ ? seriesData.values
1344
+ : seriesData;
1345
+ binCount = spec.binCount;
1346
+ if (isPareto) {
1347
+ _72 = (0, histogram_1.computePareto)((0, histogram_1.binHistogram)(rawValues, binCount)), labels = _72.labels, counts = _72.counts, cumulativePercents = _72.cumulativePercents;
1348
+ barTrace = {
1349
+ type: "bar",
1350
+ x: labels,
1351
+ y: counts,
1352
+ name: dataLabel,
1353
+ };
1354
+ applyTraceColor(barTrace, (_56 = series.color) !== null && _56 !== void 0 ? _56 : undefined, {
1355
+ noFill: series.noFill,
1356
+ dataPointColors: series.dataPointColors,
1357
+ seriesIndex: currentSeriesIndex,
1358
+ effectiveChartType: effectiveChartType,
1359
+ });
1360
+ traces.push(barTrace);
1361
+ traces.push({
1362
+ type: "scatter",
1363
+ mode: "lines+markers",
1364
+ x: labels,
1365
+ y: cumulativePercents,
1366
+ name: "Cumulative %",
1367
+ yaxis: "y2",
1368
+ });
1369
+ hasSecondaryAxis = true;
1370
+ }
1371
+ else {
1372
+ trace = tslib_1.__assign({ type: "histogram", x: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }), name: dataLabel }, (typeof binCount === "number" && binCount > 0
1373
+ ? { nbinsx: binCount }
1374
+ : {}));
1375
+ applyTraceColor(trace, (_57 = series.color) !== null && _57 !== void 0 ? _57 : undefined, {
1376
+ noFill: series.noFill,
1377
+ dataPointColors: series.dataPointColors,
1378
+ seriesIndex: currentSeriesIndex,
1379
+ effectiveChartType: effectiveChartType,
1380
+ });
1381
+ traces.push(trace);
1382
+ }
1383
+ }
1384
+ else if (effectiveChartType === "boxplot") {
1385
+ rawValues = "values" in seriesData
1386
+ ? seriesData.values
1387
+ : seriesData;
1388
+ quartileMethod = spec.quartileMethod;
1389
+ showOutliers = spec.showOutliers;
1390
+ showMeanMarker = spec.showMeanMarker === true;
1391
+ usePrecomputed = quartileMethod != null || showOutliers === false;
1392
+ trace = void 0;
1393
+ if (usePrecomputed) {
1394
+ summary = (0, boxplot_1.computeBoxplotSummary)(rawValues, {
1395
+ quartileMethod: quartileMethod,
1396
+ });
1397
+ if (!summary)
1398
+ return [2 /*return*/, "continue"];
1399
+ hideOutliers = showOutliers === false;
1400
+ trace = tslib_1.__assign(tslib_1.__assign({ type: "box", name: dataLabel,
1401
+ // Precomputed boxes need an explicit category so each
1402
+ // series lands on its own slot (raw mode derives it from
1403
+ // the trace name).
1404
+ x: [dataLabel || "trace ".concat(currentSeriesIndex)], q1: [summary.q1], median: [summary.median], q3: [summary.q3],
1405
+ // Excel: hiding outlier points extends the whiskers to
1406
+ // the full min/max; with outliers shown they stop at the
1407
+ // most extreme points inside the 1.5×IQR fences.
1408
+ lowerfence: [hideOutliers ? summary.min : summary.lowerWhisker], upperfence: [hideOutliers ? summary.max : summary.upperWhisker] }, (hideOutliers
1409
+ ? { boxpoints: false }
1410
+ : {
1411
+ // Sample points ride along so plotly can still draw
1412
+ // the outlier dots against the precomputed fences.
1413
+ y: [rawValues.filter(function (v) { return v != null; })],
1414
+ boxpoints: "outliers",
1415
+ })), (showMeanMarker
1416
+ ? { mean: [summary.mean], boxmean: true }
1417
+ : {}));
1418
+ }
1419
+ else {
1420
+ trace = tslib_1.__assign({ type: "box", y: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }), name: dataLabel,
1421
+ // Raw mode is used when outliers are visible (today's
1422
+ // default and `showOutliers: true` alike).
1423
+ boxpoints: "outliers" }, (showMeanMarker ? { boxmean: true } : {}));
1424
+ }
1425
+ applyTraceColor(trace, (_58 = series.color) !== null && _58 !== void 0 ? _58 : undefined, {
1426
+ noFill: series.noFill,
1427
+ dataPointColors: series.dataPointColors,
1428
+ seriesIndex: currentSeriesIndex,
1429
+ effectiveChartType: effectiveChartType,
1430
+ });
1431
+ traces.push(trace);
1432
+ }
1433
+ else if (effectiveChartType === "waterfall") {
1434
+ rawValues = "values" in seriesData
1435
+ ? seriesData.values
1436
+ : seriesData;
1437
+ totalIndices_1 = new Set((_59 = spec.totalIndices) !== null && _59 !== void 0 ? _59 : []);
1438
+ trace = {
1439
+ type: "waterfall",
1440
+ x: categoriesFor(series),
1441
+ y: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }),
1442
+ measure: rawValues.map(function (_, i) {
1443
+ return totalIndices_1.has(i) ? "total" : "relative";
1444
+ }),
1445
+ name: dataLabel,
1446
+ };
1447
+ applyTraceColor(trace, (_60 = series.color) !== null && _60 !== void 0 ? _60 : undefined, {
1448
+ noFill: series.noFill,
1449
+ dataPointColors: series.dataPointColors,
1450
+ seriesIndex: currentSeriesIndex,
1451
+ effectiveChartType: effectiveChartType,
1452
+ });
1453
+ traces.push(trace);
1454
+ }
1455
+ else if (effectiveChartType === "funnel") {
1456
+ rawValues = "values" in seriesData
1457
+ ? seriesData.values
1458
+ : seriesData;
1459
+ trace = {
1460
+ type: "funnel",
1461
+ y: categoriesFor(series),
1462
+ x: rawValues.map(function (v) { return (v !== null && v !== void 0 ? v : null); }),
1463
+ name: dataLabel,
1464
+ };
1465
+ applyTraceColor(trace, (_61 = series.color) !== null && _61 !== void 0 ? _61 : undefined, {
1466
+ noFill: series.noFill,
1467
+ dataPointColors: series.dataPointColors,
1468
+ seriesIndex: currentSeriesIndex,
1469
+ effectiveChartType: effectiveChartType,
1470
+ });
1471
+ traces.push(trace);
1472
+ }
1473
+ else if (effectiveChartType === "pie" && isOfPie) {
1474
+ // Pie-of-pie / bar-of-pie — split the minor slices into a
1475
+ // secondary pie or stacked bar beside the main pie, replace
1476
+ // them with an aggregated "Other" slice, and join the two
1477
+ // plots with connector-line shapes. Only the first pie series
1478
+ // participates (of-pie is a single-series chart in Excel).
1479
+ if (ofPieHandled)
1480
+ return [2 /*return*/, "continue"];
1481
+ ofPieHandled = true;
1482
+ pieData = seriesData;
1483
+ _73 = (0, of_pie_1.splitOfPie)(pieData.values, pieData.labels, {
1484
+ splitType: spec.splitType,
1485
+ splitPos: spec.splitPos,
1486
+ }), main_1 = _73.main, secondary = _73.secondary, otherTotal = _73.otherTotal, total = _73.total;
1487
+ ofPieType = (0, of_pie_1.resolveOfPieType)(spec.ofPieType);
1488
+ secondScale = (0, of_pie_1.clampSecondPieSize)(spec.secondPieSize) / 100;
1489
+ halfAngle = (0, of_pie_1.otherSliceHalfAngle)(otherTotal, total);
1490
+ paletteAt_1 = function (index) {
1491
+ return themeColorPalette[index % themeColorPalette.length];
1492
+ };
1493
+ MAIN_DOMAIN_X = [0, 0.55];
1494
+ CY = 0.5;
1495
+ SECONDARY_CX = 0.78;
1496
+ BAR_LEFT = 0.68;
1497
+ BAR_RIGHT = 0.88;
1288
1498
  traces.push({
1289
- type: "bar",
1290
- x: [""],
1291
- y: [s.value],
1292
- name: s.label,
1293
- xaxis: "x2",
1294
- yaxis: "y2",
1295
- marker: { color: paletteAt_1(main_1.length + i) },
1499
+ type: "pie",
1500
+ values: main_1.map(function (s) { return s.value; }),
1501
+ labels: main_1.map(function (s) { return s.label; }),
1502
+ name: dataLabel,
1503
+ domain: { x: MAIN_DOMAIN_X, y: [0, 1] },
1504
+ sort: false,
1505
+ direction: "clockwise",
1506
+ // Rotate so the "Other" slice's angular midpoint faces the
1507
+ // secondary plot (Excel's layout). Other is the last slice
1508
+ // of a clockwise sweep starting at `rotation`° from 12
1509
+ // o'clock, so its midpoint lands at 3 o'clock when the
1510
+ // sweep starts 90° + halfAngle past the top.
1511
+ rotation: (90 + (halfAngle * 180) / Math.PI) % 360,
1512
+ marker: { colors: main_1.map(function (_, i) { return paletteAt_1(i); }) },
1296
1513
  });
1297
- });
1298
- }
1299
- // Connector lines from the Other slice's edges to the top
1300
- // and bottom of the secondary plot. Skipped (gracefully)
1301
- // when the container size isn't known — pure paper-coord
1302
- // geometry can't compensate for the pixel aspect ratio.
1303
- var shapes = [];
1304
- if (hasGeometry) {
1305
- var connectorColor = isDarkMode
1306
- ? "rgba(255,255,255,0.45)"
1307
- : "#999999";
1308
- var mainCx = (MAIN_DOMAIN_X[0] + MAIN_DOMAIN_X[1]) / 2;
1309
- var px = mainCx + (r * Math.cos(halfAngle)) / plotW;
1310
- var pyTop = CY + (r * Math.sin(halfAngle)) / plotH;
1311
- var pyBottom = CY - (r * Math.sin(halfAngle)) / plotH;
1312
- var tx = ofPieType === "pie" ? SECONDARY_CX : BAR_LEFT;
1313
- var half = ofPieType === "pie" ? ry2 : barHalf;
1314
- var line = {
1315
- type: "line",
1316
- xref: "paper",
1317
- yref: "paper",
1318
- layer: "below",
1319
- line: { color: connectorColor, width: 1 },
1320
- };
1321
- shapes.push(tslib_1.__assign(tslib_1.__assign({}, line), { x0: px, y0: pyTop, x1: tx, y1: CY + half }), tslib_1.__assign(tslib_1.__assign({}, line), { x0: px, y0: pyBottom, x1: tx, y1: CY - half }));
1322
- }
1323
- ofPieExtras = tslib_1.__assign({ shapes: shapes }, (ofPieType === "bar"
1324
- ? {
1325
- barmode: "stack",
1326
- xaxis2: {
1327
- domain: [BAR_LEFT, BAR_RIGHT],
1328
- anchor: "y2",
1329
- visible: false,
1330
- fixedrange: true,
1331
- },
1332
- yaxis2: {
1333
- domain: [CY - barHalf, CY + barHalf],
1334
- anchor: "x2",
1335
- visible: false,
1336
- fixedrange: true,
1337
- },
1514
+ if (secondary.length > 0) {
1515
+ plotW = typeof width === "number" ? Math.max(1, width - 102) : 0;
1516
+ plotH = typeof height === "number" ? Math.max(1, height - 102) : 0;
1517
+ hasGeometry = plotW > 1 && plotH > 1;
1518
+ r = hasGeometry
1519
+ ? Math.min((MAIN_DOMAIN_X[1] - MAIN_DOMAIN_X[0]) * plotW, plotH) / 2
1520
+ : 0;
1521
+ r2 = r * secondScale;
1522
+ clampFrac = function (v, min, max) {
1523
+ return Math.min(max, Math.max(min, v));
1524
+ };
1525
+ rx2 = clampFrac(hasGeometry ? r2 / plotW : 0.14 * secondScale, 0.03, 0.19);
1526
+ ry2 = clampFrac(hasGeometry ? r2 / plotH : 0.28 * secondScale, 0.05, 0.45);
1527
+ barHalf = ry2;
1528
+ if (ofPieType === "pie") {
1529
+ traces.push({
1530
+ type: "pie",
1531
+ values: secondary.map(function (s) { return s.value; }),
1532
+ labels: secondary.map(function (s) { return s.label; }),
1533
+ name: dataLabel,
1534
+ domain: {
1535
+ x: [SECONDARY_CX - rx2, SECONDARY_CX + rx2],
1536
+ y: [CY - ry2, CY + ry2],
1537
+ },
1538
+ sort: false,
1539
+ direction: "clockwise",
1540
+ marker: {
1541
+ colors: secondary.map(function (_, i) { return paletteAt_1(main_1.length + i); }),
1542
+ },
1543
+ });
1544
+ }
1545
+ else {
1546
+ // Bar-of-pie — a single-category stacked bar on hidden
1547
+ // secondary axes; one trace per point so each segment
1548
+ // keeps its own color and legend entry.
1549
+ secondary.forEach(function (s, i) {
1550
+ traces.push({
1551
+ type: "bar",
1552
+ x: [""],
1553
+ y: [s.value],
1554
+ name: s.label,
1555
+ xaxis: "x2",
1556
+ yaxis: "y2",
1557
+ marker: { color: paletteAt_1(main_1.length + i) },
1558
+ });
1559
+ });
1560
+ }
1561
+ shapes = [];
1562
+ if (hasGeometry) {
1563
+ connectorColor = isDarkMode
1564
+ ? "rgba(255,255,255,0.45)"
1565
+ : "#999999";
1566
+ mainCx = (MAIN_DOMAIN_X[0] + MAIN_DOMAIN_X[1]) / 2;
1567
+ px = mainCx + (r * Math.cos(halfAngle)) / plotW;
1568
+ pyTop = CY + (r * Math.sin(halfAngle)) / plotH;
1569
+ pyBottom = CY - (r * Math.sin(halfAngle)) / plotH;
1570
+ tx = ofPieType === "pie" ? SECONDARY_CX : BAR_LEFT;
1571
+ half = ofPieType === "pie" ? ry2 : barHalf;
1572
+ line = {
1573
+ type: "line",
1574
+ xref: "paper",
1575
+ yref: "paper",
1576
+ layer: "below",
1577
+ line: { color: connectorColor, width: 1 },
1578
+ };
1579
+ shapes.push(tslib_1.__assign(tslib_1.__assign({}, line), { x0: px, y0: pyTop, x1: tx, y1: CY + half }), tslib_1.__assign(tslib_1.__assign({}, line), { x0: px, y0: pyBottom, x1: tx, y1: CY - half }));
1580
+ }
1581
+ ofPieExtras = tslib_1.__assign({ shapes: shapes }, (ofPieType === "bar"
1582
+ ? {
1583
+ barmode: "stack",
1584
+ xaxis2: {
1585
+ domain: [BAR_LEFT, BAR_RIGHT],
1586
+ anchor: "y2",
1587
+ visible: false,
1588
+ fixedrange: true,
1589
+ },
1590
+ yaxis2: {
1591
+ domain: [CY - barHalf, CY + barHalf],
1592
+ anchor: "x2",
1593
+ visible: false,
1594
+ fixedrange: true,
1595
+ },
1596
+ }
1597
+ : {}));
1598
+ }
1338
1599
  }
1339
- : {}));
1600
+ else if (effectiveChartType === "pie" ||
1601
+ effectiveChartType === "doughnut") {
1602
+ pieData = seriesData;
1603
+ trace = {
1604
+ type: seriesPlotlyType,
1605
+ values: pieData.values,
1606
+ labels: pieData.labels,
1607
+ name: dataLabel,
1608
+ marker: {
1609
+ colors: themeColorPalette,
1610
+ },
1611
+ };
1612
+ // Ties the trace back to spec.series for click selection and
1613
+ // the series' own number format
1614
+ trace.meta = {
1615
+ rncSeriesIndex: currentSeriesIndex,
1616
+ };
1617
+ applyTraceColor(trace, (_62 = series.color) !== null && _62 !== void 0 ? _62 : undefined, {
1618
+ noFill: series.noFill,
1619
+ dataPointColors: series.dataPointColors,
1620
+ seriesIndex: currentSeriesIndex,
1621
+ effectiveChartType: effectiveChartType,
1622
+ });
1623
+ traces.push(trace);
1624
+ }
1625
+ else if ("values" in seriesData && "labels" in seriesData) {
1626
+ _74 = assignCartesianData(categoriesFor(series), seriesData.values), x = _74.x, y = _74.y, orientation_1 = _74.orientation;
1627
+ trace = tslib_1.__assign(tslib_1.__assign({ type: seriesPlotlyType, x: x, y: y, orientation: orientation_1, name: dataLabel, stackgroup: isStacked ? "one" : undefined }, seriesTraceStyle), lineTraceVariant(series, effectiveChartType));
1628
+ // Ties the trace back to spec.series for click selection
1629
+ trace.meta = {
1630
+ rncSeriesIndex: currentSeriesIndex,
1631
+ };
1632
+ applyTraceColor(trace, (_63 = series.color) !== null && _63 !== void 0 ? _63 : undefined, {
1633
+ noFill: series.noFill,
1634
+ dataPointColors: series.dataPointColors,
1635
+ invertIfNegative: series.invertIfNegative,
1636
+ negativeColor: series.negativeColor,
1637
+ values: seriesData.values,
1638
+ seriesIndex: currentSeriesIndex,
1639
+ effectiveChartType: effectiveChartType,
1640
+ gradientColor: (0, gradient_1.gradientToPlotly)(series.gradient),
1641
+ });
1642
+ decorateCartesianTrace(trace, series, seriesData.values, dataLabel);
1643
+ traces.push(trace);
1644
+ }
1645
+ else {
1646
+ numericValues = seriesData;
1647
+ _75 = assignCartesianData(categoriesFor(series), numericValues), x = _75.x, y = _75.y, orientation_2 = _75.orientation;
1648
+ trace = tslib_1.__assign(tslib_1.__assign({ type: seriesPlotlyType, x: x, y: y, orientation: orientation_2, name: dataLabel, stackgroup: isStacked ? "one" : undefined }, seriesTraceStyle), lineTraceVariant(series, effectiveChartType));
1649
+ // Ties the trace back to spec.series for click selection
1650
+ trace.meta = {
1651
+ rncSeriesIndex: currentSeriesIndex,
1652
+ };
1653
+ applyTraceColor(trace, (_64 = series.color) !== null && _64 !== void 0 ? _64 : undefined, {
1654
+ noFill: series.noFill,
1655
+ dataPointColors: series.dataPointColors,
1656
+ invertIfNegative: series.invertIfNegative,
1657
+ negativeColor: series.negativeColor,
1658
+ values: numericValues,
1659
+ seriesIndex: currentSeriesIndex,
1660
+ effectiveChartType: effectiveChartType,
1661
+ gradientColor: (0, gradient_1.gradientToPlotly)(series.gradient),
1662
+ });
1663
+ decorateCartesianTrace(trace, series, numericValues, dataLabel);
1664
+ traces.push(trace);
1665
+ }
1666
+ return [2 /*return*/];
1340
1667
  }
1341
- }
1342
- else if (effectiveChartType === "pie") {
1343
- var pieData = seriesData;
1344
- var trace = {
1345
- type: seriesPlotlyType,
1346
- values: pieData.values,
1347
- labels: pieData.labels,
1348
- name: dataLabel,
1349
- marker: {
1350
- colors: [
1351
- theme.themeColors.accent1,
1352
- theme.themeColors.accent2,
1353
- theme.themeColors.accent3,
1354
- theme.themeColors.accent4,
1355
- theme.themeColors.accent5,
1356
- theme.themeColors.accent6,
1357
- ],
1358
- },
1359
- };
1360
- applyTraceColor(trace, (_48 = series.color) !== null && _48 !== void 0 ? _48 : undefined, {
1361
- noFill: series.noFill,
1362
- dataPointColors: series.dataPointColors,
1363
- seriesIndex: currentSeriesIndex,
1364
- effectiveChartType: effectiveChartType,
1365
- });
1366
- traces.push(trace);
1367
- }
1368
- else if ("values" in seriesData && "labels" in seriesData) {
1369
- var _56 = assignCartesianData(domainData, seriesData.values), x = _56.x, y = _56.y, orientation_1 = _56.orientation;
1370
- var trace = tslib_1.__assign({ type: seriesPlotlyType, x: x, y: y, orientation: orientation_1, name: dataLabel, stackgroup: isStacked ? "one" : undefined }, seriesTraceStyle);
1371
- applyTraceColor(trace, (_49 = series.color) !== null && _49 !== void 0 ? _49 : undefined, {
1372
- noFill: series.noFill,
1373
- dataPointColors: series.dataPointColors,
1374
- invertIfNegative: series.invertIfNegative,
1375
- negativeColor: series.negativeColor,
1376
- values: seriesData.values,
1377
- seriesIndex: currentSeriesIndex,
1378
- effectiveChartType: effectiveChartType,
1379
- gradientColor: (0, gradient_1.gradientToPlotly)(series.gradient),
1380
- });
1381
- decorateCartesianTrace(trace, series, seriesData.values, dataLabel);
1382
- traces.push(trace);
1383
- }
1384
- else {
1385
- var numericValues = seriesData;
1386
- var _57 = assignCartesianData(domainData, numericValues), x = _57.x, y = _57.y, orientation_2 = _57.orientation;
1387
- var trace = tslib_1.__assign({ type: seriesPlotlyType, x: x, y: y, orientation: orientation_2, name: dataLabel, stackgroup: isStacked ? "one" : undefined }, seriesTraceStyle);
1388
- applyTraceColor(trace, (_50 = series.color) !== null && _50 !== void 0 ? _50 : undefined, {
1389
- noFill: series.noFill,
1390
- dataPointColors: series.dataPointColors,
1391
- invertIfNegative: series.invertIfNegative,
1392
- negativeColor: series.negativeColor,
1393
- values: numericValues,
1394
- seriesIndex: currentSeriesIndex,
1395
- effectiveChartType: effectiveChartType,
1396
- gradientColor: (0, gradient_1.gradientToPlotly)(series.gradient),
1397
- });
1398
- decorateCartesianTrace(trace, series, numericValues, dataLabel);
1399
- traces.push(trace);
1400
- }
1668
+ });
1401
1669
  };
1670
+ _69.label = 18;
1671
+ case 18:
1672
+ _69.trys.push([18, 23, 24, 25]);
1673
+ _j = tslib_1.__values((_52 = spec.series) !== null && _52 !== void 0 ? _52 : []), _k = _j.next();
1674
+ _69.label = 19;
1675
+ case 19:
1676
+ if (!!_k.done) return [3 /*break*/, 22];
1677
+ series = _k.value;
1678
+ return [5 /*yield**/, _loop_2(series)];
1679
+ case 20:
1680
+ _69.sent();
1681
+ _69.label = 21;
1682
+ case 21:
1683
+ _k = _j.next();
1684
+ return [3 /*break*/, 19];
1685
+ case 22: return [3 /*break*/, 25];
1686
+ case 23:
1687
+ e_3_1 = _69.sent();
1688
+ e_3 = { error: e_3_1 };
1689
+ return [3 /*break*/, 25];
1690
+ case 24:
1402
1691
  try {
1403
- for (_j = (e_3 = void 0, tslib_1.__values(series.sources)), _k = _j.next(); !_k.done; _k = _j.next()) {
1404
- sheetRange = _k.value;
1405
- _loop_2(sheetRange);
1406
- }
1407
- }
1408
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
1409
- finally {
1410
- try {
1411
- if (_k && !_k.done && (_o = _j.return)) _o.call(_j);
1412
- }
1413
- finally { if (e_3) throw e_3.error; }
1414
- }
1415
- _53.label = 12;
1416
- case 12:
1417
- _f = _e.next();
1418
- return [3 /*break*/, 8];
1419
- case 13: return [3 /*break*/, 16];
1420
- case 14:
1421
- e_1_1 = _53.sent();
1422
- e_1 = { error: e_1_1 };
1423
- return [3 /*break*/, 16];
1424
- case 15:
1425
- try {
1426
- if (_f && !_f.done && (_m = _e.return)) _m.call(_e);
1692
+ if (_k && !_k.done && (_o = _j.return)) _o.call(_j);
1427
1693
  }
1428
- finally { if (e_1) throw e_1.error; }
1694
+ finally { if (e_3) throw e_3.error; }
1429
1695
  return [7 /*endfinally*/];
1430
- case 16:
1696
+ case 25:
1431
1697
  authoredTitleFmt = spec.titleTextFormat;
1432
- newLayout = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ title: {
1433
- text: title !== null && title !== void 0 ? title : undefined,
1698
+ isPercentStackedBars = spec.stackedType === "PERCENT_STACKED" &&
1699
+ (spec.chartType === "bar" || spec.chartType === "column");
1700
+ primaryAxisNumberFormat = isPercentStackedBars
1701
+ ? undefined
1702
+ : (0, axis_number_format_1.resolveValueAxisNumberFormat)({
1703
+ axisOptions: spec.valueAxisOptions,
1704
+ series: ((_65 = spec.series) !== null && _65 !== void 0 ? _65 : []).filter(function (s) { return !s.useSecondaryAxis; }),
1705
+ getFormattingFromRange: getFormattingFromRange,
1706
+ hiddenDimensionStrategy: spec.hiddenDimensionStrategy,
1707
+ });
1708
+ secondaryAxisNumberFormat = (0, axis_number_format_1.resolveValueAxisNumberFormat)({
1709
+ axisOptions: spec.secondaryValueAxisOptions,
1710
+ series: ((_66 = spec.series) !== null && _66 !== void 0 ? _66 : []).filter(function (s) { return s.useSecondaryAxis; }),
1711
+ getFormattingFromRange: getFormattingFromRange,
1712
+ hiddenDimensionStrategy: spec.hiddenDimensionStrategy,
1713
+ });
1714
+ newLayout = tslib_1.__assign(tslib_1.__assign({ title: {
1715
+ text: (0, plotly_title_1.plotlyTitleText)(title, spec.titleTextFormat),
1434
1716
  font: applyTextFormatToFont({
1435
1717
  family: "Untitled Sans, apple-system, sans-serif",
1436
1718
  size: 16,
@@ -1444,63 +1726,112 @@ var BasicChart = function (_a) {
1444
1726
  color: textColor,
1445
1727
  }, paper_bgcolor: bgColor, plot_bgcolor: bgColor, xaxis: applyAxisOverridesPlotly({
1446
1728
  title: {
1447
- text: (_51 = spec.horizontalAxisTitle) !== null && _51 !== void 0 ? _51 : "",
1729
+ text: (_67 = spec.horizontalAxisTitle) !== null && _67 !== void 0 ? _67 : "",
1448
1730
  font: { color: textColor },
1449
1731
  },
1450
1732
  automargin: true,
1451
1733
  showgrid: true,
1452
1734
  gridcolor: gridColor,
1453
1735
  visible: (0, helpers_1.showXAxis)(spec === null || spec === void 0 ? void 0 : spec.chartType),
1454
- type: isHorizontalBarChart ? "linear" : undefined,
1736
+ type: isHorizontalBarChart
1737
+ ? "linear"
1738
+ : multicategoryX
1739
+ ? "multicategory"
1740
+ : undefined,
1455
1741
  },
1456
1742
  // For horizontal bar, OOXML's value axis is the X axis.
1457
1743
  isHorizontalBarChart
1458
1744
  ? spec.valueAxisOptions
1459
- : spec.categoryAxisOptions), yaxis: applyAxisOverridesPlotly({
1745
+ : spec.categoryAxisOptions, isHorizontalBarChart ? primaryAxisNumberFormat : undefined), yaxis: applyAxisOverridesPlotly({
1460
1746
  title: {
1461
- text: (_52 = spec.verticalAxisTitle) !== null && _52 !== void 0 ? _52 : "",
1747
+ text: (_68 = spec.verticalAxisTitle) !== null && _68 !== void 0 ? _68 : "",
1462
1748
  font: { color: textColor },
1463
1749
  },
1464
1750
  showgrid: !isHorizontalBarChart,
1465
1751
  gridcolor: gridColor,
1466
1752
  automargin: true,
1467
- type: isHorizontalBarChart ? "category" : undefined,
1753
+ type: isHorizontalBarChart
1754
+ ? multicategoryX
1755
+ ? "multicategory"
1756
+ : "category"
1757
+ : undefined,
1468
1758
  }, isHorizontalBarChart
1469
1759
  ? spec.categoryAxisOptions
1470
- : spec.valueAxisOptions) }, (hasSecondaryAxis
1471
- ? {
1472
- yaxis2: applyAxisOverridesPlotly(tslib_1.__assign({ title: { font: { color: textColor } }, overlaying: "y", side: "right", showgrid: false, automargin: true }, (isPareto
1760
+ : spec.valueAxisOptions, isHorizontalBarChart ? undefined : primaryAxisNumberFormat) }, (hasSecondaryAxis
1761
+ ? (_p = {},
1762
+ _p[isHorizontalBarChart ? "xaxis2" : "yaxis2"] = applyAxisOverridesPlotly(tslib_1.__assign({ title: { font: { color: textColor } }, overlaying: isHorizontalBarChart ? "x" : "y", side: isHorizontalBarChart ? "top" : "right", showgrid: false, automargin: true }, (isPareto
1473
1763
  ? { range: [0, 100], ticksuffix: "%" }
1474
- : {})), spec.secondaryValueAxisOptions),
1475
- }
1476
- : {})), (function () {
1477
- var _a = applyLegendOverridesPlotly({ font: { color: textColor } }, spec.legend), legendCfg = _a.legend, showlegend = _a.showlegend;
1478
- return {
1479
- showlegend: showlegend === undefined ? true : showlegend,
1480
- legend: legendCfg,
1481
- };
1482
- })()), { margin: {
1483
- l: 50,
1484
- r: 50,
1485
- t: 50,
1486
- b: 50,
1487
- }, autosize: true }), ((spec.chartType === "bar" || spec.chartType === "column") && spec.stackedType
1488
- ? tslib_1.__assign({ barmode: spec.stackedType === "STACKED" ||
1489
- spec.stackedType === "PERCENT_STACKED"
1490
- ? "stack"
1491
- : "group" }, (spec.stackedType === "PERCENT_STACKED"
1492
- ? { barnorm: "percent" }
1493
- : {})) : {})), (typeof spec.gapWidth === "number"
1494
- ? { bargap: Math.max(0, Math.min(0.95, spec.gapWidth / 400)) }
1495
- : {})), (ofPieExtras
1496
- ? tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ shapes: ofPieExtras.shapes }, (ofPieExtras.barmode ? { barmode: ofPieExtras.barmode } : {})), (ofPieExtras.xaxis2 ? { xaxis2: ofPieExtras.xaxis2 } : {})), (ofPieExtras.yaxis2 ? { yaxis2: ofPieExtras.yaxis2 } : {})) : {}));
1764
+ : {})), spec.secondaryValueAxisOptions, secondaryAxisNumberFormat),
1765
+ _p) : {})), (hasSecondaryCategoryAxis && secondaryDomainData
1766
+ ? (_q = {},
1767
+ _q[isHorizontalBarChart ? "yaxis2" : "xaxis2"] = {
1768
+ overlaying: isHorizontalBarChart ? "y" : "x",
1769
+ side: isHorizontalBarChart ? "right" : "top",
1770
+ type: "category",
1771
+ categoryorder: "array",
1772
+ categoryarray: secondaryDomainData,
1773
+ showgrid: false,
1774
+ automargin: true,
1775
+ visible: (0, helpers_1.showXAxis)(spec === null || spec === void 0 ? void 0 : spec.chartType),
1776
+ },
1777
+ _q) : {}));
1497
1778
  dlOpts = spec.dataLabels;
1498
1779
  doughnutHole = spec.doughnutHoleSize;
1780
+ seriesNumberFormats = (0, axis_number_format_1.resolveSeriesNumberFormats)(spec.series, getFormattingFromRange, spec.hiddenDimensionStrategy);
1781
+ traceNumberFormat = function (trace) {
1782
+ var _a, _b;
1783
+ var specIndex = (_a = trace === null || trace === void 0 ? void 0 : trace.meta) === null || _a === void 0 ? void 0 : _a.rncSeriesIndex;
1784
+ return ((_b = (typeof specIndex === "number"
1785
+ ? seriesNumberFormats[specIndex]
1786
+ : undefined)) !== null && _b !== void 0 ? _b : ((trace === null || trace === void 0 ? void 0 : trace[valueAxisKey]) === secondaryValueAxisRef
1787
+ ? secondaryAxisNumberFormat
1788
+ : primaryAxisNumberFormat));
1789
+ };
1790
+ piePull = isOfPie ? undefined : (0, pie_explosion_1.explosionToPlotlyPull)((0, pie_explosion_1.resolveExplosion)(spec));
1499
1791
  formattedTraces = traces.map(function (trace) {
1500
- var next = applyDataLabelsToTracePlotly(trace, dlOpts, spec.chartType);
1501
- // Doughnut is a pie trace with `hole` set.
1792
+ var _a;
1793
+ var pattern = traceNumberFormat(trace);
1794
+ var next = applyDataLabelsToTracePlotly(trace, dlOpts, spec.chartType, pattern);
1795
+ if (next.type === "pie") {
1796
+ // Hover values format like the slice's source cell.
1797
+ if (pattern && !next.text) {
1798
+ var values = Array.isArray(next.values) ? next.values : [];
1799
+ next = tslib_1.__assign(tslib_1.__assign({}, next), { text: values.map(function (v) { return (0, axis_number_format_1.formatAxisValue)(pattern, v); }), hoverinfo: "label+text+percent+name" });
1800
+ }
1801
+ else if (pattern) {
1802
+ next = tslib_1.__assign(tslib_1.__assign({}, next), { hoverinfo: "label+text+percent+name" });
1803
+ }
1804
+ if (piePull !== undefined) {
1805
+ next = tslib_1.__assign(tslib_1.__assign({}, next), { pull: piePull });
1806
+ }
1807
+ }
1808
+ else if (!next.hovertemplate &&
1809
+ (next.type === "bar" || next.type === "scatter") &&
1810
+ typeof ((_a = next.meta) === null || _a === void 0 ? void 0 : _a.rncSeriesIndex) === "number") {
1811
+ // Hover values read like the series' own cells (Excel's data tip
1812
+ // shows the cell text) — the series format alone, not the axis
1813
+ // fallback the labels use, since that resolves to the first series
1814
+ // and would stamp its format on every other series. Plotly's `%{y}`
1815
+ // is a raw number and its d3 formats cannot express SpreadsheetML,
1816
+ // so the formatted strings ride on `customdata`; `text` stays free
1817
+ // for the data labels.
1818
+ var seriesPattern_1 = seriesNumberFormats[next.meta.rncSeriesIndex];
1819
+ var horizontal = next.orientation === "h";
1820
+ var values = horizontal ? next.x : next.y;
1821
+ if (seriesPattern_1 && Array.isArray(values)) {
1822
+ next = tslib_1.__assign(tslib_1.__assign({}, next), { customdata: values.map(function (v) {
1823
+ return (0, axis_number_format_1.formatAxisValue)(seriesPattern_1, v);
1824
+ }), hovertemplate: "".concat(horizontal ? "%{y}" : "%{x}", "<br>%{customdata}<extra>%{fullData.name}</extra>") });
1825
+ }
1826
+ }
1827
+ // Doughnut is a pie trace with `hole` set. Excel persists
1828
+ // `holeSize` as a 0-90 percentage, normalized to a 0-1 fraction
1829
+ // (doughnutHoleSize); clamp like the echarts renderer and default
1830
+ // to 0.5 when unset.
1502
1831
  if (spec.chartType === "doughnut" && next.type === "pie") {
1503
- next = tslib_1.__assign(tslib_1.__assign({}, next), { hole: typeof doughnutHole === "number" ? doughnutHole : 0.5 });
1832
+ next = tslib_1.__assign(tslib_1.__assign({}, next), { hole: typeof doughnutHole === "number"
1833
+ ? Math.max(0, Math.min(0.9, doughnutHole))
1834
+ : 0.5 });
1504
1835
  }
1505
1836
  return next;
1506
1837
  });
@@ -1524,7 +1855,12 @@ var BasicChart = function (_a) {
1524
1855
  // Update chart on spec changes
1525
1856
  (0, ui_1.useIsomorphicLayoutEffect)(function () {
1526
1857
  updateChart();
1527
- }, [chart.spec, getDomainValuesFromRange, getSeriesValuesFromRange]);
1858
+ }, [
1859
+ chart.spec,
1860
+ getDomainValuesFromRange,
1861
+ getSeriesValuesFromRange,
1862
+ getFormattingFromRange,
1863
+ ]);
1528
1864
  // Update theme
1529
1865
  (0, ui_1.useIsomorphicLayoutEffect)(function () {
1530
1866
  updateChart();
@@ -1547,21 +1883,68 @@ var BasicChart = function (_a) {
1547
1883
  });
1548
1884
  var config = {
1549
1885
  responsive: true,
1550
- // Static so a body drag falls through to the EmbedDraggable move handler
1551
- // (Excel/Sheets behavior) instead of triggering Plotly's zoom-box.
1552
- // staticPlot also drops the modebar and the `.plot-container .draglayer`
1553
- // element the move's cancel selector keys off of.
1886
+ // Interactive so plotly reports clicks (series / point selection) and
1887
+ // hover; `dragmode: false` on the layout keeps plotly from starting a
1888
+ // zoom-box or pan on mousedown, so a body drag falls through to the
1889
+ // EmbedDraggable move handler (Excel/Sheets behavior).
1554
1890
  displayModeBar: false,
1555
1891
  displaylogo: false,
1556
- staticPlot: true,
1892
+ staticPlot: false,
1893
+ scrollZoom: false,
1894
+ doubleClick: false,
1557
1895
  };
1896
+ var plotLayout = (0, react_1.useMemo)(function () { return (tslib_1.__assign(tslib_1.__assign({}, layout), { dragmode: false })); }, [layout]);
1558
1897
  // Excel's "Rounded Corners" chart frame (`<c:roundedCorners val="1"/>`
1559
1898
  // at the chartSpace root). Default per OOXML §21.2.2.183 is square,
1560
1899
  // so only opt in when the workbook explicitly set the flag.
1561
1900
  var roundedCornersStyle = spec.roundedCorners
1562
1901
  ? { borderRadius: 8, overflow: "hidden" }
1563
1902
  : undefined;
1903
+ // Excel's "Switch Row/Column" — offered to the grid's right-click menu
1904
+ // when the host can persist the chart and the sources transpose.
1905
+ var switchRowColumnAction = onUpdateChart && !readonly && (0, chart_orientation_1.canSwitchRowColumn)(spec)
1906
+ ? function () {
1907
+ var next = (0, chart_orientation_1.switchRowColumn)(spec, {
1908
+ getFormattedValue: (0, chart_orientation_1.cellLabelGetterFromRangeReader)(getDomainValuesFromRange),
1909
+ });
1910
+ if (next)
1911
+ onUpdateChart(tslib_1.__assign(tslib_1.__assign({}, chart), { spec: next }));
1912
+ }
1913
+ : undefined;
1914
+ // Copy as Picture / print preview. `plotly.js/dist/plotly` is the module
1915
+ // `react-plotly.js` itself is built on, loaded on demand so the render
1916
+ // path stays as it was.
1917
+ var exportChartPng = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
1918
+ var graphDiv, Plotly, url;
1919
+ return tslib_1.__generator(this, function (_a) {
1920
+ switch (_a.label) {
1921
+ case 0:
1922
+ graphDiv = graphDivRef.current;
1923
+ if (!graphDiv)
1924
+ return [2 /*return*/, undefined];
1925
+ return [4 /*yield*/, Promise.resolve().then(function () { return tslib_1.__importStar(require("plotly.js/dist/plotly")); })];
1926
+ case 1:
1927
+ Plotly = (_a.sent()).default;
1928
+ return [4 /*yield*/, Plotly.toImage(graphDiv, {
1929
+ format: "png",
1930
+ width: graphDiv.clientWidth || width || 600,
1931
+ height: graphDiv.clientHeight || height || 400,
1932
+ scale: 2,
1933
+ })];
1934
+ case 2:
1935
+ url = _a.sent();
1936
+ return [2 /*return*/, (0, chart_image_1.dataUrlToBlob)(url)];
1937
+ }
1938
+ });
1939
+ }); };
1940
+ // The grid's right-click menu offers these without knowing the renderer.
1941
+ (0, spreadsheet_1.useRegisterChartActions)(chart.chartId, {
1942
+ requestEdit: onRequestEdit ? function () { return onRequestEdit(chart); } : undefined,
1943
+ exportPng: exportChartPng,
1944
+ switchRowColumn: switchRowColumnAction,
1945
+ });
1564
1946
  return (react_1.default.createElement("div", { className: "flex flex-1", style: roundedCornersStyle },
1947
+ fieldButtons,
1565
1948
  isSelected ? (react_1.default.createElement(ui_1.DropdownMenu, null,
1566
1949
  react_1.default.createElement(ui_1.DropdownMenuTrigger, { asChild: true },
1567
1950
  react_1.default.createElement(ui_1.IconButton, { className: "absolute right-1 top-1 z-10" },
@@ -1580,7 +1963,9 @@ var BasicChart = function (_a) {
1580
1963
  shouldFocusSheetRef.current = true;
1581
1964
  onDeleteChart === null || onDeleteChart === void 0 ? void 0 : onDeleteChart(chart.chartId);
1582
1965
  } }, "Delete chart")))))) : null,
1583
- react_1.default.createElement("div", { className: "flex-1 rnc-plotly-chart-container" },
1584
- react_1.default.createElement(react_plotly_js_1.default, { ref: plotRef, data: plotData, layout: layout, config: config, style: { width: "100%", height: "100%" } }))));
1966
+ react_1.default.createElement("div", { className: "flex-1 rnc-plotly-chart-container", onPointerDownCapture: handlePointerDownCapture },
1967
+ react_1.default.createElement(react_plotly_js_1.default, { ref: plotRef, data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: function (_figure, graphDiv) {
1968
+ graphDivRef.current = graphDiv;
1969
+ }, style: { width: "100%", height: "100%" } }))));
1585
1970
  };
1586
1971
  exports.BasicChart = BasicChart;