@rowsncolumns/charts 28.1.7 → 28.1.10
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 +525 -419
- package/dist/cjs/basic-chart/helpers.d.ts.map +1 -1
- package/dist/cjs/basic-chart/helpers.js +2 -0
- package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/cjs/plotly/basic-chart/basic-chart.js +351 -192
- package/dist/cjs/plotly/basic-chart/helpers.d.ts.map +1 -1
- package/dist/cjs/plotly/basic-chart/helpers.js +2 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils/bubble.d.ts +34 -1
- package/dist/cjs/utils/bubble.d.ts.map +1 -1
- package/dist/cjs/utils/bubble.js +39 -13
- package/dist/cjs/utils/doughnut.d.ts +19 -0
- package/dist/cjs/utils/doughnut.d.ts.map +1 -0
- package/dist/cjs/utils/doughnut.js +28 -0
- package/dist/cjs/utils/echarts-overlays.d.ts +46 -0
- package/dist/cjs/utils/echarts-overlays.d.ts.map +1 -0
- package/dist/cjs/utils/echarts-overlays.js +134 -0
- package/dist/cjs/utils/hierarchy.d.ts +23 -1
- package/dist/cjs/utils/hierarchy.d.ts.map +1 -1
- package/dist/cjs/utils/hierarchy.js +179 -55
- package/dist/cjs/utils/overrides.d.ts +9 -0
- package/dist/cjs/utils/overrides.d.ts.map +1 -1
- package/dist/cjs/utils/overrides.js +18 -3
- package/dist/cjs/utils/radar.d.ts +31 -5
- package/dist/cjs/utils/radar.d.ts.map +1 -1
- package/dist/cjs/utils/radar.js +67 -27
- package/dist/cjs/utils/trendline.d.ts +7 -1
- package/dist/cjs/utils/trendline.d.ts.map +1 -1
- package/dist/cjs/utils/trendline.js +82 -18
- package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/basic-chart/basic-chart.js +376 -248
- package/dist/esm/basic-chart/helpers.d.ts.map +1 -1
- package/dist/esm/basic-chart/helpers.js +2 -0
- package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
- package/dist/esm/plotly/basic-chart/basic-chart.js +279 -69
- package/dist/esm/plotly/basic-chart/helpers.d.ts.map +1 -1
- package/dist/esm/plotly/basic-chart/helpers.js +2 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/bubble.d.ts +34 -1
- package/dist/esm/utils/bubble.d.ts.map +1 -1
- package/dist/esm/utils/bubble.js +35 -11
- package/dist/esm/utils/doughnut.d.ts +19 -0
- package/dist/esm/utils/doughnut.d.ts.map +1 -0
- package/dist/esm/utils/doughnut.js +21 -0
- package/dist/esm/utils/echarts-overlays.d.ts +46 -0
- package/dist/esm/utils/echarts-overlays.d.ts.map +1 -0
- package/dist/esm/utils/echarts-overlays.js +135 -0
- package/dist/esm/utils/hierarchy.d.ts +23 -1
- package/dist/esm/utils/hierarchy.d.ts.map +1 -1
- package/dist/esm/utils/hierarchy.js +168 -50
- package/dist/esm/utils/overrides.d.ts +9 -0
- package/dist/esm/utils/overrides.d.ts.map +1 -1
- package/dist/esm/utils/overrides.js +16 -2
- package/dist/esm/utils/radar.d.ts +31 -5
- package/dist/esm/utils/radar.d.ts.map +1 -1
- package/dist/esm/utils/radar.js +44 -16
- package/dist/esm/utils/trendline.d.ts +7 -1
- package/dist/esm/utils/trendline.d.ts.map +1 -1
- package/dist/esm/utils/trendline.js +67 -14
- package/package.json +4 -4
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
export declare const toLabelString: (value: unknown) => string;
|
|
2
2
|
export declare const toNumericValue: (value: unknown) => number | null;
|
|
3
|
-
export
|
|
3
|
+
export type BubbleSizeOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Whether a size value sets the bubble's area (Excel's default,
|
|
6
|
+
* diameter ∝ √value) or its width (diameter ∝ value).
|
|
7
|
+
*/
|
|
8
|
+
sizeRepresents?: "area" | "width" | null;
|
|
9
|
+
/** Percent of the default size, 0-300 (Excel's `<c:bubbleScale>`). */
|
|
10
|
+
bubbleScale?: number | null;
|
|
11
|
+
/**
|
|
12
|
+
* The plot area's smaller side in pixels — the largest bubble's
|
|
13
|
+
* diameter is a fraction of it, so bubbles grow with the chart.
|
|
14
|
+
*/
|
|
15
|
+
plotMinSide?: number | null;
|
|
16
|
+
};
|
|
17
|
+
/** The largest bubble's diameter at bubbleScale 100: a quarter of the plot area's smaller side. */
|
|
18
|
+
export declare const BUBBLE_MAX_DIAMETER_FRACTION = 0.25;
|
|
19
|
+
/**
|
|
20
|
+
* Pixel diameter per size value, scaled from ZERO like Excel: the largest
|
|
21
|
+
* absolute value gets the maximum diameter and every other bubble's area
|
|
22
|
+
* (or width) is its share of that value. Scaling from the minimum value
|
|
23
|
+
* instead made the ratio between bubbles depend on the spread of the
|
|
24
|
+
* data (100 and 101 drew as the smallest and largest bubble), and a
|
|
25
|
+
* linear diameter made the perceived area grow with the square of the
|
|
26
|
+
* value (rowsncolumns/spreadsheet#1068).
|
|
27
|
+
*/
|
|
28
|
+
export declare const createBubbleSizeScale: (values: number[], options?: BubbleSizeOptions) => (value: number) => number;
|
|
29
|
+
/** The diameter of the largest bubble for these options. */
|
|
30
|
+
export declare const bubbleMaxDiameter: (options?: BubbleSizeOptions) => number;
|
|
4
31
|
export type BubbleSeriesInput = {
|
|
5
32
|
name?: string | null;
|
|
6
33
|
values: (string | number | boolean | null | undefined)[];
|
|
@@ -23,6 +50,12 @@ export type BubbleSeriesPoint = {
|
|
|
23
50
|
value: [number, number, number];
|
|
24
51
|
name: string;
|
|
25
52
|
xLabel?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The point's row in the source ranges. Points with no Y are skipped,
|
|
55
|
+
* so this is not the point's position in the series — per-point
|
|
56
|
+
* colours (`dataPointColors[].idx`) key on it.
|
|
57
|
+
*/
|
|
58
|
+
index: number;
|
|
26
59
|
};
|
|
27
60
|
export type PreparedBubbleSeries = {
|
|
28
61
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bubble.d.ts","sourceRoot":"","sources":["../../../utils/bubble.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,MACU,CAAC;AAE1D,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,IAYxD,CAAC;AAEF,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"bubble.d.ts","sourceRoot":"","sources":["../../../utils/bubble.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,MACU,CAAC;AAE1D,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,IAYxD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACzC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAMjD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,EAAE,EAChB,UAAS,iBAAsB,MAMvB,OAAO,MAAM,WAQtB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,GAAI,UAAS,iBAAsB,WAUhE,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IACzD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IAC3D;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;;OAKG;IACH,OAAO,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IAC1D,WAAW,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IAC9D;;OAEG;IACH,UAAU,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IAC7D,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAwCF,eAAO,MAAM,uBAAuB,GAAI,+CAKrC,uBAAuB,KAAG,kBAuF5B,CAAC"}
|
package/dist/esm/utils/bubble.js
CHANGED
|
@@ -12,22 +12,45 @@ export const toNumericValue = (value) => {
|
|
|
12
12
|
}
|
|
13
13
|
return null;
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
/** The largest bubble's diameter at bubbleScale 100: a quarter of the plot area's smaller side. */
|
|
16
|
+
export const BUBBLE_MAX_DIAMETER_FRACTION = 0.25;
|
|
17
|
+
/** Fallback plot side when the chart has no measured size yet. */
|
|
18
|
+
const DEFAULT_PLOT_MIN_SIDE = 240;
|
|
19
|
+
/** A positive size never collapses below this diameter. */
|
|
20
|
+
const MIN_BUBBLE_DIAMETER = 2;
|
|
21
|
+
/**
|
|
22
|
+
* Pixel diameter per size value, scaled from ZERO like Excel: the largest
|
|
23
|
+
* absolute value gets the maximum diameter and every other bubble's area
|
|
24
|
+
* (or width) is its share of that value. Scaling from the minimum value
|
|
25
|
+
* instead made the ratio between bubbles depend on the spread of the
|
|
26
|
+
* data (100 and 101 drew as the smallest and largest bubble), and a
|
|
27
|
+
* linear diameter made the perceived area grow with the square of the
|
|
28
|
+
* value (rowsncolumns/spreadsheet#1068).
|
|
29
|
+
*/
|
|
30
|
+
export const createBubbleSizeScale = (values, options = {}) => {
|
|
31
|
+
const maxDiameter = bubbleMaxDiameter(options);
|
|
16
32
|
const valid = values.filter((value) => Number.isFinite(value));
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
const min = Math.min(...valid);
|
|
21
|
-
const max = Math.max(...valid);
|
|
22
|
-
const range = max - min || 1;
|
|
33
|
+
const maxAbs = valid.reduce((max, value) => Math.max(max, Math.abs(value)), 0);
|
|
34
|
+
const byWidth = options.sizeRepresents === "width";
|
|
23
35
|
return (value) => {
|
|
24
|
-
if (!Number.isFinite(value)) {
|
|
25
|
-
return
|
|
36
|
+
if (!Number.isFinite(value) || maxAbs === 0) {
|
|
37
|
+
return maxDiameter;
|
|
26
38
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
39
|
+
const share = Math.abs(value) / maxAbs;
|
|
40
|
+
const diameter = maxDiameter * (byWidth ? share : Math.sqrt(share));
|
|
41
|
+
return share > 0 ? Math.max(MIN_BUBBLE_DIAMETER, diameter) : 0;
|
|
29
42
|
};
|
|
30
43
|
};
|
|
44
|
+
/** The diameter of the largest bubble for these options. */
|
|
45
|
+
export const bubbleMaxDiameter = (options = {}) => {
|
|
46
|
+
const plotMinSide = typeof options.plotMinSide === "number" && options.plotMinSide > 0
|
|
47
|
+
? options.plotMinSide
|
|
48
|
+
: DEFAULT_PLOT_MIN_SIDE;
|
|
49
|
+
const scale = typeof options.bubbleScale === "number" && Number.isFinite(options.bubbleScale)
|
|
50
|
+
? Math.min(300, Math.max(0, options.bubbleScale)) / 100
|
|
51
|
+
: 1;
|
|
52
|
+
return plotMinSide * BUBBLE_MAX_DIAMETER_FRACTION * scale;
|
|
53
|
+
};
|
|
31
54
|
/**
|
|
32
55
|
* Build the X-coordinate index for a series. Numeric values map to
|
|
33
56
|
* their own coordinate; string values become categorical (deduped into
|
|
@@ -107,6 +130,7 @@ export const prepareBubbleSeriesData = ({ xValues, labelValues, sizeValues, seri
|
|
|
107
130
|
value: [coordinate.coordinate, y, sizeValue],
|
|
108
131
|
name: label,
|
|
109
132
|
xLabel: coordinateLabel,
|
|
133
|
+
index: i,
|
|
110
134
|
});
|
|
111
135
|
}
|
|
112
136
|
const name = serie.name && serie.name.trim()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doughnut geometry shared by the renderers (rowsncolumns/spreadsheet#1064,
|
|
3
|
+
* #1065). Every fraction here is of the doughnut's OUTER radius — Excel's
|
|
4
|
+
* `<c:holeSize val="75"/>` is 0.75 of the outer edge, whatever the chart
|
|
5
|
+
* draws that edge at (echarts: 75% of the chart; plotly: the trace domain).
|
|
6
|
+
*/
|
|
7
|
+
/** `doughnutHoleSize` clamped to Excel's 0-90% range; 0.5 when unset. */
|
|
8
|
+
export declare const clampDoughnutHole: (hole: unknown) => number;
|
|
9
|
+
export type DoughnutRing = {
|
|
10
|
+
inner: number;
|
|
11
|
+
outer: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Excel draws a doughnut's series as concentric rings, nested from the hole
|
|
15
|
+
* outwards — series 0 innermost — splitting the band between the hole and
|
|
16
|
+
* the outer edge evenly. One ring (the whole band) for a single series.
|
|
17
|
+
*/
|
|
18
|
+
export declare const doughnutRings: (hole: number, count: number) => DoughnutRing[];
|
|
19
|
+
//# sourceMappingURL=doughnut.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doughnut.d.ts","sourceRoot":"","sources":["../../../utils/doughnut.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,GAAI,MAAM,OAAO,KAAG,MACiB,CAAC;AAEpE,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,YAAY,EAOvE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doughnut geometry shared by the renderers (rowsncolumns/spreadsheet#1064,
|
|
3
|
+
* #1065). Every fraction here is of the doughnut's OUTER radius — Excel's
|
|
4
|
+
* `<c:holeSize val="75"/>` is 0.75 of the outer edge, whatever the chart
|
|
5
|
+
* draws that edge at (echarts: 75% of the chart; plotly: the trace domain).
|
|
6
|
+
*/
|
|
7
|
+
/** `doughnutHoleSize` clamped to Excel's 0-90% range; 0.5 when unset. */
|
|
8
|
+
export const clampDoughnutHole = (hole) => typeof hole === "number" ? Math.max(0, Math.min(0.9, hole)) : 0.5;
|
|
9
|
+
/**
|
|
10
|
+
* Excel draws a doughnut's series as concentric rings, nested from the hole
|
|
11
|
+
* outwards — series 0 innermost — splitting the band between the hole and
|
|
12
|
+
* the outer edge evenly. One ring (the whole band) for a single series.
|
|
13
|
+
*/
|
|
14
|
+
export const doughnutRings = (hole, count) => {
|
|
15
|
+
const n = Math.max(1, Math.floor(count));
|
|
16
|
+
const band = 1 - hole;
|
|
17
|
+
return Array.from({ length: n }, (_, k) => ({
|
|
18
|
+
inner: hole + (band * k) / n,
|
|
19
|
+
outer: hole + (band * (k + 1)) / n,
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
type OverlaySeriesSpec = {
|
|
2
|
+
color?: string | null;
|
|
3
|
+
useSecondaryAxis?: boolean | null;
|
|
4
|
+
trendlines?: Array<{
|
|
5
|
+
type?: any;
|
|
6
|
+
order?: number | null;
|
|
7
|
+
period?: number | null;
|
|
8
|
+
name?: string | null;
|
|
9
|
+
color?: string | null;
|
|
10
|
+
forecastForward?: number | null;
|
|
11
|
+
forecastBackward?: number | null;
|
|
12
|
+
}> | null;
|
|
13
|
+
errorBars?: {
|
|
14
|
+
direction?: "x" | "y" | null;
|
|
15
|
+
barType?: "both" | "plus" | "minus" | null;
|
|
16
|
+
valueType?: any;
|
|
17
|
+
value?: number | null;
|
|
18
|
+
noEndCap?: boolean | null;
|
|
19
|
+
plusRange?: any;
|
|
20
|
+
minusRange?: any;
|
|
21
|
+
} | null;
|
|
22
|
+
};
|
|
23
|
+
export type EchartsOverlayOptions<TRange = unknown> = {
|
|
24
|
+
series: OverlaySeriesSpec;
|
|
25
|
+
/** The series' values (Y on an XY chart), index-aligned with `xValues`. */
|
|
26
|
+
values: (number | null | undefined)[];
|
|
27
|
+
/**
|
|
28
|
+
* Scatter / bubble: the real X coordinate per point. Omitted for a
|
|
29
|
+
* category chart, where the point index is the category coordinate.
|
|
30
|
+
*/
|
|
31
|
+
xValues?: (number | null | undefined)[] | null;
|
|
32
|
+
/** Horizontal bar: the category index is the y coordinate. */
|
|
33
|
+
horizontal?: boolean;
|
|
34
|
+
dataLabel: string;
|
|
35
|
+
/** The data series' own colour — overlays default to it. */
|
|
36
|
+
seriesColor: string;
|
|
37
|
+
/** Reads a custom error bar's plus / minus range. */
|
|
38
|
+
resolveRange: (range: TRange) => unknown[] | null | undefined;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Build the overlay series for one data series. Returns an empty array
|
|
42
|
+
* when the series has neither trendlines nor error bars.
|
|
43
|
+
*/
|
|
44
|
+
export declare const buildEchartsOverlaySeries: <TRange = unknown>({ series, values, xValues, horizontal, dataLabel, seriesColor, resolveRange, }: EchartsOverlayOptions<TRange>) => any[];
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=echarts-overlays.d.ts.map
|
|
@@ -0,0 +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;KAClC,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,EA4HrC,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trendline and error-bar overlay series for the echarts renderer.
|
|
3
|
+
*
|
|
4
|
+
* One data series may carry trendlines (`<c:trendline>`) and error bars
|
|
5
|
+
* (`<c:errBars>`); both are drawn as extra echarts series appended after
|
|
6
|
+
* the data series. The same builder serves every cartesian layout:
|
|
7
|
+
*
|
|
8
|
+
* - category charts (line / column / area): the point index is the
|
|
9
|
+
* category coordinate, values sit on the value axis;
|
|
10
|
+
* - horizontal bars: the same, with the axes swapped — the category
|
|
11
|
+
* index is the y coordinate (rowsncolumns/spreadsheet#1061 drew the
|
|
12
|
+
* overlays on the swapped axes, outside the plot);
|
|
13
|
+
* - scatter / bubble: real (x, y) coordinates per point, and the
|
|
14
|
+
* trendline is a regression of Y on X (#1067).
|
|
15
|
+
*/
|
|
16
|
+
import { computeErrorBars, resolveCustomErrorBarValues } from "./error-bars";
|
|
17
|
+
import { computeTrendline } from "./trendline";
|
|
18
|
+
const ERROR_BAR_CAP_HALF = 5;
|
|
19
|
+
/**
|
|
20
|
+
* Build the overlay series for one data series. Returns an empty array
|
|
21
|
+
* when the series has neither trendlines nor error bars.
|
|
22
|
+
*/
|
|
23
|
+
export const buildEchartsOverlaySeries = ({ series, values, xValues, horizontal = false, dataLabel, seriesColor, resolveRange, }) => {
|
|
24
|
+
if (values.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
const overlays = [];
|
|
27
|
+
const isXY = Array.isArray(xValues);
|
|
28
|
+
const useSecondary = series.useSecondaryAxis ? { yAxisIndex: 1 } : {};
|
|
29
|
+
// Trendlines — one overlay line series per spec.
|
|
30
|
+
for (const tl of series.trendlines ?? []) {
|
|
31
|
+
const result = computeTrendline(values, {
|
|
32
|
+
type: tl.type,
|
|
33
|
+
order: tl.order,
|
|
34
|
+
period: tl.period,
|
|
35
|
+
forecastForward: tl.forecastForward,
|
|
36
|
+
forecastBackward: tl.forecastBackward,
|
|
37
|
+
}, isXY ? xValues : undefined);
|
|
38
|
+
if (!result || result.points.length < 2)
|
|
39
|
+
continue;
|
|
40
|
+
const tlName = tl.name ??
|
|
41
|
+
`${dataLabel ? dataLabel + " " : ""}${tl.type ?? "linear"} trend`;
|
|
42
|
+
overlays.push({
|
|
43
|
+
type: "line",
|
|
44
|
+
name: tlName,
|
|
45
|
+
// On a category chart the index x overlays the category axis even
|
|
46
|
+
// when forecasting extends beyond the data range; a horizontal bar
|
|
47
|
+
// keeps its categories on y.
|
|
48
|
+
data: result.points.map((p) => (horizontal ? [p.y, p.x] : [p.x, p.y])),
|
|
49
|
+
showSymbol: false,
|
|
50
|
+
smooth: tl.type === "poly",
|
|
51
|
+
lineStyle: {
|
|
52
|
+
color: tl.color ?? seriesColor,
|
|
53
|
+
type: "dashed",
|
|
54
|
+
width: 2,
|
|
55
|
+
},
|
|
56
|
+
itemStyle: { color: tl.color ?? seriesColor },
|
|
57
|
+
tooltip: { show: false },
|
|
58
|
+
z: 5,
|
|
59
|
+
...useSecondary,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Error bars — a custom series of whiskers. valueType "custom" reads
|
|
63
|
+
// per-point magnitudes from the spec's plus/minus ranges, resolved
|
|
64
|
+
// through the same extractor the series values use.
|
|
65
|
+
if (series.errorBars) {
|
|
66
|
+
const direction = series.errorBars.direction ?? "y";
|
|
67
|
+
// An X error bar on an XY chart sizes from the X values (a percentage
|
|
68
|
+
// or deviation of X); a category chart has only value-axis bars, so a
|
|
69
|
+
// horizontal bar's whisker runs along x whatever the direction says.
|
|
70
|
+
const alongX = isXY ? direction === "x" : horizontal || direction === "x";
|
|
71
|
+
const magnitudeSource = isXY && alongX ? xValues : values;
|
|
72
|
+
const magnitudes = computeErrorBars(magnitudeSource, resolveCustomErrorBarValues(series.errorBars, resolveRange));
|
|
73
|
+
if (magnitudes) {
|
|
74
|
+
const noEndCap = series.errorBars.noEndCap ?? false;
|
|
75
|
+
const errorData = [];
|
|
76
|
+
for (let i = 0; i < values.length; i++) {
|
|
77
|
+
const v = values[i];
|
|
78
|
+
const y = typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
79
|
+
const x = isXY ? xValues?.[i] : i;
|
|
80
|
+
if (y === null || typeof x !== "number" || !Number.isFinite(x)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// [a, b] is the point's (x, y) data coordinate; a horizontal bar
|
|
84
|
+
// keeps its value on x and its category on y.
|
|
85
|
+
const [a, b] = !isXY && horizontal ? [y, x] : [x, y];
|
|
86
|
+
errorData.push([a, b, magnitudes.plus[i] ?? 0, magnitudes.minus[i] ?? 0]);
|
|
87
|
+
}
|
|
88
|
+
overlays.push({
|
|
89
|
+
type: "custom",
|
|
90
|
+
name: `${dataLabel ? dataLabel + " " : ""}error`,
|
|
91
|
+
data: errorData,
|
|
92
|
+
z: 6,
|
|
93
|
+
tooltip: { show: false },
|
|
94
|
+
...useSecondary,
|
|
95
|
+
renderItem: (_params, api) => {
|
|
96
|
+
const a = api.value(0);
|
|
97
|
+
const b = api.value(1);
|
|
98
|
+
const plus = api.value(2);
|
|
99
|
+
const minus = api.value(3);
|
|
100
|
+
const center = api.coord([a, b]);
|
|
101
|
+
const hi = alongX ? api.coord([a + plus, b]) : api.coord([a, b + plus]);
|
|
102
|
+
const lo = alongX ? api.coord([a - minus, b]) : api.coord([a, b - minus]);
|
|
103
|
+
const stroke = { stroke: seriesColor, lineWidth: 1 };
|
|
104
|
+
const children = [
|
|
105
|
+
{
|
|
106
|
+
type: "line",
|
|
107
|
+
shape: alongX
|
|
108
|
+
? { x1: lo[0], y1: center[1], x2: hi[0], y2: center[1] }
|
|
109
|
+
: { x1: center[0], y1: lo[1], x2: center[0], y2: hi[1] },
|
|
110
|
+
style: stroke,
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
if (!noEndCap) {
|
|
114
|
+
const cap = ERROR_BAR_CAP_HALF;
|
|
115
|
+
children.push({
|
|
116
|
+
type: "line",
|
|
117
|
+
shape: alongX
|
|
118
|
+
? { x1: hi[0], y1: center[1] - cap, x2: hi[0], y2: center[1] + cap }
|
|
119
|
+
: { x1: center[0] - cap, y1: hi[1], x2: center[0] + cap, y2: hi[1] },
|
|
120
|
+
style: stroke,
|
|
121
|
+
}, {
|
|
122
|
+
type: "line",
|
|
123
|
+
shape: alongX
|
|
124
|
+
? { x1: lo[0], y1: center[1] - cap, x2: lo[0], y2: center[1] + cap }
|
|
125
|
+
: { x1: center[0] - cap, y1: lo[1], x2: center[0] + cap, y2: lo[1] },
|
|
126
|
+
style: stroke,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return { type: "group", children };
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return overlays;
|
|
135
|
+
};
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { ChartSpec, SheetRange, TreemapChart } from "@rowsncolumns/spreadsheet";
|
|
2
2
|
type Extractor = (range: SheetRange, hiddenStrategy?: ChartSpec["hiddenDimensionStrategy"]) => (string | number | boolean | null | undefined)[];
|
|
3
3
|
export type HierarchyRow = {
|
|
4
|
+
/** The node this row defines — the innermost filled level cell. */
|
|
4
5
|
label: string;
|
|
6
|
+
/** The immediate parent (the last entry of `path`), null for a root. */
|
|
5
7
|
parent: string | null;
|
|
6
8
|
value: number | null;
|
|
9
|
+
/**
|
|
10
|
+
* The level names above the node, top level first, after Excel's
|
|
11
|
+
* fill-down of blank level cells. Absent on a legacy adjacency row
|
|
12
|
+
* (`parent` alone, naming another row's label).
|
|
13
|
+
*/
|
|
14
|
+
path?: string[];
|
|
7
15
|
};
|
|
8
16
|
export type HierarchyNode = {
|
|
9
17
|
name: string;
|
|
18
|
+
/** Unique within the tree: the node's path joined with "/". */
|
|
10
19
|
id?: string;
|
|
11
20
|
value?: number | null;
|
|
12
21
|
children?: HierarchyNode[];
|
|
@@ -19,10 +28,23 @@ type ExtractOptions = {
|
|
|
19
28
|
export declare const getHierarchyHeaderTitle: (spec: TreemapChart, options: ExtractOptions) => string | undefined;
|
|
20
29
|
export declare const extractHierarchyRows: (spec: TreemapChart, options: ExtractOptions) => HierarchyRow[];
|
|
21
30
|
export declare const buildHierarchyTree: (rows: HierarchyRow[]) => HierarchyNode[];
|
|
22
|
-
export
|
|
31
|
+
export type PlotlyHierarchy = {
|
|
32
|
+
/** Node names, as drawn. */
|
|
23
33
|
labels: string[];
|
|
34
|
+
/** Unique node ids (the path joined with "/"); `parents` reference these. */
|
|
35
|
+
ids: string[];
|
|
36
|
+
/** Parent id per node, "" for a root. */
|
|
24
37
|
parents: string[];
|
|
25
38
|
values: number[];
|
|
39
|
+
/** Depth per node, 0 for a root. */
|
|
40
|
+
depths: number[];
|
|
26
41
|
};
|
|
42
|
+
export declare const toPlotlyHierarchy: (rows: HierarchyRow[]) => PlotlyHierarchy;
|
|
43
|
+
/**
|
|
44
|
+
* One solid colour per top-level category, inherited by every descendant
|
|
45
|
+
* (Excel colours a treemap / sunburst by its first level), in tree order.
|
|
46
|
+
* Returns the colour per node of `toPlotlyHierarchy`'s flat arrays.
|
|
47
|
+
*/
|
|
48
|
+
export declare const hierarchyNodeColors: (hierarchy: Pick<PlotlyHierarchy, "ids" | "parents">, palette: string[]) => string[];
|
|
27
49
|
export {};
|
|
28
50
|
//# sourceMappingURL=hierarchy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../utils/hierarchy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,CACf,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,KAClD,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../utils/hierarchy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,CACf,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,KAClD,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,wBAAwB,EAAE,SAAS,CAAC;IACpC,wBAAwB,EAAE,SAAS,CAAC;IACpC,uBAAuB,CAAC,EAAE,SAAS,CAAC,yBAAyB,CAAC,CAAC;CAChE,CAAC;AA0CF,eAAO,MAAM,uBAAuB,GAClC,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,MAAM,GAAG,SAgBX,CAAC;AAyCF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,YAAY,EAClB,SAAS,cAAc,KACtB,YAAY,EAiFd,CAAC;AAiDF,eAAO,MAAM,kBAAkB,GAAI,MAAM,YAAY,EAAE,KAAG,aAAa,EAmDtE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,4BAA4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oCAAoC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,YAAY,EAAE,KAAG,eAwBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,IAAI,CAAC,eAAe,EAAE,KAAK,GAAG,SAAS,CAAC,EACnD,SAAS,MAAM,EAAE,KAChB,MAAM,EAYR,CAAC"}
|