@rowsncolumns/charts 28.1.4 → 28.1.5

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":"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,sBAmzGjB,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) {
@@ -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 seriesPalette[index % seriesPalette.length];
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)
@@ -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":"AA6BA,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,sBA4zEjB,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);
@@ -2001,27 +2000,23 @@ var BasicChart = function (_a) {
2001
2000
  onUpdateChart(tslib_1.__assign(tslib_1.__assign({}, chart), { spec: next }));
2002
2001
  }
2003
2002
  : 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.
2003
+ // Copy as Picture / print preview, through the plotly module the chart
2004
+ // renders with.
2007
2005
  var exportChartPng = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
2008
- var graphDiv, Plotly, url;
2006
+ var graphDiv, url;
2009
2007
  return tslib_1.__generator(this, function (_a) {
2010
2008
  switch (_a.label) {
2011
2009
  case 0:
2012
2010
  graphDiv = graphDivRef.current;
2013
2011
  if (!graphDiv)
2014
2012
  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, {
2013
+ return [4 /*yield*/, plot_1.Plotly.toImage(graphDiv, {
2019
2014
  format: "png",
2020
2015
  width: graphDiv.clientWidth || width || 600,
2021
2016
  height: graphDiv.clientHeight || height || 400,
2022
2017
  scale: 2,
2023
2018
  })];
2024
- case 2:
2019
+ case 1:
2025
2020
  url = _a.sent();
2026
2021
  return [2 /*return*/, (0, chart_image_1.dataUrlToBlob)(url)];
2027
2022
  }
@@ -2054,7 +2049,7 @@ var BasicChart = function (_a) {
2054
2049
  onDeleteChart === null || onDeleteChart === void 0 ? void 0 : onDeleteChart(chart.chartId);
2055
2050
  } }, "Delete chart")))))) : null,
2056
2051
  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) {
2052
+ react_1.default.createElement(plot_1.Plot, { data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: function (_figure, graphDiv) {
2058
2053
  graphDivRef.current = graphDiv;
2059
2054
  }, style: { width: "100%", height: "100%" } }))));
2060
2055
  };
@@ -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":"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,sBAmzGjB,CAAC"}
@@ -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) => seriesPalette[index % seriesPalette.length];
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) => {
@@ -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":"AA6BA,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,sBA4zEjB,CAAC"}
@@ -4,7 +4,6 @@ import { useSubscribeToSheet } from "@rowsncolumns/spreadsheet-state";
4
4
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuTrigger, IconButton, useIsomorphicLayoutEffect, useOnVisibilityChange, } from "@rowsncolumns/ui";
5
5
  import { debug, 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);
@@ -2158,14 +2157,12 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2158
2157
  onUpdateChart({ ...chart, spec: next });
2159
2158
  }
2160
2159
  : 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.
2160
+ // Copy as Picture / print preview, through the plotly module the chart
2161
+ // renders with.
2164
2162
  const exportChartPng = async () => {
2165
2163
  const graphDiv = graphDivRef.current;
2166
2164
  if (!graphDiv)
2167
2165
  return undefined;
2168
- const { default: Plotly } = await import("plotly.js/dist/plotly");
2169
2166
  const url = await Plotly.toImage(graphDiv, {
2170
2167
  format: "png",
2171
2168
  width: graphDiv.clientWidth || width || 600,
@@ -2201,7 +2198,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
2201
2198
  onDeleteChart?.(chart.chartId);
2202
2199
  } }, "Delete chart")))))) : null,
2203
2200
  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) => {
2201
+ React.createElement(Plot, { data: plotData, layout: plotLayout, config: config, onClick: handlePlotClick, onInitialized: (_figure, graphDiv) => {
2205
2202
  graphDivRef.current = graphDiv;
2206
2203
  }, style: { width: "100%", height: "100%" } }))));
2207
2204
  };
@@ -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.5",
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.6",
76
76
  "@rowsncolumns/ui": ">=16.0.4",
77
- "@rowsncolumns/utils": ">=9.5.3",
77
+ "@rowsncolumns/utils": ">=9.5.4",
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"