@rowsncolumns/charts 28.1.4 → 28.1.6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AA4DA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmQrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAqEnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAwyGjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAkEA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmQrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAqEnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAwzGjB,CAAC"}
@@ -367,7 +367,7 @@ var BasicChart = function (_a) {
367
367
  * Triggers a chart update
368
368
  */
369
369
  var updateChart = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
370
- var threeDRenderKind, canRender3D, willRender3D, isRegionMap, regionSpec, geoScope, geo, labels, seriesEntry, values, _a, data, unmatched, min, max, textColor, ramp, noDataColor, borderColor, regionSeriesLabel, seriesName, chartDomains, chartSeries, legend, chartType, position, showAxis, isBubble, isHierarchy, skipHeaders_1, labelValues, perSeriesX, perSeriesSize, seriesInputs, i, seriesEntry, resolvedLabel, _b, xValues, sizeValues_1, sharedXValues, sharedSizeValues, _c, categories_1, preparedSeries, sizeValues, sizeScale_1, xAxisConfig, tooltipFormatter, bubbleSeriesLabel_1, hierarchyRows, headerTitle, hierarchyData, rootName, seriesDisplayName, hierarchyDepth, levels, sizeNumberFormat_1, tooltipFormatter, hierarchyDataLabels, hierarchySeriesLabel, isContour, categories_2, contourSeriesInputs, _d, _e, seriesEntry, dataLabel, _f, _g, values, e_1_1, seriesNames_1, contourPoints, _h, zMin, zMax, contourFormats_1, contourLabel, categories_3, threeDSeriesInputs, _j, _k, seriesEntry, dataLabel, _l, _m, values, e_2_1, seriesNames_2, threeDPalette_1, seriesColorAt_1, categoryAxisLabel, seriesAxisLabel, stackedBar3D_1, threeDFormats_1, threeDTooltipFormatter, threeDSeries, visualMap, xAxis3D, yAxis3D, categoryCount, categoryTotals_1, threeDSeriesInputs_1, threeDSeriesInputs_1_1, entry, isPercent_1, surfacePoints, _o, zMin, zMax, skipHeaders, categories, radarSeriesInputs, _p, _q, seriesEntry, label, values, indicators_1, radarData, radarStyle_1, radarColors_1, radarFormats_1, radarDataLabels_1, radarSeriesLabelFor_1, radarTooltipFormatter, variant_1, categories, seriesValues, stockFormats_1, stockRoleIndex_1, stockFormatFor_1, stockDataLabels_1, stockSeriesLabelFor_1, upColor_1, downColor_1, volumePoints, hasVolume, stockGrid, baseStockXAxis, stockXAxis, volumeYAxis, volumeSeries, stockAxisPointer, candleData, lineSeries, stockColors_1, isStacked, isCircularChart, isOfPie, ofPieLayout, isHorizontalBarChart, shouldAggregate, primaryDomainSource, rawPrimaryDomainValues, aggregateDomainValues, categoryLevels, pushSeriesOverlays, sideBySideBarCount, specBarGap, specBarCategoryGap, _loop_1, _r, _s, _t, specSeriesIndex, series, e_3_1, labels, seriesEntry, rawValues, _u, main_1, secondary, otherTotal, total, ofPieType_1, secondScale, halfAngle_1, hasSecondary, MAIN_CX_1, CY_1, MAIN_RADIUS_PCT_1, SECONDARY_CX_1, secondaryRadiusPct_1, BAR_LEFT_1, BAR_RIGHT, barHalfFrac_1, ofPiePalette_1, paletteAt_1, connectorColor_1, primaryDomainSource_1, rawDomainValues, labels, seriesEntry, rawValues_1, totalIndices, steps, accent_1, decreaseColor_1, totalColor_1, connectors, primaryDomainSource_2, rawDomainValues, labels_1, seriesEntry, rawValues, quartileMethod, showOutliers, showMeanMarker, boxStats, boxLabels, outlierPoints, meanPoints, _v, _w, seriesEntry, label, rawValues, summary, boxIndex, lo, hi, _x, _y, outlier, boxSeries, boxColor, rawValues, _z, labels, counts, isPareto_1, cumulativePercents, pareto, histogramSeries, histogramColor, renderedSeriesCount, replaceMerge, valueAxisBase, isPareto, hasSecondaryAxis, isPercentStackedBars, primaryAxisNumberFormat, secondaryAxisNumberFormat, axisNumberFormatFor, seriesNumberFormats, seriesNumberFormatFor, tooltipConfig, finalLegend, bottomAxisNameGap, legendBand, positionedLegend, gridConfig, dataLabelOptions, seriesLabelOptionFor, isDoughnut, doughnutHoleSize, explosion, explosionOffset, barSeries, len, categoryTotals_2, barSeries_1, barSeries_1_1, s, i, raw, n, barSeries_2, barSeries_2_1, s, seriesWithLabels;
370
+ var threeDRenderKind, canRender3D, willRender3D, isRegionMap, regionSpec, geoScope, geo, labels, seriesEntry, values, _a, data, unmatched, min, max, textColor, ramp, noDataColor, borderColor, regionSeriesLabel, seriesName, chartDomains, chartSeries, legend, chartType, position, showAxis, isBubble, isHierarchy, skipHeaders_1, labelValues, perSeriesX, perSeriesSize, seriesInputs, i, seriesEntry, resolvedLabel, _b, xValues, sizeValues_1, sharedXValues, sharedSizeValues, _c, categories_1, preparedSeries, sizeValues, sizeScale_1, xAxisConfig, tooltipFormatter, bubbleSeriesLabel_1, hierarchyRows, headerTitle, hierarchyData, rootName, seriesDisplayName, hierarchyDepth, levels, sizeNumberFormat_1, tooltipFormatter, hierarchyDataLabels, hierarchySeriesLabel, isContour, categories_2, contourSeriesInputs, _d, _e, seriesEntry, dataLabel, _f, _g, values, e_1_1, seriesNames_1, contourPoints, _h, zMin, zMax, contourFormats_1, contourLabel, categories_3, threeDSeriesInputs, _j, _k, seriesEntry, dataLabel, _l, _m, values, e_2_1, seriesNames_2, threeDPalette_1, seriesColorAt_1, categoryAxisLabel, seriesAxisLabel, stackedBar3D_1, threeDFormats_1, threeDTooltipFormatter, threeDSeries, visualMap, xAxis3D, yAxis3D, categoryCount, categoryTotals_1, threeDSeriesInputs_1, threeDSeriesInputs_1_1, entry, isPercent_1, surfacePoints, _o, zMin, zMax, skipHeaders, categories, radarSeriesInputs, _p, _q, seriesEntry, label, values, indicators_1, radarData, radarStyle_1, radarColors_1, radarFormats_1, radarDataLabels_1, radarSeriesLabelFor_1, radarTooltipFormatter, variant_1, categories, seriesValues, stockFormats_1, stockRoleIndex_1, stockFormatFor_1, stockDataLabels_1, stockSeriesLabelFor_1, upColor_1, downColor_1, volumePoints, hasVolume, stockGrid, baseStockXAxis, stockXAxis, volumeYAxis, volumeSeries, stockAxisPointer, candleData, lineSeries, stockColors_1, isStacked, isCircularChart, isOfPie, ofPieLayout, isHorizontalBarChart, shouldAggregate, primaryDomainSource, rawPrimaryDomainValues, aggregateDomainValues, categoryLevels, pushSeriesOverlays, sideBySideBarCount, specBarGap, specBarCategoryGap, seriesPalette, paletteColorAt, _loop_1, _r, _s, _t, specSeriesIndex, series, e_3_1, labels, seriesEntry, rawValues, _u, main_1, secondary, otherTotal, total, ofPieType_1, secondScale, halfAngle_1, hasSecondary, MAIN_CX_1, CY_1, MAIN_RADIUS_PCT_1, SECONDARY_CX_1, secondaryRadiusPct_1, BAR_LEFT_1, BAR_RIGHT, barHalfFrac_1, ofPiePalette_1, paletteAt_1, connectorColor_1, primaryDomainSource_1, rawDomainValues, labels, seriesEntry, rawValues_1, totalIndices, steps, accent_1, decreaseColor_1, totalColor_1, connectors, primaryDomainSource_2, rawDomainValues, labels_1, seriesEntry, rawValues, quartileMethod, showOutliers, showMeanMarker, boxStats, boxLabels, outlierPoints, meanPoints, _v, _w, seriesEntry, label, rawValues, summary, boxIndex, lo, hi, _x, _y, outlier, boxSeries, boxColor, rawValues, _z, labels, counts, isPareto_1, cumulativePercents, pareto, histogramSeries, histogramColor, renderedSeriesCount, replaceMerge, valueAxisBase, isPareto, hasSecondaryAxis, isPercentStackedBars, primaryAxisNumberFormat, secondaryAxisNumberFormat, axisNumberFormatFor, seriesNumberFormats, seriesNumberFormatFor, tooltipConfig, finalLegend, bottomAxisNameGap, legendBand, positionedLegend, gridConfig, dataLabelOptions, seriesLabelOptionFor, isDoughnut, doughnutHoleSize, explosion, explosionOffset, barSeries, len, categoryTotals_2, barSeries_1, barSeries_1_1, s, i, raw, n, barSeries_2, barSeries_2_1, s, seriesWithLabels;
371
371
  var e_1, _0, e_2, _1, e_4, _2, e_5, _3, e_3, _4, e_6, _5, e_7, _6, e_8, _7, e_9, _8;
372
372
  var _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, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128, _129, _130, _131, _132, _133, _134, _135, _136, _137, _138;
373
373
  return tslib_1.__generator(this, function (_139) {
@@ -958,7 +958,7 @@ var BasicChart = function (_a) {
958
958
  ]);
959
959
  seriesColorAt_1 = function (index) {
960
960
  var _a, _b, _c;
961
- return (_c = (_b = (_a = spec.series) === null || _a === void 0 ? void 0 : _a[index]) === null || _b === void 0 ? void 0 : _b.color) !== null && _c !== void 0 ? _c : threeDPalette_1[index % threeDPalette_1.length];
961
+ return (_c = (_b = (_a = spec.series) === null || _a === void 0 ? void 0 : _a[index]) === null || _b === void 0 ? void 0 : _b.color) !== null && _c !== void 0 ? _c : (0, utils_1.chartPaletteColorAt)(threeDPalette_1, index);
962
962
  };
963
963
  // Entering 3-D from a 2-D render: the cartesian option doesn't
964
964
  // merge into a grid3D one, so re-initialize the echarts instance
@@ -1364,7 +1364,7 @@ var BasicChart = function (_a) {
1364
1364
  grid: stockGrid,
1365
1365
  tooltip: { trigger: "axis" },
1366
1366
  axisPointer: stockAxisPointer,
1367
- series: tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(lineSeries.map(function (s, i) { return (tslib_1.__assign(tslib_1.__assign({ type: "line", name: s.name, data: s.values, showSymbol: false, itemStyle: { color: stockColors_1[i % stockColors_1.length] }, lineStyle: { color: stockColors_1[i % stockColors_1.length] } }, (stockSeriesLabelFor_1(s.role)
1367
+ series: tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(lineSeries.map(function (s, i) { return (tslib_1.__assign(tslib_1.__assign({ type: "line", name: s.name, data: s.values, showSymbol: false, itemStyle: { color: (0, utils_1.chartPaletteColorAt)(stockColors_1, i) }, lineStyle: { color: (0, utils_1.chartPaletteColorAt)(stockColors_1, i) } }, (stockSeriesLabelFor_1(s.role)
1368
1368
  ? { label: stockSeriesLabelFor_1(s.role) }
1369
1369
  : {})), ((0, axis_number_format_1.tooltipValueFormatter)(stockFormatFor_1(s.role))
1370
1370
  ? {
@@ -1615,8 +1615,19 @@ var BasicChart = function (_a) {
1615
1615
  seriesCount: sideBySideBarCount,
1616
1616
  overlap: isStacked ? 0 : spec.overlap,
1617
1617
  });
1618
+ seriesPalette = (0, chart_styles_1.getChartPalette)(spec, [
1619
+ theme.themeColors.accent1,
1620
+ theme.themeColors.accent2,
1621
+ theme.themeColors.accent3,
1622
+ theme.themeColors.accent4,
1623
+ theme.themeColors.accent5,
1624
+ theme.themeColors.accent6,
1625
+ ]);
1626
+ paletteColorAt = function (index) {
1627
+ return (0, utils_1.chartPaletteColorAt)(seriesPalette, index);
1628
+ };
1618
1629
  _loop_1 = function (specSeriesIndex, series) {
1619
- var dataLabel, _140, _141, effectiveChartType, lineLike, domainSources, pieDomainLabels, piePointOffset, data, seriesEchartsType, seriesStyleAttrs, seriesEntry, isBarOrColumn, seriesAny, markerSymbol, wantsMarkers, isolated, marked, isolated_1, isolated_1_1, i, gradientArgs, gradient, overrides_2, _142, _143, dp, fallback_1, overrides_3, _144, _145, dp, slicePalette_1, positiveColor_1, negativeColor_1;
1630
+ var dataLabel, _140, _141, effectiveChartType, lineLike, domainSources, pieDomainLabels, piePointOffset, data, seriesEchartsType, seriesStyleAttrs, seriesEntry, isBarOrColumn, seriesAny, markerSymbol, wantsMarkers, isolated, marked, isolated_1, isolated_1_1, i, gradientArgs, gradient, overrides_2, _142, _143, dp, fallback_1, overrides_3, _144, _145, dp, positiveColor_1, negativeColor_1;
1620
1631
  var e_11, _146, e_12, _147, e_13, _148;
1621
1632
  return tslib_1.__generator(this, function (_149) {
1622
1633
  switch (_149.label) {
@@ -1762,7 +1773,7 @@ var BasicChart = function (_a) {
1762
1773
  }
1763
1774
  finally { if (e_12) throw e_12.error; }
1764
1775
  }
1765
- fallback_1 = (_85 = series.color) !== null && _85 !== void 0 ? _85 : theme.themeColors.accent1;
1776
+ fallback_1 = (_85 = series.color) !== null && _85 !== void 0 ? _85 : paletteColorAt(specSeriesIndex);
1766
1777
  seriesEntry.itemStyle = tslib_1.__assign(tslib_1.__assign({}, ((_86 = seriesEntry.itemStyle) !== null && _86 !== void 0 ? _86 : {})), { color: function (params) { var _a; return (_a = overrides_2.get(params.dataIndex)) !== null && _a !== void 0 ? _a : fallback_1; } });
1767
1778
  }
1768
1779
  else if (isCircularChart &&
@@ -1784,23 +1795,14 @@ var BasicChart = function (_a) {
1784
1795
  }
1785
1796
  finally { if (e_13) throw e_13.error; }
1786
1797
  }
1787
- slicePalette_1 = (0, chart_styles_1.getChartPalette)(spec, [
1788
- theme.themeColors.accent1,
1789
- theme.themeColors.accent2,
1790
- theme.themeColors.accent3,
1791
- theme.themeColors.accent4,
1792
- theme.themeColors.accent5,
1793
- theme.themeColors.accent6,
1794
- ]);
1795
1798
  seriesEntry.itemStyle = tslib_1.__assign(tslib_1.__assign({}, ((_87 = seriesEntry.itemStyle) !== null && _87 !== void 0 ? _87 : {})), { color: function (params) {
1796
1799
  var _a, _b;
1797
- return (_b = (_a = overrides_3.get(params.dataIndex)) !== null && _a !== void 0 ? _a : series.color) !== null && _b !== void 0 ? _b : slicePalette_1[params.dataIndex % slicePalette_1.length];
1800
+ return (_b = (_a = overrides_3.get(params.dataIndex)) !== null && _a !== void 0 ? _a : series.color) !== null && _b !== void 0 ? _b : paletteColorAt(params.dataIndex);
1798
1801
  } });
1799
1802
  }
1800
1803
  else if (isBarOrColumn && series.invertIfNegative) {
1801
- positiveColor_1 = (_88 = series.color) !== null && _88 !== void 0 ? _88 : theme.themeColors.accent1;
1804
+ positiveColor_1 = (_88 = series.color) !== null && _88 !== void 0 ? _88 : paletteColorAt(specSeriesIndex);
1802
1805
  negativeColor_1 = (_89 = series.negativeColor) !== null && _89 !== void 0 ? _89 : "#FF0000";
1803
- // Use a color function that returns different colors based on value
1804
1806
  seriesEntry.itemStyle = tslib_1.__assign(tslib_1.__assign({}, ((_90 = seriesEntry.itemStyle) !== null && _90 !== void 0 ? _90 : {})), { color: function (params) {
1805
1807
  var _a, _b;
1806
1808
  var value = Array.isArray(params.data)
@@ -1902,7 +1904,7 @@ var BasicChart = function (_a) {
1902
1904
  theme.themeColors.accent6,
1903
1905
  ]);
1904
1906
  paletteAt_1 = function (index) {
1905
- return ofPiePalette_1[index % ofPiePalette_1.length];
1907
+ return (0, utils_1.chartPaletteColorAt)(ofPiePalette_1, index);
1906
1908
  };
1907
1909
  chartSeries.push({
1908
1910
  type: "pie",
@@ -2661,14 +2663,17 @@ var BasicChart = function (_a) {
2661
2663
  color: textColor,
2662
2664
  },
2663
2665
  },
2664
- color: (0, chart_styles_1.getChartPalette)(chart.spec, [
2666
+ // Unrolled through Excel's luminance variations: echarts cycles this
2667
+ // list over pie slices and over series, and the seventh must not
2668
+ // repeat the first (rowsncolumns/spreadsheet#1045).
2669
+ color: (0, utils_1.expandChartPalette)((0, chart_styles_1.getChartPalette)(chart.spec, [
2665
2670
  theme.themeColors.accent1,
2666
2671
  theme.themeColors.accent2,
2667
2672
  theme.themeColors.accent3,
2668
2673
  theme.themeColors.accent4,
2669
2674
  theme.themeColors.accent5,
2670
2675
  theme.themeColors.accent6,
2671
- ]),
2676
+ ])),
2672
2677
  // Excel's Format Chart Area fill; `transparent` (echarts' own
2673
2678
  // default) so clearing the fill undoes an earlier setOption.
2674
2679
  backgroundColor: (_f = chart.spec.backgroundColor) !== null && _f !== void 0 ? _f : "transparent",
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAGtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA+WxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAg0EjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAgXxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBA8zEjB,CAAC"}
@@ -8,7 +8,6 @@ var spreadsheet_state_1 = require("@rowsncolumns/spreadsheet-state");
8
8
  var ui_1 = require("@rowsncolumns/ui");
9
9
  var utils_1 = require("@rowsncolumns/utils");
10
10
  var react_1 = tslib_1.__importStar(require("react"));
11
- var react_plotly_js_1 = tslib_1.__importDefault(require("react-plotly.js"));
12
11
  var aggregation_1 = require("../../utils/aggregation");
13
12
  var axis_number_format_1 = require("../../utils/axis-number-format");
14
13
  var boxplot_1 = require("../../utils/boxplot");
@@ -34,6 +33,7 @@ var radar_1 = require("../../utils/radar");
34
33
  var region_map_1 = require("../../utils/region-map");
35
34
  var stock_1 = require("../../utils/stock");
36
35
  var trendline_1 = require("../../utils/trendline");
36
+ var plot_1 = require("../plot");
37
37
  var helpers_1 = require("./helpers");
38
38
  var BASIC_CHART_TYPES = new Set([
39
39
  "bar",
@@ -374,7 +374,6 @@ var BasicChart = function (_a) {
374
374
  var hierarchyTitleRef = (0, react_1.useRef)(undefined);
375
375
  var explicitChartTitle = (_b = chart.spec.title) !== null && _b !== void 0 ? _b : undefined;
376
376
  var title = explicitChartTitle !== null && explicitChartTitle !== void 0 ? explicitChartTitle : hierarchyTitleRef.current;
377
- var plotRef = (0, react_1.useRef)(null);
378
377
  // The plotted `<div>` plotly hands back on init — what `Plotly.toImage`
379
378
  // rasterises for Copy as Picture and the print preview.
380
379
  var graphDivRef = (0, react_1.useRef)(null);
@@ -553,7 +552,7 @@ var BasicChart = function (_a) {
553
552
  });
554
553
  var yValues = entry.points.map(function (point) { return point.value[1]; });
555
554
  var labelValuesForSeries = entry.points.map(function (point) { return point.name; });
556
- var seriesColor = (_b = (_a = spec.series[index]) === null || _a === void 0 ? void 0 : _a.color) !== null && _b !== void 0 ? _b : palette_1[index % palette_1.length];
555
+ var seriesColor = (_b = (_a = spec.series[index]) === null || _a === void 0 ? void 0 : _a.color) !== null && _b !== void 0 ? _b : (0, utils_1.chartPaletteColorAt)(palette_1, index);
557
556
  var perSeriesMarker = (_d = (_c = spec.series[index]) === null || _c === void 0 ? void 0 : _c.marker) !== null && _d !== void 0 ? _d : undefined;
558
557
  if (isScatter_1) {
559
558
  // Per-series marker.symbol = "none" → pure line (no markers).
@@ -1114,7 +1113,7 @@ var BasicChart = function (_a) {
1114
1113
  // then theme palette. Plotly cannot paint the real gradient, so the
1115
1114
  // median stop stands in for the whole ramp.
1116
1115
  var effectiveColor = (_g = (_f = options === null || options === void 0 ? void 0 : options.gradientColor) !== null && _f !== void 0 ? _f : seriesColor) !== null && _g !== void 0 ? _g : ((options === null || options === void 0 ? void 0 : options.seriesIndex) !== undefined
1117
- ? themeColorPalette[options.seriesIndex % themeColorPalette.length]
1116
+ ? (0, utils_1.chartPaletteColorAt)(themeColorPalette, options.seriesIndex)
1118
1117
  : undefined);
1119
1118
  // Per-data-point color overrides — Gantt charts use `<c:dPt>` to
1120
1119
  // give every task its own color. Build a per-point color array
@@ -1146,7 +1145,7 @@ var BasicChart = function (_a) {
1146
1145
  // with (or the series' own colour when one was authored).
1147
1146
  var existing_1 = Array.isArray((_h = target.marker) === null || _h === void 0 ? void 0 : _h.colors)
1148
1147
  ? target.marker.colors
1149
- : themeColorPalette;
1148
+ : (0, utils_1.expandChartPalette)(themeColorPalette);
1150
1149
  var labelCount = Array.isArray(target.labels)
1151
1150
  ? target.labels.length
1152
1151
  : 0;
@@ -1515,7 +1514,7 @@ var BasicChart = function (_a) {
1515
1514
  secondScale = (0, of_pie_1.clampSecondPieSize)(spec.secondPieSize) / 100;
1516
1515
  halfAngle = (0, of_pie_1.otherSliceHalfAngle)(otherTotal, total);
1517
1516
  paletteAt_1 = function (index) {
1518
- return themeColorPalette[index % themeColorPalette.length];
1517
+ return (0, utils_1.chartPaletteColorAt)(themeColorPalette, index);
1519
1518
  };
1520
1519
  MAIN_DOMAIN_X = [0, 0.55];
1521
1520
  CY = 0.5;
@@ -1633,7 +1632,9 @@ var BasicChart = function (_a) {
1633
1632
  labels: pieData.labels,
1634
1633
  name: dataLabel,
1635
1634
  marker: {
1636
- colors: themeColorPalette,
1635
+ // Unrolled through Excel's luminance variations so slice 7 does
1636
+ // not repeat slice 1 (rowsncolumns/spreadsheet#1045).
1637
+ colors: (0, utils_1.expandChartPalette)(themeColorPalette),
1637
1638
  },
1638
1639
  };
1639
1640
  // Ties the trace back to spec.series for click selection and
@@ -2001,27 +2002,23 @@ var BasicChart = function (_a) {
2001
2002
  onUpdateChart(tslib_1.__assign(tslib_1.__assign({}, chart), { spec: next }));
2002
2003
  }
2003
2004
  : undefined;
2004
- // Copy as Picture / print preview. `plotly.js/dist/plotly` is the module
2005
- // `react-plotly.js` itself is built on, loaded on demand so the render
2006
- // path stays as it was.
2005
+ // Copy as Picture / print preview, through the plotly module the chart
2006
+ // renders with.
2007
2007
  var exportChartPng = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
2008
- var graphDiv, Plotly, url;
2008
+ var graphDiv, url;
2009
2009
  return tslib_1.__generator(this, function (_a) {
2010
2010
  switch (_a.label) {
2011
2011
  case 0:
2012
2012
  graphDiv = graphDivRef.current;
2013
2013
  if (!graphDiv)
2014
2014
  return [2 /*return*/, undefined];
2015
- return [4 /*yield*/, Promise.resolve().then(function () { return tslib_1.__importStar(require("plotly.js/dist/plotly")); })];
2016
- case 1:
2017
- Plotly = (_a.sent()).default;
2018
- return [4 /*yield*/, Plotly.toImage(graphDiv, {
2015
+ return [4 /*yield*/, plot_1.Plotly.toImage(graphDiv, {
2019
2016
  format: "png",
2020
2017
  width: graphDiv.clientWidth || width || 600,
2021
2018
  height: graphDiv.clientHeight || height || 400,
2022
2019
  scale: 2,
2023
2020
  })];
2024
- case 2:
2021
+ case 1:
2025
2022
  url = _a.sent();
2026
2023
  return [2 /*return*/, (0, chart_image_1.dataUrlToBlob)(url)];
2027
2024
  }
@@ -2054,7 +2051,7 @@ var BasicChart = function (_a) {
2054
2051
  onDeleteChart === null || onDeleteChart === void 0 ? void 0 : onDeleteChart(chart.chartId);
2055
2052
  } }, "Delete chart")))))) : null,
2056
2053
  react_1.default.createElement("div", { className: "flex-1 rnc-plotly-chart-container", onPointerDownCapture: handlePointerDownCapture },
2057
- react_1.default.createElement(react_plotly_js_1.default, { ref: plotRef, data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: function (_figure, graphDiv) {
2054
+ react_1.default.createElement(plot_1.Plot, { data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: function (_figure, graphDiv) {
2058
2055
  graphDivRef.current = graphDiv;
2059
2056
  }, style: { width: "100%", height: "100%" } }))));
2060
2057
  };
@@ -0,0 +1,12 @@
1
+ import Plotly from "plotly.js-dist-min";
2
+ /**
3
+ * The one plotly module the plotly charts render and export with:
4
+ * `plotly.js-dist-min`, the full bundle (every trace type) already minified.
5
+ * react-plotly.js's default entry would load the separate
6
+ * `plotly.js/dist/plotly` build instead, so a host that ships
7
+ * `plotly.js-dist-min` for its own charts would carry two copies of the same
8
+ * plotly release.
9
+ */
10
+ export { Plotly };
11
+ export declare const Plot: import("react").ComponentType<import("react-plotly.js").PlotParams>;
12
+ //# sourceMappingURL=plot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plot.d.ts","sourceRoot":"","sources":["../../../plotly/plot.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAGxC;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,eAAO,MAAM,IAAI,qEAAgC,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Plot = exports.Plotly = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var plotly_js_dist_min_1 = tslib_1.__importDefault(require("plotly.js-dist-min"));
6
+ exports.Plotly = plotly_js_dist_min_1.default;
7
+ var factory_1 = tslib_1.__importDefault(require("react-plotly.js/factory"));
8
+ exports.Plot = (0, factory_1.default)(plotly_js_dist_min_1.default);
@@ -1 +1 @@
1
- {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/echarts-gl-loader.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
1
+ {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/plot.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/echarts-gl-loader.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
@@ -7,12 +7,24 @@
7
7
  * so the regressions are hand-rolled here as pure least-squares math and
8
8
  * the renderers draw the returned points as an overlay line series.
9
9
  *
10
- * All fits operate on the index domain x = 0, 1, 2, … (one step per
11
- * category) which matches how a category-axis chart positions points.
12
- * The caller passes the raw y-values; gaps (null/NaN) are skipped during
13
- * fitting but the fitted curve is still emitted for every x in range.
10
+ * All fits operate on Excel's category domain x = 1, 2, …, n (one step per
11
+ * category, first category = 1) — the domain Excel fits and prints for a
12
+ * category-axis chart (line, column, bar, area). Linear, polynomial and
13
+ * exponential curves are invariant to where the domain starts (only the
14
+ * equation text moves), but logarithmic and power fits are not: fitting
15
+ * them on x = 0, 1, … dropped the first category from the fit and evaluated
16
+ * ln(x) at x → 0 for it, which drew the Jan point of a 12-month log trend
17
+ * at about −524 instead of Excel's ≈6.4 (rowsncolumns/spreadsheet#1028).
18
+ *
19
+ * The emitted points keep the renderer-facing 0-based CATEGORY INDEX in `x`
20
+ * (echarts plots `[x, y]` on the category axis, plotly maps `x` onto the
21
+ * category labels), so a forecast of k periods still extends to index
22
+ * n−1+k forward and −k backward. The caller passes the raw y-values; gaps
23
+ * (null/NaN) are skipped during fitting but the fitted curve is still
24
+ * emitted for every x in range.
14
25
  */
15
26
  export type TrendlineType = "linear" | "exp" | "log" | "poly" | "power" | "movingAvg";
27
+ /** `x` is the 0-based category index (−k … n−1+k with forecasting), `y` the fitted value. */
16
28
  export type TrendlinePoint = {
17
29
  x: number;
18
30
  y: number;
@@ -28,7 +40,8 @@ export type TrendlineResult = {
28
40
  /**
29
41
  * Compute a trendline for a series of y-values.
30
42
  *
31
- * @param values Raw y-values; the category index is used as x.
43
+ * @param values Raw y-values; the 1-based category position is used as x
44
+ * for the fit, the 0-based index is reported in the points.
32
45
  * @param spec Trendline parameters (type/order/period/forecast).
33
46
  */
34
47
  export declare const computeTrendline: (values: (number | null | undefined)[], spec?: {
@@ -1 +1 @@
1
- {"version":3,"file":"trendline.d.ts","sourceRoot":"","sources":["../../../utils/trendline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,CAAC;AAEhB,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AA+IF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,OAAM;IACJ,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,KACL,eAAe,GAAG,IA6FpB,CAAC"}
1
+ {"version":3,"file":"trendline.d.ts","sourceRoot":"","sources":["../../../utils/trendline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,CAAC;AAEhB,6FAA6F;AAC7F,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAsJF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,OAAM;IACJ,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,KACL,eAAe,GAAG,IAiGpB,CAAC"}
@@ -8,10 +8,21 @@
8
8
  * so the regressions are hand-rolled here as pure least-squares math and
9
9
  * the renderers draw the returned points as an overlay line series.
10
10
  *
11
- * All fits operate on the index domain x = 0, 1, 2, … (one step per
12
- * category) which matches how a category-axis chart positions points.
13
- * The caller passes the raw y-values; gaps (null/NaN) are skipped during
14
- * fitting but the fitted curve is still emitted for every x in range.
11
+ * All fits operate on Excel's category domain x = 1, 2, …, n (one step per
12
+ * category, first category = 1) — the domain Excel fits and prints for a
13
+ * category-axis chart (line, column, bar, area). Linear, polynomial and
14
+ * exponential curves are invariant to where the domain starts (only the
15
+ * equation text moves), but logarithmic and power fits are not: fitting
16
+ * them on x = 0, 1, … dropped the first category from the fit and evaluated
17
+ * ln(x) at x → 0 for it, which drew the Jan point of a 12-month log trend
18
+ * at about −524 instead of Excel's ≈6.4 (rowsncolumns/spreadsheet#1028).
19
+ *
20
+ * The emitted points keep the renderer-facing 0-based CATEGORY INDEX in `x`
21
+ * (echarts plots `[x, y]` on the category axis, plotly maps `x` onto the
22
+ * category labels), so a forecast of k periods still extends to index
23
+ * n−1+k forward and −k backward. The caller passes the raw y-values; gaps
24
+ * (null/NaN) are skipped during fitting but the fitted curve is still
25
+ * emitted for every x in range.
15
26
  */
16
27
  Object.defineProperty(exports, "__esModule", { value: true });
17
28
  exports.computeTrendline = void 0;
@@ -20,7 +31,8 @@ var isFiniteNum = function (v) {
20
31
  return typeof v === "number" && Number.isFinite(v);
21
32
  };
22
33
  /**
23
- * Build (x, y) pairs from raw y-values using the category index as x.
34
+ * Build (x, y) pairs from raw y-values using Excel's 1-based category
35
+ * position as x (the first category is x = 1, see the module comment).
24
36
  * Non-finite y-values are dropped (they cannot be fitted).
25
37
  */
26
38
  var toPairs = function (values) {
@@ -28,7 +40,7 @@ var toPairs = function (values) {
28
40
  for (var i = 0; i < values.length; i++) {
29
41
  var y = values[i];
30
42
  if (isFiniteNum(y))
31
- pairs.push({ x: i, y: y });
43
+ pairs.push({ x: i + 1, y: y });
32
44
  }
33
45
  return pairs;
34
46
  };
@@ -66,6 +78,11 @@ var round = function (n, digits) {
66
78
  var f = Math.pow(10, digits);
67
79
  return Math.round(n * f) / f;
68
80
  };
81
+ /** `+ 2` / `- 2` for an additive term, the way Excel prints an equation. */
82
+ var signed = function (n) {
83
+ var r = round(n);
84
+ return r < 0 ? "- ".concat(Math.abs(r)) : "+ ".concat(r);
85
+ };
69
86
  /** Solve a small linear system A·x = b via Gaussian elimination. */
70
87
  var solveLinearSystem = function (A, b) {
71
88
  var _a;
@@ -198,7 +215,8 @@ var fitPower = function (pairs) {
198
215
  /**
199
216
  * Compute a trendline for a series of y-values.
200
217
  *
201
- * @param values Raw y-values; the category index is used as x.
218
+ * @param values Raw y-values; the 1-based category position is used as x
219
+ * for the fit, the 0-based index is reported in the points.
202
220
  * @param spec Trendline parameters (type/order/period/forecast).
203
221
  */
204
222
  var computeTrendline = function (values, spec) {
@@ -230,9 +248,9 @@ var computeTrendline = function (values, spec) {
230
248
  }
231
249
  return { points: points_1, rSquared: null, equation: null };
232
250
  }
233
- var lastX = values.length - 1;
234
- var xStart = -backward;
235
- var xEnd = lastX + forward;
251
+ // Fit domain is 1..n; a forecast of k periods extends it to 1−k / n+k.
252
+ var xStart = 1 - backward;
253
+ var xEnd = values.length + forward;
236
254
  var xs = [];
237
255
  for (var x = xStart; x <= xEnd; x++)
238
256
  xs.push(x);
@@ -244,7 +262,7 @@ var computeTrendline = function (values, spec) {
244
262
  if (!fit_1)
245
263
  return null;
246
264
  predict = function (x) { return fit_1.m * x + fit_1.b; };
247
- equation = "y = ".concat(round(fit_1.m), "x + ").concat(round(fit_1.b));
265
+ equation = "y = ".concat(round(fit_1.m), "x ").concat(signed(fit_1.b));
248
266
  break;
249
267
  }
250
268
  case "poly": {
@@ -257,8 +275,10 @@ var computeTrendline = function (values, spec) {
257
275
  equation =
258
276
  "y = " +
259
277
  coeffs_1
260
- .map(function (c, i) { return (i === 0 ? "".concat(round(c)) : "".concat(round(c), "x^").concat(i)); })
261
- .join(" + ");
278
+ .map(function (c, i) {
279
+ return i === 0 ? "".concat(round(c)) : "".concat(signed(c), "x").concat(i === 1 ? "" : "^".concat(i));
280
+ })
281
+ .join(" ");
262
282
  break;
263
283
  }
264
284
  case "exp": {
@@ -273,9 +293,10 @@ var computeTrendline = function (values, spec) {
273
293
  var fit_3 = fitLog(pairs);
274
294
  if (!fit_3)
275
295
  return null;
276
- // ln(0) and ln(negative) are undefined; clamp x to >0 for the curve.
296
+ // Only a backward forecast reaches x ≤ 0 (the fit domain starts at 1);
297
+ // ln(0) and ln(negative) are undefined, so clamp x to >0 for the curve.
277
298
  predict = function (x) { return fit_3.a + fit_3.b * Math.log(x <= 0 ? 1e-9 : x); };
278
- equation = "y = ".concat(round(fit_3.a), " + ").concat(round(fit_3.b), "ln(x)");
299
+ equation = "y = ".concat(round(fit_3.b), "ln(x) ").concat(signed(fit_3.a));
279
300
  break;
280
301
  }
281
302
  case "power": {
@@ -289,8 +310,9 @@ var computeTrendline = function (values, spec) {
289
310
  default:
290
311
  return null;
291
312
  }
313
+ // Report the renderer-facing 0-based category index (see module comment).
292
314
  var points = xs
293
- .map(function (x) { return ({ x: x, y: predict(x) }); })
315
+ .map(function (x) { return ({ x: x - 1, y: predict(x) }); })
294
316
  .filter(function (p) { return Number.isFinite(p.y); });
295
317
  if (points.length < 2)
296
318
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AA4DA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmQrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAqEnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAwyGjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAkEA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAmQrD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAqEnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAwzGjB,CAAC"}
@@ -3,7 +3,7 @@ import { getStringifiedColor, useFocusSheet, useRegisterChartActions, useSetSele
3
3
  import { useSubscribeToMultipleRanges } from "@rowsncolumns/spreadsheet-state";
4
4
  import { createDownloadableFile } from "@rowsncolumns/toolkit";
5
5
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DropdownRightSlot, IconButton, useIsomorphicLayoutEffect, useOnVisibilityChange, } from "@rowsncolumns/ui";
6
- import { debug, isAFormula, isNil } from "@rowsncolumns/utils";
6
+ import { chartPaletteColorAt, debug, expandChartPalette, isAFormula, isNil, } from "@rowsncolumns/utils";
7
7
  import { BarChart, BoxplotChart, CandlestickChart, CustomChart, FunnelChart, HeatmapChart, LineChart, PieChart, RadarChart as EchartsRadarChart, ScatterChart, SunburstChart, TreemapChart as EchartsTreemapChart, } from "echarts/charts";
8
8
  import { DatasetComponent, GridComponent, LegendComponent, RadarComponent, TitleComponent, TooltipComponent, VisualMapComponent, } from "echarts/components";
9
9
  import * as echarts from "echarts/core";
@@ -942,7 +942,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
942
942
  theme.themeColors.accent6,
943
943
  ]);
944
944
  const seriesColorAt = (index) => spec.series?.[index]?.color ??
945
- threeDPalette[index % threeDPalette.length];
945
+ chartPaletteColorAt(threeDPalette, index);
946
946
  // Entering 3-D from a 2-D render: the cartesian option doesn't
947
947
  // merge into a grid3D one, so re-initialize the echarts instance
948
948
  // from scratch (theme options are re-applied after setOption).
@@ -1402,8 +1402,8 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1402
1402
  name: s.name,
1403
1403
  data: s.values,
1404
1404
  showSymbol: false,
1405
- itemStyle: { color: stockColors[i % stockColors.length] },
1406
- lineStyle: { color: stockColors[i % stockColors.length] },
1405
+ itemStyle: { color: chartPaletteColorAt(stockColors, i) },
1406
+ lineStyle: { color: chartPaletteColorAt(stockColors, i) },
1407
1407
  ...(stockSeriesLabelFor(s.role)
1408
1408
  ? { label: stockSeriesLabelFor(s.role) }
1409
1409
  : {}),
@@ -1675,6 +1675,20 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1675
1675
  seriesCount: sideBySideBarCount,
1676
1676
  overlap: isStacked ? 0 : spec.overlap,
1677
1677
  });
1678
+ // The colour a series without its own fill gets: the chart palette entry
1679
+ // for its position, the same cycle the option-level `color` gives echarts'
1680
+ // default path. Excel keeps that colour whatever else is authored on the
1681
+ // series — `<c:dPt>` overrides recolour only their points and
1682
+ // `invertIfNegative` only the negative bars (rowsncolumns/spreadsheet#1030).
1683
+ const seriesPalette = getChartPalette(spec, [
1684
+ theme.themeColors.accent1,
1685
+ theme.themeColors.accent2,
1686
+ theme.themeColors.accent3,
1687
+ theme.themeColors.accent4,
1688
+ theme.themeColors.accent5,
1689
+ theme.themeColors.accent6,
1690
+ ]);
1691
+ const paletteColorAt = (index) => chartPaletteColorAt(seriesPalette, index);
1678
1692
  for (const [specSeriesIndex, series] of (spec.series ?? []).entries()) {
1679
1693
  const dataLabel = !isNil(series.dataLabel) && isAFormula(series.dataLabel)
1680
1694
  ? coerceCalculatedLabel(await onRequestCalculate(series.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
@@ -1822,14 +1836,16 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1822
1836
  // Per-data-point color overrides — Gantt-style charts colour
1823
1837
  // each task differently via `<c:dPt>`. Echarts accepts an
1824
1838
  // `itemStyle.color` function that receives the data index;
1825
- // we look up the override or fall back to the series color.
1839
+ // we look up the override or fall back to the series colour —
1840
+ // its own, else its palette slot (never a fixed accent1, which
1841
+ // painted every such series alike).
1826
1842
  const overrides = new Map();
1827
1843
  for (const dp of seriesAny.dataPointColors) {
1828
1844
  if (typeof dp.idx === "number" && typeof dp.color === "string") {
1829
1845
  overrides.set(dp.idx, dp.color);
1830
1846
  }
1831
1847
  }
1832
- const fallback = series.color ?? theme.themeColors.accent1;
1848
+ const fallback = series.color ?? paletteColorAt(specSeriesIndex);
1833
1849
  seriesEntry.itemStyle = {
1834
1850
  ...(seriesEntry.itemStyle ?? {}),
1835
1851
  color: (params) => overrides.get(params.dataIndex) ?? fallback,
@@ -1847,25 +1863,18 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1847
1863
  overrides.set(dp.idx, dp.color);
1848
1864
  }
1849
1865
  }
1850
- const slicePalette = getChartPalette(spec, [
1851
- theme.themeColors.accent1,
1852
- theme.themeColors.accent2,
1853
- theme.themeColors.accent3,
1854
- theme.themeColors.accent4,
1855
- theme.themeColors.accent5,
1856
- theme.themeColors.accent6,
1857
- ]);
1858
1866
  seriesEntry.itemStyle = {
1859
1867
  ...(seriesEntry.itemStyle ?? {}),
1860
1868
  color: (params) => overrides.get(params.dataIndex) ??
1861
1869
  series.color ??
1862
- slicePalette[params.dataIndex % slicePalette.length],
1870
+ paletteColorAt(params.dataIndex),
1863
1871
  };
1864
1872
  }
1865
1873
  else if (isBarOrColumn && series.invertIfNegative) {
1866
- const positiveColor = series.color ?? theme.themeColors.accent1;
1874
+ // Positive bars keep the series colour (own, else palette slot);
1875
+ // only negative bars take the inverted colour.
1876
+ const positiveColor = series.color ?? paletteColorAt(specSeriesIndex);
1867
1877
  const negativeColor = series.negativeColor ?? "#FF0000";
1868
- // Use a color function that returns different colors based on value
1869
1878
  seriesEntry.itemStyle = {
1870
1879
  ...(seriesEntry.itemStyle ?? {}),
1871
1880
  color: (params) => {
@@ -1960,7 +1969,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1960
1969
  theme.themeColors.accent5,
1961
1970
  theme.themeColors.accent6,
1962
1971
  ]);
1963
- const paletteAt = (index) => ofPiePalette[index % ofPiePalette.length];
1972
+ const paletteAt = (index) => chartPaletteColorAt(ofPiePalette, index);
1964
1973
  chartSeries.push({
1965
1974
  type: "pie",
1966
1975
  name: seriesEntry?.dataLabel ?? "",
@@ -2773,14 +2782,17 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2773
2782
  color: textColor,
2774
2783
  },
2775
2784
  },
2776
- color: getChartPalette(chart.spec, [
2785
+ // Unrolled through Excel's luminance variations: echarts cycles this
2786
+ // list over pie slices and over series, and the seventh must not
2787
+ // repeat the first (rowsncolumns/spreadsheet#1045).
2788
+ color: expandChartPalette(getChartPalette(chart.spec, [
2777
2789
  theme.themeColors.accent1,
2778
2790
  theme.themeColors.accent2,
2779
2791
  theme.themeColors.accent3,
2780
2792
  theme.themeColors.accent4,
2781
2793
  theme.themeColors.accent5,
2782
2794
  theme.themeColors.accent6,
2783
- ]),
2795
+ ])),
2784
2796
  // Excel's Format Chart Area fill; `transparent` (echarts' own
2785
2797
  // default) so clearing the fill undoes an earlier setOption.
2786
2798
  backgroundColor: chart.spec.backgroundColor ?? "transparent",
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAGtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA+WxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBAg0EjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAgXxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AA0FnD,eAAO,MAAM,UAAU,GAAI,wOAiBxB,eAAe,sBA8zEjB,CAAC"}
@@ -2,9 +2,8 @@ import { DotsVerticalIcon } from "@rowsncolumns/icons";
2
2
  import { getStringifiedColor, useFocusSheet, useRegisterChartActions, useSetSelectedChartSeries, } from "@rowsncolumns/spreadsheet";
3
3
  import { useSubscribeToSheet } from "@rowsncolumns/spreadsheet-state";
4
4
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuTrigger, IconButton, useIsomorphicLayoutEffect, useOnVisibilityChange, } from "@rowsncolumns/ui";
5
- import { debug, isAFormula, isNil, ssfFormat } from "@rowsncolumns/utils";
5
+ import { chartPaletteColorAt, debug, expandChartPalette, isAFormula, isNil, ssfFormat, } from "@rowsncolumns/utils";
6
6
  import React, { useCallback, useMemo, useRef, useState } from "react";
7
- import Plot from "react-plotly.js";
8
7
  import { aggregateSeriesByDomain, getDomainValuesForAxis, sanitizeDomainValues, shouldAggregateSeries, } from "../../utils/aggregation";
9
8
  import { formatAxisValue, numberFormatToPlotlyTicks, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
10
9
  import { computeBoxplotSummary } from "../../utils/boxplot";
@@ -30,6 +29,7 @@ import { buildRadarIndicators } from "../../utils/radar";
30
29
  import { buildSequentialColorRamp, isRegionMapSpec, resolveGeoScope, WORLD_GEO_SCOPE, } from "../../utils/region-map";
31
30
  import { assignStockRoles, toLineSeries, toVolumeSeries, } from "../../utils/stock";
32
31
  import { computeTrendline } from "../../utils/trendline";
32
+ import { Plot, Plotly } from "../plot";
33
33
  import { chartTypeToPlotlyType, getPlotlyTraceStyle, mapMarkerSymbolToPlotly, showXAxis, } from "./helpers";
34
34
  const BASIC_CHART_TYPES = new Set([
35
35
  "bar",
@@ -350,7 +350,6 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
350
350
  const hierarchyTitleRef = useRef(undefined);
351
351
  const explicitChartTitle = chart.spec.title ?? undefined;
352
352
  const title = explicitChartTitle ?? hierarchyTitleRef.current;
353
- const plotRef = useRef(null);
354
353
  // The plotted `<div>` plotly hands back on init — what `Plotly.toImage`
355
354
  // rasterises for Copy as Picture and the print preview.
356
355
  const graphDivRef = useRef(null);
@@ -526,7 +525,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
526
525
  : point.value[0]);
527
526
  const yValues = entry.points.map((point) => point.value[1]);
528
527
  const labelValuesForSeries = entry.points.map((point) => point.name);
529
- const seriesColor = spec.series[index]?.color ?? palette[index % palette.length];
528
+ const seriesColor = spec.series[index]?.color ?? chartPaletteColorAt(palette, index);
530
529
  const perSeriesMarker = spec.series[index]?.marker ?? undefined;
531
530
  if (isScatter) {
532
531
  // Per-series marker.symbol = "none" → pure line (no markers).
@@ -1145,7 +1144,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1145
1144
  const effectiveColor = options?.gradientColor ??
1146
1145
  seriesColor ??
1147
1146
  (options?.seriesIndex !== undefined
1148
- ? themeColorPalette[options.seriesIndex % themeColorPalette.length]
1147
+ ? chartPaletteColorAt(themeColorPalette, options.seriesIndex)
1149
1148
  : undefined);
1150
1149
  // Per-data-point color overrides — Gantt charts use `<c:dPt>` to
1151
1150
  // give every task its own color. Build a per-point color array
@@ -1167,7 +1166,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1167
1166
  // with (or the series' own colour when one was authored).
1168
1167
  const existing = Array.isArray(target.marker?.colors)
1169
1168
  ? target.marker.colors
1170
- : themeColorPalette;
1169
+ : expandChartPalette(themeColorPalette);
1171
1170
  const labelCount = Array.isArray(target.labels)
1172
1171
  ? target.labels.length
1173
1172
  : 0;
@@ -1585,7 +1584,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1585
1584
  const ofPieType = resolveOfPieType(spec.ofPieType);
1586
1585
  const secondScale = clampSecondPieSize(spec.secondPieSize) / 100;
1587
1586
  const halfAngle = otherSliceHalfAngle(otherTotal, total);
1588
- const paletteAt = (index) => themeColorPalette[index % themeColorPalette.length];
1587
+ const paletteAt = (index) => chartPaletteColorAt(themeColorPalette, index);
1589
1588
  // Layout in paper coordinates (0-1 across the plot area
1590
1589
  // inside the margins). Main pie on the left, secondary plot
1591
1590
  // on the right.
@@ -1715,7 +1714,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1715
1714
  labels: pieData.labels,
1716
1715
  name: dataLabel,
1717
1716
  marker: {
1718
- colors: themeColorPalette,
1717
+ // Unrolled through Excel's luminance variations so slice 7 does
1718
+ // not repeat slice 1 (rowsncolumns/spreadsheet#1045).
1719
+ colors: expandChartPalette(themeColorPalette),
1719
1720
  },
1720
1721
  };
1721
1722
  // Ties the trace back to spec.series for click selection and
@@ -2158,14 +2159,12 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2158
2159
  onUpdateChart({ ...chart, spec: next });
2159
2160
  }
2160
2161
  : undefined;
2161
- // Copy as Picture / print preview. `plotly.js/dist/plotly` is the module
2162
- // `react-plotly.js` itself is built on, loaded on demand so the render
2163
- // path stays as it was.
2162
+ // Copy as Picture / print preview, through the plotly module the chart
2163
+ // renders with.
2164
2164
  const exportChartPng = async () => {
2165
2165
  const graphDiv = graphDivRef.current;
2166
2166
  if (!graphDiv)
2167
2167
  return undefined;
2168
- const { default: Plotly } = await import("plotly.js/dist/plotly");
2169
2168
  const url = await Plotly.toImage(graphDiv, {
2170
2169
  format: "png",
2171
2170
  width: graphDiv.clientWidth || width || 600,
@@ -2201,7 +2200,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2201
2200
  onDeleteChart?.(chart.chartId);
2202
2201
  } }, "Delete chart")))))) : null,
2203
2202
  React.createElement("div", { className: "flex-1 rnc-plotly-chart-container", onPointerDownCapture: handlePointerDownCapture },
2204
- React.createElement(Plot, { ref: plotRef, data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: (_figure, graphDiv) => {
2203
+ React.createElement(Plot, { data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: (_figure, graphDiv) => {
2205
2204
  graphDivRef.current = graphDiv;
2206
2205
  }, style: { width: "100%", height: "100%" } }))));
2207
2206
  };
@@ -0,0 +1,12 @@
1
+ import Plotly from "plotly.js-dist-min";
2
+ /**
3
+ * The one plotly module the plotly charts render and export with:
4
+ * `plotly.js-dist-min`, the full bundle (every trace type) already minified.
5
+ * react-plotly.js's default entry would load the separate
6
+ * `plotly.js/dist/plotly` build instead, so a host that ships
7
+ * `plotly.js-dist-min` for its own charts would carry two copies of the same
8
+ * plotly release.
9
+ */
10
+ export { Plotly };
11
+ export declare const Plot: import("react").ComponentType<import("react-plotly.js").PlotParams>;
12
+ //# sourceMappingURL=plot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plot.d.ts","sourceRoot":"","sources":["../../../plotly/plot.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAGxC;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,eAAO,MAAM,IAAI,qEAAgC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import Plotly from "plotly.js-dist-min";
2
+ import createPlotlyComponent from "react-plotly.js/factory";
3
+ /**
4
+ * The one plotly module the plotly charts render and export with:
5
+ * `plotly.js-dist-min`, the full bundle (every trace type) already minified.
6
+ * react-plotly.js's default entry would load the separate
7
+ * `plotly.js/dist/plotly` build instead, so a host that ships
8
+ * `plotly.js-dist-min` for its own charts would carry two copies of the same
9
+ * plotly release.
10
+ */
11
+ export { Plotly };
12
+ export const Plot = createPlotlyComponent(Plotly);
@@ -1 +1 @@
1
- {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/echarts-gl-loader.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
1
+ {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/plot.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/echarts-gl-loader.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
@@ -7,12 +7,24 @@
7
7
  * so the regressions are hand-rolled here as pure least-squares math and
8
8
  * the renderers draw the returned points as an overlay line series.
9
9
  *
10
- * All fits operate on the index domain x = 0, 1, 2, … (one step per
11
- * category) which matches how a category-axis chart positions points.
12
- * The caller passes the raw y-values; gaps (null/NaN) are skipped during
13
- * fitting but the fitted curve is still emitted for every x in range.
10
+ * All fits operate on Excel's category domain x = 1, 2, …, n (one step per
11
+ * category, first category = 1) — the domain Excel fits and prints for a
12
+ * category-axis chart (line, column, bar, area). Linear, polynomial and
13
+ * exponential curves are invariant to where the domain starts (only the
14
+ * equation text moves), but logarithmic and power fits are not: fitting
15
+ * them on x = 0, 1, … dropped the first category from the fit and evaluated
16
+ * ln(x) at x → 0 for it, which drew the Jan point of a 12-month log trend
17
+ * at about −524 instead of Excel's ≈6.4 (rowsncolumns/spreadsheet#1028).
18
+ *
19
+ * The emitted points keep the renderer-facing 0-based CATEGORY INDEX in `x`
20
+ * (echarts plots `[x, y]` on the category axis, plotly maps `x` onto the
21
+ * category labels), so a forecast of k periods still extends to index
22
+ * n−1+k forward and −k backward. The caller passes the raw y-values; gaps
23
+ * (null/NaN) are skipped during fitting but the fitted curve is still
24
+ * emitted for every x in range.
14
25
  */
15
26
  export type TrendlineType = "linear" | "exp" | "log" | "poly" | "power" | "movingAvg";
27
+ /** `x` is the 0-based category index (−k … n−1+k with forecasting), `y` the fitted value. */
16
28
  export type TrendlinePoint = {
17
29
  x: number;
18
30
  y: number;
@@ -28,7 +40,8 @@ export type TrendlineResult = {
28
40
  /**
29
41
  * Compute a trendline for a series of y-values.
30
42
  *
31
- * @param values Raw y-values; the category index is used as x.
43
+ * @param values Raw y-values; the 1-based category position is used as x
44
+ * for the fit, the 0-based index is reported in the points.
32
45
  * @param spec Trendline parameters (type/order/period/forecast).
33
46
  */
34
47
  export declare const computeTrendline: (values: (number | null | undefined)[], spec?: {
@@ -1 +1 @@
1
- {"version":3,"file":"trendline.d.ts","sourceRoot":"","sources":["../../../utils/trendline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,CAAC;AAEhB,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AA+IF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,OAAM;IACJ,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,KACL,eAAe,GAAG,IA6FpB,CAAC"}
1
+ {"version":3,"file":"trendline.d.ts","sourceRoot":"","sources":["../../../utils/trendline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,CAAC;AAEhB,6FAA6F;AAC7F,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAsJF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,OAAM;IACJ,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,KACL,eAAe,GAAG,IAiGpB,CAAC"}
@@ -7,14 +7,26 @@
7
7
  * so the regressions are hand-rolled here as pure least-squares math and
8
8
  * the renderers draw the returned points as an overlay line series.
9
9
  *
10
- * All fits operate on the index domain x = 0, 1, 2, … (one step per
11
- * category) which matches how a category-axis chart positions points.
12
- * The caller passes the raw y-values; gaps (null/NaN) are skipped during
13
- * fitting but the fitted curve is still emitted for every x in range.
10
+ * All fits operate on Excel's category domain x = 1, 2, …, n (one step per
11
+ * category, first category = 1) — the domain Excel fits and prints for a
12
+ * category-axis chart (line, column, bar, area). Linear, polynomial and
13
+ * exponential curves are invariant to where the domain starts (only the
14
+ * equation text moves), but logarithmic and power fits are not: fitting
15
+ * them on x = 0, 1, … dropped the first category from the fit and evaluated
16
+ * ln(x) at x → 0 for it, which drew the Jan point of a 12-month log trend
17
+ * at about −524 instead of Excel's ≈6.4 (rowsncolumns/spreadsheet#1028).
18
+ *
19
+ * The emitted points keep the renderer-facing 0-based CATEGORY INDEX in `x`
20
+ * (echarts plots `[x, y]` on the category axis, plotly maps `x` onto the
21
+ * category labels), so a forecast of k periods still extends to index
22
+ * n−1+k forward and −k backward. The caller passes the raw y-values; gaps
23
+ * (null/NaN) are skipped during fitting but the fitted curve is still
24
+ * emitted for every x in range.
14
25
  */
15
26
  const isFiniteNum = (v) => typeof v === "number" && Number.isFinite(v);
16
27
  /**
17
- * Build (x, y) pairs from raw y-values using the category index as x.
28
+ * Build (x, y) pairs from raw y-values using Excel's 1-based category
29
+ * position as x (the first category is x = 1, see the module comment).
18
30
  * Non-finite y-values are dropped (they cannot be fitted).
19
31
  */
20
32
  const toPairs = (values) => {
@@ -22,7 +34,7 @@ const toPairs = (values) => {
22
34
  for (let i = 0; i < values.length; i++) {
23
35
  const y = values[i];
24
36
  if (isFiniteNum(y))
25
- pairs.push({ x: i, y });
37
+ pairs.push({ x: i + 1, y });
26
38
  }
27
39
  return pairs;
28
40
  };
@@ -48,6 +60,11 @@ const round = (n, digits = 4) => {
48
60
  const f = 10 ** digits;
49
61
  return Math.round(n * f) / f;
50
62
  };
63
+ /** `+ 2` / `- 2` for an additive term, the way Excel prints an equation. */
64
+ const signed = (n) => {
65
+ const r = round(n);
66
+ return r < 0 ? `- ${Math.abs(r)}` : `+ ${r}`;
67
+ };
51
68
  /** Solve a small linear system A·x = b via Gaussian elimination. */
52
69
  const solveLinearSystem = (A, b) => {
53
70
  const n = b.length;
@@ -157,7 +174,8 @@ const fitPower = (pairs) => {
157
174
  /**
158
175
  * Compute a trendline for a series of y-values.
159
176
  *
160
- * @param values Raw y-values; the category index is used as x.
177
+ * @param values Raw y-values; the 1-based category position is used as x
178
+ * for the fit, the 0-based index is reported in the points.
161
179
  * @param spec Trendline parameters (type/order/period/forecast).
162
180
  */
163
181
  export const computeTrendline = (values, spec = {}) => {
@@ -187,9 +205,9 @@ export const computeTrendline = (values, spec = {}) => {
187
205
  }
188
206
  return { points, rSquared: null, equation: null };
189
207
  }
190
- const lastX = values.length - 1;
191
- const xStart = -backward;
192
- const xEnd = lastX + forward;
208
+ // Fit domain is 1..n; a forecast of k periods extends it to 1−k / n+k.
209
+ const xStart = 1 - backward;
210
+ const xEnd = values.length + forward;
193
211
  const xs = [];
194
212
  for (let x = xStart; x <= xEnd; x++)
195
213
  xs.push(x);
@@ -201,7 +219,7 @@ export const computeTrendline = (values, spec = {}) => {
201
219
  if (!fit)
202
220
  return null;
203
221
  predict = (x) => fit.m * x + fit.b;
204
- equation = `y = ${round(fit.m)}x + ${round(fit.b)}`;
222
+ equation = `y = ${round(fit.m)}x ${signed(fit.b)}`;
205
223
  break;
206
224
  }
207
225
  case "poly": {
@@ -212,8 +230,8 @@ export const computeTrendline = (values, spec = {}) => {
212
230
  equation =
213
231
  "y = " +
214
232
  coeffs
215
- .map((c, i) => (i === 0 ? `${round(c)}` : `${round(c)}x^${i}`))
216
- .join(" + ");
233
+ .map((c, i) => i === 0 ? `${round(c)}` : `${signed(c)}x${i === 1 ? "" : `^${i}`}`)
234
+ .join(" ");
217
235
  break;
218
236
  }
219
237
  case "exp": {
@@ -228,9 +246,10 @@ export const computeTrendline = (values, spec = {}) => {
228
246
  const fit = fitLog(pairs);
229
247
  if (!fit)
230
248
  return null;
231
- // ln(0) and ln(negative) are undefined; clamp x to >0 for the curve.
249
+ // Only a backward forecast reaches x ≤ 0 (the fit domain starts at 1);
250
+ // ln(0) and ln(negative) are undefined, so clamp x to >0 for the curve.
232
251
  predict = (x) => fit.a + fit.b * Math.log(x <= 0 ? 1e-9 : x);
233
- equation = `y = ${round(fit.a)} + ${round(fit.b)}ln(x)`;
252
+ equation = `y = ${round(fit.b)}ln(x) ${signed(fit.a)}`;
234
253
  break;
235
254
  }
236
255
  case "power": {
@@ -244,8 +263,9 @@ export const computeTrendline = (values, spec = {}) => {
244
263
  default:
245
264
  return null;
246
265
  }
266
+ // Report the renderer-facing 0-based category index (see module comment).
247
267
  const points = xs
248
- .map((x) => ({ x, y: predict(x) }))
268
+ .map((x) => ({ x: x - 1, y: predict(x) }))
249
269
  .filter((p) => Number.isFinite(p.y));
250
270
  if (points.length < 2)
251
271
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowsncolumns/charts",
3
- "version": "28.1.4",
3
+ "version": "28.1.6",
4
4
  "author": "Vinay M",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "main": "./dist/cjs/index.js",
@@ -70,16 +70,16 @@
70
70
  "@rowsncolumns/common-types": ">=5.3.2",
71
71
  "@rowsncolumns/grid": ">=13.2.35",
72
72
  "@rowsncolumns/icons": ">=7.2.33",
73
- "@rowsncolumns/spreadsheet": ">=10.4.4",
74
- "@rowsncolumns/spreadsheet-state": ">=29.1.6",
75
- "@rowsncolumns/toolkit": ">=24.5.5",
73
+ "@rowsncolumns/spreadsheet": ">=10.4.5",
74
+ "@rowsncolumns/spreadsheet-state": ">=29.1.7",
75
+ "@rowsncolumns/toolkit": ">=24.5.7",
76
76
  "@rowsncolumns/ui": ">=16.0.4",
77
- "@rowsncolumns/utils": ">=9.5.3",
77
+ "@rowsncolumns/utils": ">=9.5.5",
78
78
  "@types/react-plotly.js": "^2.6.3",
79
79
  "echarts": "^5.6.0",
80
80
  "formik": "^2.4.6",
81
81
  "immer": "^10.1.1",
82
- "plotly.js": "^3.1.1",
82
+ "plotly.js-dist-min": "^3.1.1",
83
83
  "react-plotly.js": "^2.6.0"
84
84
  },
85
85
  "peerDependencies": {
@@ -94,7 +94,7 @@
94
94
  "@rowsncolumns/utils": ">=9.3.0",
95
95
  "immer": ">10.0.0",
96
96
  "jotai": ">=2.10.3",
97
- "plotly.js": ">=3",
97
+ "plotly.js-dist-min": ">=3",
98
98
  "react": ">=18.0.0",
99
99
  "react-dom": ">=18.0.0",
100
100
  "react-plotly.js": ">=2"