@rowsncolumns/charts 28.1.13 → 28.1.15
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.
- package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/cjs/basic-chart/basic-chart.js +308 -270
- package/dist/cjs/components/editors/chart-editor-capabilities.d.ts +48 -0
- package/dist/cjs/components/editors/chart-editor-capabilities.d.ts.map +1 -0
- package/dist/cjs/components/editors/chart-editor-capabilities.js +62 -0
- package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/chart-editor.js +200 -534
- package/dist/cjs/components/editors/fields/axis-options-fields.d.ts +16 -0
- package/dist/cjs/components/editors/fields/axis-options-fields.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/axis-options-fields.js +31 -0
- package/dist/cjs/components/editors/fields/chart-type-options.d.ts +25 -0
- package/dist/cjs/components/editors/fields/chart-type-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/chart-type-options.js +170 -0
- package/dist/cjs/components/editors/fields/data-labels-fields.d.ts +15 -0
- package/dist/cjs/components/editors/fields/data-labels-fields.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/data-labels-fields.js +57 -0
- package/dist/cjs/components/editors/fields/primitives.d.ts +54 -0
- package/dist/cjs/components/editors/fields/primitives.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/primitives.js +52 -0
- package/dist/cjs/components/editors/fields/series-format-fields.d.ts +17 -0
- package/dist/cjs/components/editors/fields/series-format-fields.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/series-format-fields.js +165 -0
- package/dist/cjs/components/editors/fields/series-name-field.d.ts +16 -0
- package/dist/cjs/components/editors/fields/series-name-field.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/series-name-field.js +36 -0
- package/dist/cjs/components/editors/fields/text-format-fields.d.ts +20 -0
- package/dist/cjs/components/editors/fields/text-format-fields.d.ts.map +1 -0
- package/dist/cjs/components/editors/fields/text-format-fields.js +46 -0
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +3 -0
- package/dist/cjs/interface/create-chart.d.ts +3 -2
- package/dist/cjs/interface/create-chart.d.ts.map +1 -1
- package/dist/cjs/interface/create-chart.js +7 -0
- package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/cjs/plotly/basic-chart/basic-chart.js +255 -218
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils/chart-orientation.d.ts.map +1 -1
- package/dist/cjs/utils/chart-orientation.js +24 -12
- package/dist/cjs/utils/chart-spec-utils.d.ts.map +1 -1
- package/dist/cjs/utils/chart-spec-utils.js +120 -21
- package/dist/cjs/utils/echarts-overlays.d.ts +2 -0
- package/dist/cjs/utils/echarts-overlays.d.ts.map +1 -1
- package/dist/cjs/utils/echarts-overlays.js +25 -12
- package/dist/cjs/utils/series-name.d.ts +12 -0
- package/dist/cjs/utils/series-name.d.ts.map +1 -0
- package/dist/cjs/utils/series-name.js +26 -0
- package/dist/cjs/utils/trendline.d.ts +9 -0
- package/dist/cjs/utils/trendline.d.ts.map +1 -1
- package/dist/cjs/utils/trendline.js +16 -1
- package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/basic-chart/basic-chart.js +73 -37
- package/dist/esm/components/editors/chart-editor-capabilities.d.ts +48 -0
- package/dist/esm/components/editors/chart-editor-capabilities.d.ts.map +1 -0
- package/dist/esm/components/editors/chart-editor-capabilities.js +58 -0
- package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/chart-editor.js +166 -448
- package/dist/esm/components/editors/fields/axis-options-fields.d.ts +16 -0
- package/dist/esm/components/editors/fields/axis-options-fields.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/axis-options-fields.js +22 -0
- package/dist/esm/components/editors/fields/chart-type-options.d.ts +25 -0
- package/dist/esm/components/editors/fields/chart-type-options.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/chart-type-options.js +151 -0
- package/dist/esm/components/editors/fields/data-labels-fields.d.ts +15 -0
- package/dist/esm/components/editors/fields/data-labels-fields.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/data-labels-fields.js +47 -0
- package/dist/esm/components/editors/fields/primitives.d.ts +54 -0
- package/dist/esm/components/editors/fields/primitives.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/primitives.js +26 -0
- package/dist/esm/components/editors/fields/series-format-fields.d.ts +17 -0
- package/dist/esm/components/editors/fields/series-format-fields.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/series-format-fields.js +143 -0
- package/dist/esm/components/editors/fields/series-name-field.d.ts +16 -0
- package/dist/esm/components/editors/fields/series-name-field.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/series-name-field.js +31 -0
- package/dist/esm/components/editors/fields/text-format-fields.d.ts +20 -0
- package/dist/esm/components/editors/fields/text-format-fields.d.ts.map +1 -0
- package/dist/esm/components/editors/fields/text-format-fields.js +34 -0
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +3 -0
- package/dist/esm/interface/create-chart.d.ts +3 -2
- package/dist/esm/interface/create-chart.d.ts.map +1 -1
- package/dist/esm/interface/create-chart.js +8 -1
- package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/plotly/basic-chart/basic-chart.js +52 -30
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/chart-orientation.d.ts.map +1 -1
- package/dist/esm/utils/chart-orientation.js +20 -0
- package/dist/esm/utils/chart-spec-utils.d.ts.map +1 -1
- package/dist/esm/utils/chart-spec-utils.js +95 -8
- package/dist/esm/utils/echarts-overlays.d.ts +2 -0
- package/dist/esm/utils/echarts-overlays.d.ts.map +1 -1
- package/dist/esm/utils/echarts-overlays.js +15 -1
- package/dist/esm/utils/series-name.d.ts +12 -0
- package/dist/esm/utils/series-name.d.ts.map +1 -0
- package/dist/esm/utils/series-name.js +24 -0
- package/dist/esm/utils/trendline.d.ts +9 -0
- package/dist/esm/utils/trendline.d.ts.map +1 -1
- package/dist/esm/utils/trendline.js +14 -0
- package/package.json +3 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Input, Stack } from "@rowsncolumns/ui";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ChartRangeInput } from "../chart-range-input";
|
|
4
|
+
/**
|
|
5
|
+
* Excel's "Series name": either text, or a link to a header cell
|
|
6
|
+
* (`dataLabelSource`, #1100). A linked name shows the cell's current text
|
|
7
|
+
* and the cell it comes from; typing a name replaces the link with the
|
|
8
|
+
* literal, picking a cell links it.
|
|
9
|
+
*/
|
|
10
|
+
export const SeriesNameField = ({ sheetId, series, getFormattedValue, onChange, }) => {
|
|
11
|
+
const source = series.dataLabelSource ?? undefined;
|
|
12
|
+
const linkedText = source
|
|
13
|
+
? getFormattedValue?.(source.sheetId, source.startRowIndex, source.startColumnIndex)
|
|
14
|
+
: undefined;
|
|
15
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
|
|
16
|
+
React.createElement("label", { className: "font-system text-sm" }, "Name"),
|
|
17
|
+
React.createElement(Input, { value: (source ? linkedText ?? series.dataLabel : series.dataLabel) ?? "", type: "text", onChange: (e) => onChange({ dataLabel: e.target.value, dataLabelSource: undefined }), className: "text-xs", placeholder: "Series name", "aria-label": "Series name" }),
|
|
18
|
+
React.createElement("label", { className: "font-system text-xs text-rnc-muted-foreground" }, source ? "Linked to cell" : "Or link to a cell"),
|
|
19
|
+
React.createElement(ChartRangeInput, { sheetId: sheetId, range: source, onChangeRange: (range) => {
|
|
20
|
+
const cell = {
|
|
21
|
+
...range,
|
|
22
|
+
endRowIndex: range.startRowIndex,
|
|
23
|
+
endColumnIndex: range.startColumnIndex,
|
|
24
|
+
};
|
|
25
|
+
onChange({
|
|
26
|
+
dataLabel: getFormattedValue?.(cell.sheetId, cell.startRowIndex, cell.startColumnIndex) ??
|
|
27
|
+
series.dataLabel,
|
|
28
|
+
dataLabelSource: cell,
|
|
29
|
+
});
|
|
30
|
+
}, placeholder: "Header cell", className: "mb-0" })));
|
|
31
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ChartTextFormat } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Font family / size / colour / bold / italic / underline / strikethrough
|
|
5
|
+
* of one text element — the chart title, the legend, an axis or the data
|
|
6
|
+
* labels (`ChartTextFormat`, OOXML `<c:txPr>`).
|
|
7
|
+
*/
|
|
8
|
+
export declare const TextFormatFields: ({ label, value, onChange, collapsible, ariaLabels, }: {
|
|
9
|
+
label: string;
|
|
10
|
+
value: ChartTextFormat | null | undefined;
|
|
11
|
+
onChange(next: ChartTextFormat | undefined): void;
|
|
12
|
+
/** Mount the fields behind a "Font…" toggle (secondary text elements). */
|
|
13
|
+
collapsible?: boolean;
|
|
14
|
+
ariaLabels?: {
|
|
15
|
+
family?: string;
|
|
16
|
+
size?: string;
|
|
17
|
+
color?: string;
|
|
18
|
+
};
|
|
19
|
+
}) => React.JSX.Element;
|
|
20
|
+
//# sourceMappingURL=text-format-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-format-fields.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/text-format-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,sDAM9B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC;IAClD,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjE,sBA6EA,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Input } from "@rowsncolumns/ui";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { CheckboxField, COLOR_CLASS } from "./primitives";
|
|
4
|
+
/**
|
|
5
|
+
* Font family / size / colour / bold / italic / underline / strikethrough
|
|
6
|
+
* of one text element — the chart title, the legend, an axis or the data
|
|
7
|
+
* labels (`ChartTextFormat`, OOXML `<c:txPr>`).
|
|
8
|
+
*/
|
|
9
|
+
export const TextFormatFields = ({ label, value, onChange, collapsible = false, ariaLabels, }) => {
|
|
10
|
+
const [open, setOpen] = useState(!collapsible);
|
|
11
|
+
if (collapsible && !open) {
|
|
12
|
+
return (React.createElement("div", { className: "pb-2" },
|
|
13
|
+
React.createElement("button", { type: "button", className: "font-system text-xs text-rnc-muted-foreground underline", onClick: () => setOpen(true) },
|
|
14
|
+
label,
|
|
15
|
+
"\u2026")));
|
|
16
|
+
}
|
|
17
|
+
const set = (patch) => {
|
|
18
|
+
const next = { ...(value ?? {}), ...patch };
|
|
19
|
+
const entries = Object.entries(next).filter(([, v]) => v !== undefined && v !== null && v !== false && v !== "");
|
|
20
|
+
onChange(entries.length ? Object.fromEntries(entries) : undefined);
|
|
21
|
+
};
|
|
22
|
+
return (React.createElement("div", { className: "flex flex-col gap-1 pb-2" },
|
|
23
|
+
React.createElement("label", { className: "font-system text-sm" }, label),
|
|
24
|
+
React.createElement("div", { className: "flex items-center gap-1 flex-wrap" },
|
|
25
|
+
React.createElement(Input, { value: value?.fontFamily ?? "", type: "text", onChange: (e) => set({ fontFamily: e.target.value || undefined }), className: "text-xs w-32", placeholder: "Font family", "aria-label": ariaLabels?.family ?? `${label} family` }),
|
|
26
|
+
React.createElement(Input, { value: value?.fontSize ?? "", type: "number", min: 1, onChange: (e) => set({
|
|
27
|
+
fontSize: e.target.value === "" ? undefined : Number(e.target.value),
|
|
28
|
+
}), className: "text-xs w-16", placeholder: "Size", "aria-label": ariaLabels?.size ?? `${label} size` }),
|
|
29
|
+
React.createElement("input", { type: "color", value: value?.color ?? "#000000", onChange: (e) => set({ color: e.target.value }), className: COLOR_CLASS, "aria-label": ariaLabels?.color ?? `${label} color` }),
|
|
30
|
+
React.createElement(CheckboxField, { label: "Bold", checked: Boolean(value?.bold), onChange: (bold) => set({ bold }) }),
|
|
31
|
+
React.createElement(CheckboxField, { label: "Italic", checked: Boolean(value?.italic), onChange: (italic) => set({ italic }) }),
|
|
32
|
+
React.createElement(CheckboxField, { label: "Underline", checked: Boolean(value?.underline), onChange: (underline) => set({ underline }) }),
|
|
33
|
+
React.createElement(CheckboxField, { label: "Strikethrough", checked: Boolean(value?.strikethrough), onChange: (strikethrough) => set({ strikethrough }) }))));
|
|
34
|
+
};
|
package/dist/esm/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAwR3D,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAgB1E,CAAC;AAYJ;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,OAQzD,CAAC;AAuBF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,MA4B9D,CAAC"}
|
package/dist/esm/config.js
CHANGED
|
@@ -232,6 +232,9 @@ const HIERARCHY_CHART_TYPES = [
|
|
|
232
232
|
];
|
|
233
233
|
const STATISTICAL_CHART_TYPES = [
|
|
234
234
|
["Histogram", { chartType: "histogram" }],
|
|
235
|
+
// Excel's Pareto: a histogram with its bins sorted descending plus a
|
|
236
|
+
// cumulative-% line (sourceChartType PARETO, the import token).
|
|
237
|
+
["Pareto", { chartType: "histogram", sourceChartType: "PARETO" }],
|
|
235
238
|
["Box & Whisker", { chartType: "boxplot" }],
|
|
236
239
|
];
|
|
237
240
|
const FLOW_CHART_TYPES = [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { CellInterface, SelectionArea } from "@rowsncolumns/grid";
|
|
2
|
-
import {
|
|
1
|
+
import type { CellInterface, SelectionArea } from "@rowsncolumns/grid";
|
|
2
|
+
import type { EmbeddedChart, SelectionAttributes } from "@rowsncolumns/spreadsheet";
|
|
3
|
+
import { type CellData } from "@rowsncolumns/spreadsheet";
|
|
3
4
|
import type { UseOnCreateChartProps } from "../hooks/use-on-create-chart";
|
|
4
5
|
/**
|
|
5
6
|
* Ensures endIndex is at least minValue.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-chart.d.ts","sourceRoot":"","sources":["../../../interface/create-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-chart.d.ts","sourceRoot":"","sources":["../../../interface/create-chart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,KAAK,EAIV,aAAa,EACb,mBAAmB,EACR,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EACL,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAiB1E;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,GAAG,SAAS,EAC5B,UAAU,MAAM,KACf,MAAkF,CAAC;AAEtF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,QAAQ,EAAE,8FAM7C,qBAAqB,CAAC,CAAC,CAAC,MAEvB,SAAS,MAAM,EACf,YAAY,aAAa,EACzB,YAAY,aAAa,CAAC,mBAAmB,CAAC,EAAE,EAChD,YAAY,aAAa,kBA8H5B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isNumber, selectionBoundsFromCells, uuid } from "@rowsncolumns/utils";
|
|
2
2
|
import { enablePatches, produceWithPatches } from "immer";
|
|
3
3
|
import { deriveChartSeriesFromRange, pickSeriesOrientationForRange, } from "../utils/chart-orientation";
|
|
4
|
-
import {
|
|
4
|
+
import { getDefaultChartTypeSpec, isBasicChartSpec, } from "../utils/chart-spec-utils";
|
|
5
5
|
// For external interface
|
|
6
6
|
enablePatches();
|
|
7
7
|
/**
|
|
@@ -30,6 +30,13 @@ export const createChart = ({ onChangeCharts, getFormattedValue, getEffectiveVal
|
|
|
30
30
|
? [
|
|
31
31
|
{
|
|
32
32
|
dataLabel: getFormattedValue(sheetId, lastSelection.range.startRowIndex, lastSelection.range.startColumnIndex) ?? "",
|
|
33
|
+
dataLabelSource: {
|
|
34
|
+
sheetId,
|
|
35
|
+
startRowIndex: lastSelection.range.startRowIndex,
|
|
36
|
+
endRowIndex: lastSelection.range.startRowIndex,
|
|
37
|
+
startColumnIndex: lastSelection.range.startColumnIndex,
|
|
38
|
+
endColumnIndex: lastSelection.range.startColumnIndex,
|
|
39
|
+
},
|
|
33
40
|
sources: categoryAxis,
|
|
34
41
|
aggregateType: "COUNT",
|
|
35
42
|
},
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AA+ZxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAmGnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBA2rFjB,CAAC"}
|
|
@@ -7,29 +7,30 @@ import React, { useCallback, useMemo, useRef, useState } from "react";
|
|
|
7
7
|
import { aggregateSeriesByDomain, getDomainValuesForAxis, sanitizeDomainValues, shouldAggregateSeries, } from "../../utils/aggregation";
|
|
8
8
|
import { formatAxisValue, numberFormatToPlotlyTicks, plotlySeparators, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
|
|
9
9
|
import { createBubbleSizeScale, prepareBubbleSeriesData, toLabelString, } from "../../utils/bubble";
|
|
10
|
-
import {
|
|
10
|
+
import { plotlyMulticategoryX, resolveCategoryLevels, } from "../../utils/category-levels";
|
|
11
11
|
import { dataUrlToBlob } from "../../utils/chart-image";
|
|
12
|
-
import {
|
|
12
|
+
import { canSwitchRowColumn, cellLabelGetterFromRangeReader, switchRowColumn, } from "../../utils/chart-orientation";
|
|
13
13
|
import { coerceCalculatedLabel } from "../../utils/chart-spec-utils";
|
|
14
|
+
import { getChartPalette } from "../../utils/chart-styles";
|
|
15
|
+
import { clampDoughnutHole, doughnutRings } from "../../utils/doughnut";
|
|
14
16
|
import { applyEmptyCellsPolicy, connectsAcrossEmptyCells, isLineLikeChartType, isolatedPointIndexes, } from "../../utils/empty-cells";
|
|
15
17
|
import { computeErrorBars, resolveCustomErrorBarValues, } from "../../utils/error-bars";
|
|
16
|
-
import { plotlyMulticategoryX, resolveCategoryLevels, } from "../../utils/category-levels";
|
|
17
18
|
import { gradientToPlotly } from "../../utils/gradient";
|
|
19
|
+
import { extractHierarchyRows, getHierarchyHeaderTitle, hierarchyNodeColors, toPlotlyHierarchy, } from "../../utils/hierarchy";
|
|
20
|
+
import { aggregateByCategory, binHistogram, computePareto, hasExcelBinning, isParetoSpec, } from "../../utils/histogram";
|
|
18
21
|
import { BAND_GAP, legendLabelsFrom, measureTextWidth, reservePlotlyLegendBand, } from "../../utils/legend-layout";
|
|
19
|
-
import {
|
|
22
|
+
import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../../utils/of-pie";
|
|
20
23
|
import { dataLabelFormatter, resolveSeriesDataLabels, } from "../../utils/overrides";
|
|
21
|
-
import { plotlyTitleText } from "../../utils/plotly-title";
|
|
22
24
|
import { explosionToPlotlyPull, resolveExplosion, } from "../../utils/pie-explosion";
|
|
23
25
|
import { resolvePlotlyClickSelection, wasDragged, } from "../../utils/plotly-click";
|
|
24
26
|
import { buildPlotlySurfaceTrace } from "../../utils/plotly-surface";
|
|
25
|
-
import {
|
|
26
|
-
import { extractHierarchyRows, getHierarchyHeaderTitle, hierarchyNodeColors, toPlotlyHierarchy, } from "../../utils/hierarchy";
|
|
27
|
-
import { aggregateByCategory, binHistogram, computePareto, hasExcelBinning, isParetoSpec, } from "../../utils/histogram";
|
|
28
|
-
import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../../utils/of-pie";
|
|
27
|
+
import { plotlyTitleText } from "../../utils/plotly-title";
|
|
29
28
|
import { buildRadarIndicators } from "../../utils/radar";
|
|
30
29
|
import { buildSequentialColorRamp, isRegionMapSpec, resolveGeoScope, WORLD_GEO_SCOPE, } from "../../utils/region-map";
|
|
30
|
+
import { linkedSeriesName } from "../../utils/series-name";
|
|
31
31
|
import { assignStockRoles, toLineSeries, toVolumeSeries, } from "../../utils/stock";
|
|
32
|
-
import {
|
|
32
|
+
import { normalize3DSourceType, } from "../../utils/three-d";
|
|
33
|
+
import { computeTrendline, trendlineLabel } from "../../utils/trendline";
|
|
33
34
|
import { Plot, Plotly } from "../plot";
|
|
34
35
|
import { chartTypeToPlotlyType, getPlotlyTraceStyle, mapMarkerSymbolToPlotly, showXAxis, } from "./helpers";
|
|
35
36
|
const BASIC_CHART_TYPES = new Set([
|
|
@@ -503,8 +504,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
503
504
|
const seriesInputs = [];
|
|
504
505
|
for (let i = 0; i < spec.series.length; i++) {
|
|
505
506
|
const seriesEntry = spec.series[i];
|
|
506
|
-
|
|
507
|
-
|
|
507
|
+
const linkedLabel = linkedSeriesName(seriesEntry, getDomainValuesFromRange);
|
|
508
|
+
let resolvedLabel = linkedLabel ?? seriesEntry.dataLabel ?? "";
|
|
509
|
+
if (linkedLabel === undefined && resolvedLabel && isAFormula(resolvedLabel)) {
|
|
508
510
|
resolvedLabel = coerceCalculatedLabel(await onRequestCalculate(resolvedLabel, chart.position.sheetId ?? sheetId, chart.position.overlayPosition.anchorCell.rowIndex, chart.position.overlayPosition.anchorCell.columnIndex));
|
|
509
511
|
}
|
|
510
512
|
// Per-series X, with fallback to the first domain so single-X
|
|
@@ -693,9 +695,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
693
695
|
continue;
|
|
694
696
|
const tlName = tl.name ??
|
|
695
697
|
`${entry.name ? entry.name + " " : ""}${tl.type ?? "linear"} trend`;
|
|
698
|
+
const label = trendlineLabel(tl, result);
|
|
696
699
|
traces.push({
|
|
697
700
|
type: "scatter",
|
|
698
|
-
mode: "lines",
|
|
701
|
+
mode: label ? "lines+text" : "lines",
|
|
699
702
|
name: tlName,
|
|
700
703
|
x: result.points.map((p) => hasStringX
|
|
701
704
|
? categories[Math.round(p.x)] ?? p.x
|
|
@@ -703,6 +706,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
703
706
|
y: result.points.map((p) => p.y),
|
|
704
707
|
line: { color: tl.color ?? seriesColor, dash: "dash", width: 2 },
|
|
705
708
|
hoverinfo: "skip",
|
|
709
|
+
...(label
|
|
710
|
+
? {
|
|
711
|
+
// Excel prints the equation / R² at the line's end.
|
|
712
|
+
text: result.points.map((_, i) => i === result.points.length - 1 ? label.replace("\n", "<br>") : ""),
|
|
713
|
+
textposition: "top left",
|
|
714
|
+
textfont: { color: tl.color ?? seriesColor, size: 11 },
|
|
715
|
+
}
|
|
716
|
+
: {}),
|
|
706
717
|
...onSecondary,
|
|
707
718
|
});
|
|
708
719
|
}
|
|
@@ -1006,9 +1017,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1006
1017
|
const categories = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map((v) => String(v ?? ""));
|
|
1007
1018
|
const surfaceSeriesInputs = [];
|
|
1008
1019
|
for (const seriesEntry of spec.series ?? []) {
|
|
1009
|
-
const dataLabel =
|
|
1010
|
-
|
|
1011
|
-
|
|
1020
|
+
const dataLabel = linkedSeriesName(seriesEntry, getDomainValuesFromRange) ??
|
|
1021
|
+
(!isNil(seriesEntry.dataLabel) && isAFormula(seriesEntry.dataLabel)
|
|
1022
|
+
? coerceCalculatedLabel(await onRequestCalculate(seriesEntry.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
|
|
1023
|
+
: seriesEntry.dataLabel ?? "");
|
|
1012
1024
|
const values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map((v) => (typeof v === "number" ? v : Number(v)));
|
|
1013
1025
|
surfaceSeriesInputs.push({ name: dataLabel, values });
|
|
1014
1026
|
}
|
|
@@ -1068,9 +1080,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1068
1080
|
const radarTraces = [];
|
|
1069
1081
|
const radarInputs = [];
|
|
1070
1082
|
for (const seriesEntry of spec.series ?? []) {
|
|
1071
|
-
const label = seriesEntry
|
|
1072
|
-
|
|
1073
|
-
|
|
1083
|
+
const label = linkedSeriesName(seriesEntry, getDomainValuesFromRange) ??
|
|
1084
|
+
(seriesEntry.dataLabel && !isAFormula(seriesEntry.dataLabel)
|
|
1085
|
+
? seriesEntry.dataLabel
|
|
1086
|
+
: "");
|
|
1074
1087
|
const values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map((v) => (typeof v === "number" ? v : Number(v)));
|
|
1075
1088
|
radarInputs.push({ name: label, values });
|
|
1076
1089
|
}
|
|
@@ -1579,9 +1592,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1579
1592
|
const categories = categoriesFor(series);
|
|
1580
1593
|
const xs = result.points.map((p) => p.x >= 0 && p.x < categories.length ? categories[p.x] : p.x);
|
|
1581
1594
|
const ys = result.points.map((p) => p.y);
|
|
1595
|
+
const label = trendlineLabel(tl, result);
|
|
1582
1596
|
const overlay = {
|
|
1583
1597
|
type: "scatter",
|
|
1584
|
-
mode: "lines",
|
|
1598
|
+
mode: label ? "lines+text" : "lines",
|
|
1585
1599
|
name: tlName,
|
|
1586
1600
|
line: {
|
|
1587
1601
|
color: tl.color ?? seriesColor,
|
|
@@ -1589,6 +1603,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1589
1603
|
width: 2,
|
|
1590
1604
|
},
|
|
1591
1605
|
hoverinfo: "skip",
|
|
1606
|
+
...(label
|
|
1607
|
+
? {
|
|
1608
|
+
// Excel prints the equation / R² at the line's end.
|
|
1609
|
+
text: result.points.map((_, i) => i === result.points.length - 1 ? label.replace("\n", "<br>") : ""),
|
|
1610
|
+
textposition: "top left",
|
|
1611
|
+
textfont: { color: tl.color ?? seriesColor, size: 11 },
|
|
1612
|
+
}
|
|
1613
|
+
: {}),
|
|
1592
1614
|
...(series.useSecondaryAxis
|
|
1593
1615
|
? { [valueAxisKey]: secondaryValueAxisRef }
|
|
1594
1616
|
: {}),
|
|
@@ -1613,9 +1635,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1613
1635
|
let seriesIndex = 0;
|
|
1614
1636
|
for (const series of spec.series ?? []) {
|
|
1615
1637
|
const currentSeriesIndex = seriesIndex++;
|
|
1616
|
-
const dataLabel =
|
|
1617
|
-
|
|
1618
|
-
|
|
1638
|
+
const dataLabel = linkedSeriesName(series, getDomainValuesFromRange) ??
|
|
1639
|
+
(!isNil(series.dataLabel) && isAFormula(series.dataLabel)
|
|
1640
|
+
? coerceCalculatedLabel(await onRequestCalculate(series.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
|
|
1641
|
+
: series.dataLabel ?? "");
|
|
1619
1642
|
// A series with no ranges draws nothing.
|
|
1620
1643
|
if (series.sources.length === 0)
|
|
1621
1644
|
continue;
|
|
@@ -1754,10 +1777,11 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1754
1777
|
const showMeanLine = spec.showMeanLine === true;
|
|
1755
1778
|
// A category domain groups the series by its values (one box per
|
|
1756
1779
|
// category per series, `boxmode: "group"` in the layout); without
|
|
1757
|
-
// one
|
|
1758
|
-
//
|
|
1759
|
-
//
|
|
1760
|
-
//
|
|
1780
|
+
// one every series is a box in a single group labelled "1", side by
|
|
1781
|
+
// side as Excel draws it (#1092, #1099). Plotly's box trace computes
|
|
1782
|
+
// the quartiles (Excel's inclusive / exclusive methods are native),
|
|
1783
|
+
// keeps the whiskers at the 1.5×IQR fences and only hides the
|
|
1784
|
+
// points when outliers are off.
|
|
1761
1785
|
const boxDomainSource = spec.domains?.[0]?.sources?.[0];
|
|
1762
1786
|
const boxCategories = boxDomainSource
|
|
1763
1787
|
? (getDomainValuesFromRange(boxDomainSource, spec.hiddenDimensionStrategy) ?? []).map((v) => (v === null || v === undefined ? "" : `${v}`.trim()))
|
|
@@ -1768,9 +1792,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
|
|
|
1768
1792
|
type: "box",
|
|
1769
1793
|
name: dataLabel,
|
|
1770
1794
|
y: values,
|
|
1771
|
-
|
|
1772
|
-
? { x: values.map((_, i) => boxCategories[i] ?? "") }
|
|
1773
|
-
: {}),
|
|
1795
|
+
x: values.map((_, i) => (grouped ? boxCategories[i] ?? "" : "1")),
|
|
1774
1796
|
...(quartileMethod ? { quartilemethod: quartileMethod } : {}),
|
|
1775
1797
|
boxpoints: showInnerPoints ? "all" : showOutliers ? "outliers" : false,
|
|
1776
1798
|
...(showInnerPoints ? { jitter: 0, pointpos: 0 } : {}),
|
|
@@ -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/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/doughnut.ts","../../utils/echarts-gl-loader.ts","../../utils/echarts-overlays.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-capabilities.ts","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../components/editors/fields/axis-options-fields.tsx","../../components/editors/fields/chart-type-options.tsx","../../components/editors/fields/data-labels-fields.tsx","../../components/editors/fields/primitives.tsx","../../components/editors/fields/series-format-fields.tsx","../../components/editors/fields/series-name-field.tsx","../../components/editors/fields/text-format-fields.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/doughnut.ts","../../utils/echarts-gl-loader.ts","../../utils/echarts-overlays.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/series-name.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-orientation.d.ts","sourceRoot":"","sources":["../../../utils/chart-orientation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"chart-orientation.d.ts","sourceRoot":"","sources":["../../../utils/chart-orientation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAevC,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/B;;;GAGG;AACH,eAAO,MAAM,8BAA8B,GAEvC,WAAW,CACT,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,yBAAyB,GAAG,IAAI,KAC9C,SAAS,OAAO,EAAE,KACtB,oBAaF,CAAC;AAOJ;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,SAAS,KAAG,iBAQxD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,aAAa,iBAAiB,KAC7B,iBAAkE,CAAC;AAEtE;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,KACjC,iBAIY,CAAC;AAEhB;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,4CAIxC;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,KAAG;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CA8D9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,SAAS,EACf,aAAa,iBAAiB,KAC7B,UAAU,GAAG,SAsCf,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,OAIrC,CAAC;AAEjB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,SAAS,EACf,wBAAuB;IAAE,iBAAiB,CAAC,EAAE,oBAAoB,CAAA;CAAO,KACvE,SAAS,GAAG,SAgGd,CAAC"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { isBasicChartSpec } from "./chart-spec-utils";
|
|
2
|
+
/** The single-cell range a series name is linked to (its header cell). */
|
|
3
|
+
const cellRange = (sheetId, rowIndex, columnIndex) => ({
|
|
4
|
+
sheetId,
|
|
5
|
+
startRowIndex: rowIndex,
|
|
6
|
+
endRowIndex: rowIndex,
|
|
7
|
+
startColumnIndex: columnIndex,
|
|
8
|
+
endColumnIndex: columnIndex,
|
|
9
|
+
});
|
|
2
10
|
/**
|
|
3
11
|
* Adapt a range reader (the renderers' `getDomainValuesFromRange`) into
|
|
4
12
|
* the single-cell label getter the orientation helpers take.
|
|
@@ -68,6 +76,7 @@ export const deriveChartSeriesFromRange = ({ range, orientation, getFormattedVal
|
|
|
68
76
|
for (let rowIndex = startRowIndex + 1; rowIndex <= endRowIndex; rowIndex++) {
|
|
69
77
|
series.push({
|
|
70
78
|
dataLabel: label(rowIndex, startColumnIndex),
|
|
79
|
+
dataLabelSource: cellRange(sheetId, rowIndex, startColumnIndex),
|
|
71
80
|
sources: [
|
|
72
81
|
{
|
|
73
82
|
sheetId,
|
|
@@ -92,6 +101,7 @@ export const deriveChartSeriesFromRange = ({ range, orientation, getFormattedVal
|
|
|
92
101
|
for (let columnIndex = startColumnIndex + 1; columnIndex <= endColumnIndex; columnIndex++) {
|
|
93
102
|
series.push({
|
|
94
103
|
dataLabel: label(startRowIndex, columnIndex),
|
|
104
|
+
dataLabelSource: cellRange(sheetId, startRowIndex, columnIndex),
|
|
95
105
|
sources: [
|
|
96
106
|
{
|
|
97
107
|
sheetId,
|
|
@@ -193,6 +203,11 @@ export const switchRowColumn = (spec, { getFormattedValue } = {}) => {
|
|
|
193
203
|
dataLabel: categorySource && getFormattedValue
|
|
194
204
|
? getFormattedValue(categorySource.sheetId, categorySource.startRowIndex + offset, categorySource.startColumnIndex) ?? undefined
|
|
195
205
|
: undefined,
|
|
206
|
+
...(categorySource
|
|
207
|
+
? {
|
|
208
|
+
dataLabelSource: cellRange(categorySource.sheetId, categorySource.startRowIndex + offset, categorySource.startColumnIndex),
|
|
209
|
+
}
|
|
210
|
+
: {}),
|
|
196
211
|
sources: [
|
|
197
212
|
{
|
|
198
213
|
sheetId: block.sheetId,
|
|
@@ -212,6 +227,11 @@ export const switchRowColumn = (spec, { getFormattedValue } = {}) => {
|
|
|
212
227
|
dataLabel: categorySource && getFormattedValue
|
|
213
228
|
? getFormattedValue(categorySource.sheetId, categorySource.startRowIndex, categorySource.startColumnIndex + offset) ?? undefined
|
|
214
229
|
: undefined,
|
|
230
|
+
...(categorySource
|
|
231
|
+
? {
|
|
232
|
+
dataLabelSource: cellRange(categorySource.sheetId, categorySource.startRowIndex, categorySource.startColumnIndex + offset),
|
|
233
|
+
}
|
|
234
|
+
: {}),
|
|
215
235
|
sources: [
|
|
216
236
|
{
|
|
217
237
|
sheetId: block.sheetId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-spec-utils.d.ts","sourceRoot":"","sources":["../../../utils/chart-spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AACpD,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,iBAAiB,6MAe5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,6MAA4C,CAAC;AAE5E,eAAO,MAAM,qBAAqB,6MAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,SAAS,KAAG,aAKvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,cAAuD,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yEAAyE;IACzE,YAAY,CAAC,EACT,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,IAAI,CAAC;CACV,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,qBACiB,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,kBACoB,CAAC;AAwC5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,WAAW,SAAS,KACnB,OAAO,CAAC,SAAS,CAEnB,CAAC;
|
|
1
|
+
{"version":3,"file":"chart-spec-utils.d.ts","sourceRoot":"","sources":["../../../utils/chart-spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AACpD,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,iBAAiB,6MAe5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,6MAA4C,CAAC;AAE5E,eAAO,MAAM,qBAAqB,6MAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,SAAS,KAAG,aAKvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,cAAuD,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yEAAyE;IACzE,YAAY,CAAC,EACT,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,IAAI,CAAC;CACV,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,qBACiB,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,kBACoB,CAAC;AAwC5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,WAAW,SAAS,KACnB,OAAO,CAAC,SAAS,CAEnB,CAAC;AA2HF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,SAAS,EACnB,QAAQ,SAAS,KAChB,MAAM,EAoBR,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,SAAS,EAAE,KAAG,OAO3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,EAAE,EACrB,WAAW,SAAS,EAAE,KACrB,SAAS,EAKX,CAAC;AA+BF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,cAAc,SAAS,EACvB,cAAc,OAAO,CAAC,SAAS,CAAC,KAC/B,SA0FF,CAAC;AAyCF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,UAAU,EAsB9D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,OAAO,KAAG,MAQvD,CAAC"}
|
|
@@ -101,7 +101,25 @@ const BASIC_CHART_TYPE_PROPERTIES = {
|
|
|
101
101
|
],
|
|
102
102
|
doughnut: ["doughnutHoleSize", "explosion"],
|
|
103
103
|
waterfall: ["totalIndices"],
|
|
104
|
-
boxplot: [
|
|
104
|
+
boxplot: [
|
|
105
|
+
"quartileMethod",
|
|
106
|
+
"showOutliers",
|
|
107
|
+
"showMeanMarker",
|
|
108
|
+
"showInnerPoints",
|
|
109
|
+
"showMeanLine",
|
|
110
|
+
],
|
|
111
|
+
histogram: [
|
|
112
|
+
"binCount",
|
|
113
|
+
"binSize",
|
|
114
|
+
"intervalClosed",
|
|
115
|
+
"overflow",
|
|
116
|
+
"underflow",
|
|
117
|
+
"paretoLineColor",
|
|
118
|
+
// A Pareto is a histogram variant (`sourceChartType: "PARETO"`).
|
|
119
|
+
"sourceChartType",
|
|
120
|
+
],
|
|
121
|
+
radar: ["radarStyle"],
|
|
122
|
+
stock: ["stockVariant"],
|
|
105
123
|
// Region map (filled map / choropleth) — the geo scope and the
|
|
106
124
|
// authored-class marker are meaningless on any other chart type.
|
|
107
125
|
regionMap: ["sourceChartType", "geoScope"],
|
|
@@ -127,6 +145,19 @@ const CATEGORY_SPECIFIC_PROPERTIES = {
|
|
|
127
145
|
"quartileMethod",
|
|
128
146
|
"showOutliers",
|
|
129
147
|
"showMeanMarker",
|
|
148
|
+
"showInnerPoints",
|
|
149
|
+
"showMeanLine",
|
|
150
|
+
"binCount",
|
|
151
|
+
"binSize",
|
|
152
|
+
"intervalClosed",
|
|
153
|
+
"overflow",
|
|
154
|
+
"underflow",
|
|
155
|
+
"paretoLineColor",
|
|
156
|
+
"radarStyle",
|
|
157
|
+
"stockVariant",
|
|
158
|
+
"overlap",
|
|
159
|
+
"gapWidth",
|
|
160
|
+
"categoryLevels",
|
|
130
161
|
"geoScope",
|
|
131
162
|
],
|
|
132
163
|
bubble: [
|
|
@@ -134,14 +165,24 @@ const CATEGORY_SPECIFIC_PROPERTIES = {
|
|
|
134
165
|
"bubbleSizes",
|
|
135
166
|
"useFirstRowAsHeaders",
|
|
136
167
|
"scatterStyle",
|
|
168
|
+
"bubbleScale",
|
|
169
|
+
"sizeRepresents",
|
|
170
|
+
],
|
|
171
|
+
hierarchy: [
|
|
172
|
+
"labels",
|
|
173
|
+
"parentLabels",
|
|
174
|
+
"sizeData",
|
|
175
|
+
"useFirstRowAsHeaders",
|
|
176
|
+
"drillDown",
|
|
177
|
+
"parentLabelLayout",
|
|
137
178
|
],
|
|
138
|
-
hierarchy: ["labels", "parentLabels", "sizeData", "useFirstRowAsHeaders"],
|
|
139
179
|
};
|
|
140
180
|
/**
|
|
141
|
-
* `sourceChartType` tokens the picker's presets author (3-D classes
|
|
142
|
-
*
|
|
143
|
-
* resets the variant, so "Clustered Column" after
|
|
144
|
-
*
|
|
181
|
+
* `sourceChartType` tokens the picker's presets author (3-D classes, the
|
|
182
|
+
* of-pie composite and the Pareto histogram). Picking a chart type that
|
|
183
|
+
* carries none of them resets the variant, so "Clustered Column" after
|
|
184
|
+
* "3-D Column" is 2-D again and "Histogram" after "Pareto" is a plain
|
|
185
|
+
* histogram — unlike `REGION_MAP`, which only an import sets.
|
|
145
186
|
*/
|
|
146
187
|
const PICKER_VARIANT_TOKENS = new Set([
|
|
147
188
|
"BAR_3D",
|
|
@@ -151,6 +192,7 @@ const PICKER_VARIANT_TOKENS = new Set([
|
|
|
151
192
|
"SURFACE",
|
|
152
193
|
"SURFACE_3D",
|
|
153
194
|
"OF_PIE",
|
|
195
|
+
"PARETO",
|
|
154
196
|
]);
|
|
155
197
|
/** Of-pie split fields; meaningless once the spec is no longer an of-pie. */
|
|
156
198
|
const OF_PIE_FIELDS = ["ofPieType", "splitType", "splitPos", "secondPieSize"];
|
|
@@ -230,7 +272,9 @@ export const mergeChartSpec = (existingSpec, incomingSpec) => {
|
|
|
230
272
|
delete merged[prop];
|
|
231
273
|
}
|
|
232
274
|
}
|
|
233
|
-
// When switching categories, remove data fields from old category
|
|
275
|
+
// When switching categories, remove data fields from old category. The
|
|
276
|
+
// data itself is carried over below (`carryChartDataAcrossCategories`),
|
|
277
|
+
// as Excel keeps the selected cells when the chart type changes.
|
|
234
278
|
if (isCategoryChange) {
|
|
235
279
|
const oldCategoryDataFields = CATEGORY_DATA_FIELDS[existingCategory];
|
|
236
280
|
for (const field of oldCategoryDataFields) {
|
|
@@ -261,15 +305,58 @@ export const mergeChartSpec = (existingSpec, incomingSpec) => {
|
|
|
261
305
|
const existingWithData = existingSpec;
|
|
262
306
|
const incomingWithData = incomingSpec;
|
|
263
307
|
const targetDataFields = CATEGORY_DATA_FIELDS[targetCategory];
|
|
308
|
+
const carried = isCategoryChange
|
|
309
|
+
? carryChartDataAcrossCategories(existingWithData, existingCategory, targetCategory)
|
|
310
|
+
: undefined;
|
|
264
311
|
for (const field of targetDataFields) {
|
|
265
|
-
const existingData = isCategoryChange
|
|
312
|
+
const existingData = isCategoryChange
|
|
313
|
+
? carried?.[field]
|
|
314
|
+
: existingWithData[field];
|
|
266
315
|
const incomingData = incomingWithData[field];
|
|
267
316
|
if (existingData !== undefined || incomingData !== undefined) {
|
|
268
317
|
merged[field] = mergeChartDataArray(existingData, incomingData);
|
|
269
318
|
}
|
|
270
319
|
}
|
|
320
|
+
// Every data array of the target category exists on the result — the
|
|
321
|
+
// editor maps over them, and a chart type switched from another category
|
|
322
|
+
// (line → bubble) used to leave `series` / `domains` undefined and crash
|
|
323
|
+
// the editor on `series.some` (rowsncolumns/spreadsheet#1101).
|
|
324
|
+
for (const field of REQUIRED_DATA_FIELDS[targetCategory]) {
|
|
325
|
+
if (!Array.isArray(merged[field]))
|
|
326
|
+
merged[field] = [];
|
|
327
|
+
}
|
|
271
328
|
return merged;
|
|
272
329
|
};
|
|
330
|
+
/**
|
|
331
|
+
* The data arrays a category's spec type declares as required (the editor
|
|
332
|
+
* and the renderers map over them without a guard).
|
|
333
|
+
*/
|
|
334
|
+
const REQUIRED_DATA_FIELDS = {
|
|
335
|
+
basic: ["domains", "series"],
|
|
336
|
+
bubble: ["domains", "series", "bubbleLabels"],
|
|
337
|
+
hierarchy: ["labels", "parentLabels", "sizeData"],
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* The selected cells survive a chart type change across categories, as in
|
|
341
|
+
* Excel: a column chart's categories become a scatter's X values and its
|
|
342
|
+
* series the Y values (and back); a treemap's labels become the categories
|
|
343
|
+
* and its sizes the first series (and back, with no parent levels).
|
|
344
|
+
*/
|
|
345
|
+
const carryChartDataAcrossCategories = (existing, from, to) => {
|
|
346
|
+
const clone = (data) => data?.map((entry) => ({ ...entry, sources: [...(entry.sources ?? [])] }));
|
|
347
|
+
const categories = from === "hierarchy" ? clone(existing.labels) : clone(existing.domains);
|
|
348
|
+
const series = from === "hierarchy" ? clone(existing.sizeData) : clone(existing.series);
|
|
349
|
+
if (to === "hierarchy") {
|
|
350
|
+
return {
|
|
351
|
+
labels: categories ?? [],
|
|
352
|
+
parentLabels: [],
|
|
353
|
+
sizeData: series?.length ? [series[0]] : [],
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
// A bubble's labels and sizes cannot be guessed — the user picks them
|
|
357
|
+
// in the editor (the preset's placeholder entry is kept).
|
|
358
|
+
return { domains: categories ?? [], series: series ?? [] };
|
|
359
|
+
};
|
|
273
360
|
/**
|
|
274
361
|
* Extracts all SheetRange objects from a ChartSpec.
|
|
275
362
|
* Useful for subscribing to data changes across all chart data sources.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"echarts-overlays.d.ts","sourceRoot":"","sources":["../../../utils/echarts-overlays.ts"],"names":[],"mappings":"AAkBA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,EACP,KAAK,CAAC;QACJ,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"echarts-overlays.d.ts","sourceRoot":"","sources":["../../../utils/echarts-overlays.ts"],"names":[],"mappings":"AAkBA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,EACP,KAAK,CAAC;QACJ,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC/B,CAAC,GACF,IAAI,CAAC;IACT,SAAS,CAAC,EAAE;QACV,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAC3C,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC1B,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,UAAU,CAAC,EAAE,GAAG,CAAC;KAClB,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,MAAM,GAAG,OAAO,IAAI;IACpD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IAC/C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAC/D,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GAAI,MAAM,GAAG,OAAO,EAAE,gFAQzD,qBAAqB,CAAC,MAAM,CAAC,KAAG,GAAG,EA0IrC,CAAC"}
|