@coinbase/cds-web-visualization 3.4.0-beta.1 → 3.4.0-beta.11
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/CHANGELOG.md +53 -0
- package/dts/chart/CartesianChart.d.ts +38 -2
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/Path.d.ts +27 -7
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +0 -4
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +54 -24
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +33 -6
- package/dts/chart/area/AreaChart.d.ts.map +1 -1
- package/dts/chart/area/DottedArea.d.ts +21 -44
- package/dts/chart/area/DottedArea.d.ts.map +1 -1
- package/dts/chart/area/GradientArea.d.ts +21 -12
- package/dts/chart/area/GradientArea.d.ts.map +1 -1
- package/dts/chart/area/SolidArea.d.ts +16 -1
- package/dts/chart/area/SolidArea.d.ts.map +1 -1
- package/dts/chart/axis/Axis.d.ts +109 -63
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
- package/dts/chart/axis/XAxis.d.ts +1 -1
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts +2 -2
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/axis/index.d.ts +1 -0
- package/dts/chart/axis/index.d.ts.map +1 -1
- package/dts/chart/bar/Bar.d.ts +16 -13
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +17 -8
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +2 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +40 -48
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +1 -0
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
- package/dts/chart/gradient/Gradient.d.ts +35 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -0
- package/dts/chart/gradient/index.d.ts +2 -0
- package/dts/chart/gradient/index.d.ts.map +1 -0
- package/dts/chart/index.d.ts +2 -1
- package/dts/chart/index.d.ts.map +1 -1
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts +15 -3
- package/dts/chart/line/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +87 -28
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +26 -8
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +91 -44
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts +14 -3
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/line/index.d.ts +1 -1
- package/dts/chart/line/index.d.ts.map +1 -1
- package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
- package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
- package/dts/chart/point/Point.d.ts +201 -0
- package/dts/chart/point/Point.d.ts.map +1 -0
- package/dts/chart/point/index.d.ts +3 -0
- package/dts/chart/point/index.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +24 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +10 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/Scrubber.d.ts +207 -66
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +70 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +32 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/index.d.ts +3 -0
- package/dts/chart/scrubber/index.d.ts.map +1 -1
- package/dts/chart/text/ChartText.d.ts +46 -43
- package/dts/chart/text/ChartText.d.ts.map +1 -1
- package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
- package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
- package/dts/chart/text/index.d.ts +1 -1
- package/dts/chart/text/index.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +25 -1
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +27 -7
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +6 -0
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +104 -0
- package/dts/chart/utils/gradient.d.ts.map +1 -0
- package/dts/chart/utils/index.d.ts +4 -0
- package/dts/chart/utils/index.d.ts.map +1 -1
- package/dts/chart/utils/interpolate.d.ts +112 -0
- package/dts/chart/utils/interpolate.d.ts.map +1 -0
- package/dts/chart/utils/path.d.ts +24 -1
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +40 -7
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/scale.d.ts +11 -0
- package/dts/chart/utils/scale.d.ts.map +1 -1
- package/dts/chart/utils/scrubber.d.ts +39 -0
- package/dts/chart/utils/scrubber.d.ts.map +1 -0
- package/dts/chart/utils/transition.d.ts +65 -0
- package/dts/chart/utils/transition.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +140 -85
- package/esm/chart/Path.js +53 -47
- package/esm/chart/PeriodSelector.js +4 -18
- package/esm/chart/area/Area.js +24 -34
- package/esm/chart/area/AreaChart.js +24 -15
- package/esm/chart/area/DottedArea.js +35 -89
- package/esm/chart/area/GradientArea.js +34 -80
- package/esm/chart/area/SolidArea.js +29 -11
- package/esm/chart/axis/Axis.js +4 -39
- package/esm/chart/axis/DefaultAxisTickLabel.js +15 -0
- package/esm/chart/axis/XAxis.js +184 -63
- package/esm/chart/axis/YAxis.js +190 -57
- package/esm/chart/axis/index.js +1 -0
- package/esm/chart/bar/Bar.js +3 -1
- package/esm/chart/bar/BarChart.js +15 -32
- package/esm/chart/bar/BarPlot.js +3 -2
- package/esm/chart/bar/BarStack.js +65 -23
- package/esm/chart/bar/BarStackGroup.js +7 -17
- package/esm/chart/bar/DefaultBar.js +4 -7
- package/esm/chart/bar/DefaultBarStack.js +5 -7
- package/esm/chart/gradient/Gradient.js +104 -0
- package/esm/chart/gradient/index.js +1 -0
- package/esm/chart/index.js +2 -1
- package/esm/chart/line/DefaultReferenceLineLabel.js +81 -0
- package/esm/chart/line/DottedLine.js +38 -17
- package/esm/chart/line/Line.js +96 -70
- package/esm/chart/line/LineChart.js +18 -6
- package/esm/chart/line/ReferenceLine.js +41 -43
- package/esm/chart/line/SolidLine.js +36 -15
- package/esm/chart/line/index.js +1 -1
- package/esm/chart/{line/GradientLine.js → point/DefaultPointLabel.js} +31 -45
- package/esm/chart/point/Point.css +2 -0
- package/esm/chart/{Point.js → point/Point.js} +66 -57
- package/esm/chart/point/index.js +2 -0
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +155 -0
- package/esm/chart/scrubber/{ScrubberBeaconLabel.js → DefaultScrubberBeaconLabel.js} +23 -10
- package/esm/chart/scrubber/DefaultScrubberLabel.js +30 -0
- package/esm/chart/scrubber/Scrubber.js +98 -392
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +166 -0
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +186 -0
- package/esm/chart/scrubber/index.js +3 -1
- package/esm/chart/text/ChartText.js +15 -20
- package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +4 -3
- package/esm/chart/text/index.js +1 -1
- package/esm/chart/utils/axis.js +45 -29
- package/esm/chart/utils/chart.js +29 -3
- package/esm/chart/utils/gradient.js +257 -0
- package/esm/chart/utils/index.js +4 -0
- package/esm/chart/utils/interpolate.js +644 -0
- package/esm/chart/utils/path.js +32 -9
- package/esm/chart/utils/point.js +99 -12
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +132 -0
- package/esm/chart/utils/transition.js +111 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +8 -4
- package/package.json +9 -9
- package/dts/chart/Point.d.ts +0 -153
- package/dts/chart/Point.d.ts.map +0 -1
- package/dts/chart/line/GradientLine.d.ts +0 -42
- package/dts/chart/line/GradientLine.d.ts.map +0 -1
- package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -93
- package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +0 -7
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +0 -1
- package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
- package/esm/chart/Point.css +0 -2
- package/esm/chart/scrubber/ScrubberBeacon.js +0 -195
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { forwardRef, memo, useCallback, useImperativeHandle, useMemo } from 'react';
|
|
2
|
+
import { useRefMap } from '@coinbase/cds-common/hooks/useRefMap';
|
|
3
|
+
import { useCartesianChartContext } from '../ChartProvider';
|
|
4
|
+
import { evaluateGradientAtValue, getGradientConfig, useScrubberContext } from '../utils';
|
|
5
|
+
import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
// Helper component to calculate beacon data for a specific series
|
|
8
|
+
const BeaconWithData = /*#__PURE__*/memo(_ref => {
|
|
9
|
+
let {
|
|
10
|
+
seriesId,
|
|
11
|
+
dataIndex,
|
|
12
|
+
dataX,
|
|
13
|
+
isIdle,
|
|
14
|
+
BeaconComponent,
|
|
15
|
+
idlePulse,
|
|
16
|
+
transitions,
|
|
17
|
+
className,
|
|
18
|
+
style,
|
|
19
|
+
testID,
|
|
20
|
+
beaconRef
|
|
21
|
+
} = _ref;
|
|
22
|
+
const {
|
|
23
|
+
getSeries,
|
|
24
|
+
getSeriesData,
|
|
25
|
+
getXScale,
|
|
26
|
+
getYScale
|
|
27
|
+
} = useCartesianChartContext();
|
|
28
|
+
const series = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
|
|
29
|
+
const sourceData = useMemo(() => getSeriesData(seriesId), [getSeriesData, seriesId]);
|
|
30
|
+
const gradient = series === null || series === void 0 ? void 0 : series.gradient;
|
|
31
|
+
|
|
32
|
+
// Get dataY from series data
|
|
33
|
+
const dataY = useMemo(() => {
|
|
34
|
+
if (sourceData && dataIndex >= 0 && dataIndex < sourceData.length) {
|
|
35
|
+
const dataValue = sourceData[dataIndex];
|
|
36
|
+
if (typeof dataValue === 'number') {
|
|
37
|
+
return dataValue;
|
|
38
|
+
} else if (Array.isArray(dataValue)) {
|
|
39
|
+
const validValues = dataValue.filter(val => val !== null);
|
|
40
|
+
if (validValues.length >= 1) {
|
|
41
|
+
return validValues[validValues.length - 1];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}, [sourceData, dataIndex]);
|
|
47
|
+
|
|
48
|
+
// Evaluate gradient color
|
|
49
|
+
const color = useMemo(() => {
|
|
50
|
+
var _series$color, _series$color2;
|
|
51
|
+
if (dataY === undefined) return (_series$color = series === null || series === void 0 ? void 0 : series.color) !== null && _series$color !== void 0 ? _series$color : 'var(--color-fgPrimary)';
|
|
52
|
+
if (gradient) {
|
|
53
|
+
const xScale = getXScale();
|
|
54
|
+
const yScale = getYScale(series === null || series === void 0 ? void 0 : series.yAxisId);
|
|
55
|
+
if (xScale && yScale) {
|
|
56
|
+
const gradientScale = gradient.axis === 'x' ? xScale : yScale;
|
|
57
|
+
const stops = getGradientConfig(gradient, xScale, yScale);
|
|
58
|
+
if (stops) {
|
|
59
|
+
var _gradient$axis;
|
|
60
|
+
const gradientAxis = (_gradient$axis = gradient.axis) !== null && _gradient$axis !== void 0 ? _gradient$axis : 'y';
|
|
61
|
+
const dataValue = gradientAxis === 'x' ? dataX : dataY;
|
|
62
|
+
const evaluatedColor = evaluateGradientAtValue(stops, dataValue, gradientScale);
|
|
63
|
+
if (evaluatedColor) {
|
|
64
|
+
return evaluatedColor;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return (_series$color2 = series === null || series === void 0 ? void 0 : series.color) !== null && _series$color2 !== void 0 ? _series$color2 : 'var(--color-fgPrimary)';
|
|
70
|
+
}, [gradient, dataX, dataY, series === null || series === void 0 ? void 0 : series.color, series === null || series === void 0 ? void 0 : series.yAxisId, getXScale, getYScale]);
|
|
71
|
+
if (dataY === undefined) return null;
|
|
72
|
+
return /*#__PURE__*/_jsx(BeaconComponent, {
|
|
73
|
+
ref: beaconRef,
|
|
74
|
+
className: className,
|
|
75
|
+
color: color,
|
|
76
|
+
dataX: dataX,
|
|
77
|
+
dataY: dataY,
|
|
78
|
+
idlePulse: idlePulse,
|
|
79
|
+
isIdle: isIdle,
|
|
80
|
+
seriesId: seriesId,
|
|
81
|
+
style: style,
|
|
82
|
+
testID: testID,
|
|
83
|
+
transitions: transitions
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
export const ScrubberBeaconGroup = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
87
|
+
let {
|
|
88
|
+
seriesIds,
|
|
89
|
+
idlePulse,
|
|
90
|
+
transitions,
|
|
91
|
+
BeaconComponent = DefaultScrubberBeacon,
|
|
92
|
+
className,
|
|
93
|
+
style,
|
|
94
|
+
testID
|
|
95
|
+
} = _ref2;
|
|
96
|
+
const ScrubberBeaconRefs = useRefMap();
|
|
97
|
+
const {
|
|
98
|
+
scrubberPosition
|
|
99
|
+
} = useScrubberContext();
|
|
100
|
+
const {
|
|
101
|
+
getXScale,
|
|
102
|
+
getXAxis,
|
|
103
|
+
dataLength,
|
|
104
|
+
series
|
|
105
|
+
} = useCartesianChartContext();
|
|
106
|
+
|
|
107
|
+
// Expose imperative handle with pulse method
|
|
108
|
+
useImperativeHandle(ref, () => ({
|
|
109
|
+
pulse: () => {
|
|
110
|
+
Object.values(ScrubberBeaconRefs.refs).forEach(beaconRef => {
|
|
111
|
+
beaconRef === null || beaconRef === void 0 || beaconRef.pulse();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}));
|
|
115
|
+
const filteredSeries = useMemo(() => {
|
|
116
|
+
var _series$filter;
|
|
117
|
+
return (_series$filter = series === null || series === void 0 ? void 0 : series.filter(s => seriesIds.includes(s.id))) !== null && _series$filter !== void 0 ? _series$filter : [];
|
|
118
|
+
}, [series, seriesIds]);
|
|
119
|
+
const {
|
|
120
|
+
dataX,
|
|
121
|
+
dataIndex
|
|
122
|
+
} = useMemo(() => {
|
|
123
|
+
const xScale = getXScale();
|
|
124
|
+
const xAxis = getXAxis();
|
|
125
|
+
if (!xScale) return {
|
|
126
|
+
dataX: undefined,
|
|
127
|
+
dataIndex: undefined
|
|
128
|
+
};
|
|
129
|
+
const dataIndex = scrubberPosition !== null && scrubberPosition !== void 0 ? scrubberPosition : Math.max(0, dataLength - 1);
|
|
130
|
+
|
|
131
|
+
// Convert index to actual x value if axis has data
|
|
132
|
+
let dataX;
|
|
133
|
+
if (xAxis !== null && xAxis !== void 0 && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex] !== undefined) {
|
|
134
|
+
const dataValue = xAxis.data[dataIndex];
|
|
135
|
+
dataX = typeof dataValue === 'string' ? dataIndex : dataValue;
|
|
136
|
+
} else {
|
|
137
|
+
dataX = dataIndex;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
dataX,
|
|
141
|
+
dataIndex
|
|
142
|
+
};
|
|
143
|
+
}, [getXScale, getXAxis, scrubberPosition, dataLength]);
|
|
144
|
+
const isIdle = scrubberPosition === undefined;
|
|
145
|
+
const createBeaconRef = useCallback(seriesId => {
|
|
146
|
+
return beaconRef => {
|
|
147
|
+
if (beaconRef) {
|
|
148
|
+
ScrubberBeaconRefs.registerRef(seriesId, beaconRef);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}, [ScrubberBeaconRefs]);
|
|
152
|
+
if (dataX === undefined || dataIndex === undefined) return null;
|
|
153
|
+
return filteredSeries.map(s => /*#__PURE__*/_jsx(BeaconWithData, {
|
|
154
|
+
BeaconComponent: BeaconComponent,
|
|
155
|
+
beaconRef: createBeaconRef(s.id),
|
|
156
|
+
className: className,
|
|
157
|
+
dataIndex: dataIndex,
|
|
158
|
+
dataX: dataX,
|
|
159
|
+
idlePulse: idlePulse,
|
|
160
|
+
isIdle: isIdle,
|
|
161
|
+
seriesId: s.id,
|
|
162
|
+
style: style,
|
|
163
|
+
testID: testID ? "".concat(testID !== null && testID !== void 0 ? testID : 'beacon', "-").concat(s.id) : undefined,
|
|
164
|
+
transitions: transitions
|
|
165
|
+
}, s.id));
|
|
166
|
+
}));
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
2
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
3
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
6
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
7
|
+
import { useCartesianChartContext } from '../ChartProvider';
|
|
8
|
+
import { getPointOnScale, useScrubberContext } from '../utils';
|
|
9
|
+
import { calculateLabelYPositions, getLabelPosition } from '../utils/scrubber';
|
|
10
|
+
import { DefaultScrubberBeaconLabel } from './DefaultScrubberBeaconLabel';
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const PositionedLabel = /*#__PURE__*/memo(_ref => {
|
|
13
|
+
let {
|
|
14
|
+
index,
|
|
15
|
+
positions,
|
|
16
|
+
position,
|
|
17
|
+
label,
|
|
18
|
+
color,
|
|
19
|
+
seriesId,
|
|
20
|
+
onDimensionsChange,
|
|
21
|
+
BeaconLabelComponent,
|
|
22
|
+
labelHorizontalOffset,
|
|
23
|
+
labelFont
|
|
24
|
+
} = _ref;
|
|
25
|
+
const pos = positions[index];
|
|
26
|
+
|
|
27
|
+
// Don't render if position is null (invalid data)
|
|
28
|
+
if (!pos) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const x = pos.x;
|
|
32
|
+
const y = pos.y;
|
|
33
|
+
const dx = position === 'right' ? labelHorizontalOffset : -labelHorizontalOffset;
|
|
34
|
+
const horizontalAlignment = position === 'right' ? 'left' : 'right';
|
|
35
|
+
return /*#__PURE__*/_jsx(BeaconLabelComponent, {
|
|
36
|
+
color: color,
|
|
37
|
+
dx: dx,
|
|
38
|
+
font: labelFont,
|
|
39
|
+
horizontalAlignment: horizontalAlignment,
|
|
40
|
+
label: label,
|
|
41
|
+
onDimensionsChange: d => onDimensionsChange(seriesId, d),
|
|
42
|
+
seriesId: seriesId,
|
|
43
|
+
x: x,
|
|
44
|
+
y: y
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
export const ScrubberBeaconLabelGroup = /*#__PURE__*/memo(_ref2 => {
|
|
48
|
+
let {
|
|
49
|
+
labels,
|
|
50
|
+
labelMinGap = 4,
|
|
51
|
+
labelHorizontalOffset = 16,
|
|
52
|
+
labelFont,
|
|
53
|
+
BeaconLabelComponent = DefaultScrubberBeaconLabel
|
|
54
|
+
} = _ref2;
|
|
55
|
+
const {
|
|
56
|
+
getSeries,
|
|
57
|
+
getSeriesData,
|
|
58
|
+
getXScale,
|
|
59
|
+
getYScale,
|
|
60
|
+
getXAxis,
|
|
61
|
+
drawingArea,
|
|
62
|
+
dataLength
|
|
63
|
+
} = useCartesianChartContext();
|
|
64
|
+
const {
|
|
65
|
+
scrubberPosition
|
|
66
|
+
} = useScrubberContext();
|
|
67
|
+
const [labelDimensions, setLabelDimensions] = useState({});
|
|
68
|
+
const handleDimensionsChange = useCallback((seriesId, dimensions) => {
|
|
69
|
+
setLabelDimensions(prev => {
|
|
70
|
+
const existing = prev[seriesId];
|
|
71
|
+
if (existing && existing.width === dimensions.width && existing.height === dimensions.height) {
|
|
72
|
+
return prev;
|
|
73
|
+
}
|
|
74
|
+
return _objectSpread(_objectSpread({}, prev), {}, {
|
|
75
|
+
[seriesId]: dimensions
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}, []);
|
|
79
|
+
const seriesInfo = useMemo(() => {
|
|
80
|
+
return labels.map(label => {
|
|
81
|
+
const series = getSeries(label.seriesId);
|
|
82
|
+
if (!series) return null;
|
|
83
|
+
const sourceData = getSeriesData(label.seriesId);
|
|
84
|
+
const yScale = getYScale(series.yAxisId);
|
|
85
|
+
return {
|
|
86
|
+
seriesId: label.seriesId,
|
|
87
|
+
sourceData,
|
|
88
|
+
yScale
|
|
89
|
+
};
|
|
90
|
+
}).filter(info => info !== null);
|
|
91
|
+
}, [labels, getSeries, getSeriesData, getYScale]);
|
|
92
|
+
const xScale = getXScale();
|
|
93
|
+
const xAxis = getXAxis();
|
|
94
|
+
const dataIndex = useMemo(() => {
|
|
95
|
+
return scrubberPosition !== null && scrubberPosition !== void 0 ? scrubberPosition : Math.max(0, dataLength - 1);
|
|
96
|
+
}, [scrubberPosition, dataLength]);
|
|
97
|
+
const dataX = useMemo(() => {
|
|
98
|
+
if (xAxis !== null && xAxis !== void 0 && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex] !== undefined) {
|
|
99
|
+
const dataValue = xAxis.data[dataIndex];
|
|
100
|
+
return typeof dataValue === 'string' ? dataIndex : dataValue;
|
|
101
|
+
}
|
|
102
|
+
return dataIndex;
|
|
103
|
+
}, [xAxis, dataIndex]);
|
|
104
|
+
const allLabelPositions = useMemo(() => {
|
|
105
|
+
if (!xScale || dataX === undefined) return [];
|
|
106
|
+
const sharedPixelX = getPointOnScale(dataX, xScale);
|
|
107
|
+
const desiredPositions = seriesInfo.map(info => {
|
|
108
|
+
let dataY;
|
|
109
|
+
if (info.yScale) {
|
|
110
|
+
if (info.sourceData && dataIndex !== undefined && dataIndex >= 0 && dataIndex < info.sourceData.length) {
|
|
111
|
+
const dataValue = info.sourceData[dataIndex];
|
|
112
|
+
if (Array.isArray(dataValue)) {
|
|
113
|
+
const validValues = dataValue.filter(val => val !== null);
|
|
114
|
+
if (validValues.length >= 1) {
|
|
115
|
+
dataY = validValues[validValues.length - 1];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (dataY !== undefined && info.yScale) {
|
|
121
|
+
return {
|
|
122
|
+
seriesId: info.seriesId,
|
|
123
|
+
x: sharedPixelX,
|
|
124
|
+
desiredY: getPointOnScale(dataY, info.yScale)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Return null for invalid data
|
|
129
|
+
return null;
|
|
130
|
+
});
|
|
131
|
+
const maxLabelHeight = Math.max(...Object.values(labelDimensions).map(dim => dim.height));
|
|
132
|
+
const maxLabelWidth = Math.max(...Object.values(labelDimensions).map(dim => dim.width));
|
|
133
|
+
|
|
134
|
+
// Only apply collision detection to valid positions
|
|
135
|
+
const validPositions = desiredPositions.filter(pos => pos !== null);
|
|
136
|
+
|
|
137
|
+
// Convert to LabelDimension format expected by utility
|
|
138
|
+
const dimensions = validPositions.map(pos => {
|
|
139
|
+
var _trackedDimensions$wi, _trackedDimensions$he;
|
|
140
|
+
const trackedDimensions = labelDimensions[pos.seriesId];
|
|
141
|
+
return {
|
|
142
|
+
seriesId: pos.seriesId,
|
|
143
|
+
width: (_trackedDimensions$wi = trackedDimensions === null || trackedDimensions === void 0 ? void 0 : trackedDimensions.width) !== null && _trackedDimensions$wi !== void 0 ? _trackedDimensions$wi : maxLabelWidth,
|
|
144
|
+
height: (_trackedDimensions$he = trackedDimensions === null || trackedDimensions === void 0 ? void 0 : trackedDimensions.height) !== null && _trackedDimensions$he !== void 0 ? _trackedDimensions$he : maxLabelHeight,
|
|
145
|
+
preferredX: pos.x,
|
|
146
|
+
preferredY: pos.desiredY
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Calculate Y positions with collision resolution for valid positions only
|
|
151
|
+
const yPositions = calculateLabelYPositions(dimensions, drawingArea, maxLabelHeight, labelMinGap);
|
|
152
|
+
|
|
153
|
+
// Return all positions (including null ones)
|
|
154
|
+
return desiredPositions.map(pos => {
|
|
155
|
+
var _yPositions$get;
|
|
156
|
+
if (!pos) return null;
|
|
157
|
+
return {
|
|
158
|
+
seriesId: pos.seriesId,
|
|
159
|
+
x: pos.x,
|
|
160
|
+
y: (_yPositions$get = yPositions.get(pos.seriesId)) !== null && _yPositions$get !== void 0 ? _yPositions$get : pos.desiredY
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
}, [seriesInfo, dataIndex, dataX, xScale, labelDimensions, drawingArea, labelMinGap]);
|
|
164
|
+
const currentPosition = useMemo(() => {
|
|
165
|
+
if (!xScale || dataX === undefined) return 'right';
|
|
166
|
+
const pixelX = getPointOnScale(dataX, xScale);
|
|
167
|
+
const maxWidth = Math.max(...Object.values(labelDimensions).map(dim => dim.width));
|
|
168
|
+
return getLabelPosition(pixelX, maxWidth, drawingArea, labelHorizontalOffset);
|
|
169
|
+
}, [dataX, xScale, labelDimensions, drawingArea, labelHorizontalOffset]);
|
|
170
|
+
return seriesInfo.map((info, index) => {
|
|
171
|
+
const labelInfo = labels.find(label => label.seriesId === info.seriesId);
|
|
172
|
+
if (!labelInfo) return;
|
|
173
|
+
return /*#__PURE__*/_jsx(PositionedLabel, {
|
|
174
|
+
BeaconLabelComponent: BeaconLabelComponent,
|
|
175
|
+
color: labelInfo.color,
|
|
176
|
+
index: index,
|
|
177
|
+
label: labelInfo.label,
|
|
178
|
+
labelFont: labelFont,
|
|
179
|
+
labelHorizontalOffset: labelHorizontalOffset,
|
|
180
|
+
onDimensionsChange: handleDimensionsChange,
|
|
181
|
+
position: currentPosition,
|
|
182
|
+
positions: allLabelPositions,
|
|
183
|
+
seriesId: info.seriesId
|
|
184
|
+
}, info.seriesId);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -10,6 +10,7 @@ import { Text } from '@coinbase/cds-web/typography';
|
|
|
10
10
|
import { m as motion } from 'framer-motion';
|
|
11
11
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
12
12
|
import { getChartInset } from '../utils';
|
|
13
|
+
import { accessoryFadeTransitionDuration } from '../utils/transition';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The supported content types for ChartText.
|
|
@@ -67,9 +68,9 @@ export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
|
67
68
|
fontFamily,
|
|
68
69
|
fontSize,
|
|
69
70
|
fontWeight,
|
|
70
|
-
|
|
71
|
+
elevated,
|
|
71
72
|
color = 'var(--color-fgMuted)',
|
|
72
|
-
background =
|
|
73
|
+
background = elevated ? 'var(--color-bg)' : 'transparent',
|
|
73
74
|
borderRadius,
|
|
74
75
|
inset: insetInput,
|
|
75
76
|
onDimensionsChange,
|
|
@@ -112,7 +113,7 @@ export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
const parentBounds = bounds !== null && bounds !== void 0 ? bounds : fullChartBounds;
|
|
115
|
-
if (!
|
|
116
|
+
if (!backgroundRectDimensions || !parentBounds || parentBounds.width <= 0 || parentBounds.height <= 0) {
|
|
116
117
|
return {
|
|
117
118
|
x: 0,
|
|
118
119
|
y: 0
|
|
@@ -120,25 +121,21 @@ export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
|
120
121
|
}
|
|
121
122
|
let x = 0;
|
|
122
123
|
let y = 0;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
x = parentBounds.x -
|
|
127
|
-
} else if (textBBox.x + textBBox.width > parentBounds.x + parentBounds.width) {
|
|
128
|
-
x = parentBounds.x + parentBounds.width - (textBBox.x + textBBox.width); // negative = shift left
|
|
124
|
+
if (backgroundRectDimensions.x < parentBounds.x) {
|
|
125
|
+
x = parentBounds.x - backgroundRectDimensions.x; // positive = shift right
|
|
126
|
+
} else if (backgroundRectDimensions.x + backgroundRectDimensions.width > parentBounds.x + parentBounds.width) {
|
|
127
|
+
x = parentBounds.x + parentBounds.width - (backgroundRectDimensions.x + backgroundRectDimensions.width); // negative = shift left
|
|
129
128
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
y = parentBounds.y -
|
|
134
|
-
} else if (textBBox.y + textBBox.height > parentBounds.y + parentBounds.height) {
|
|
135
|
-
y = parentBounds.y + parentBounds.height - (textBBox.y + textBBox.height); // negative = shift up
|
|
129
|
+
if (backgroundRectDimensions.y < parentBounds.y) {
|
|
130
|
+
y = parentBounds.y - backgroundRectDimensions.y; // positive = shift down
|
|
131
|
+
} else if (backgroundRectDimensions.y + backgroundRectDimensions.height > parentBounds.y + parentBounds.height) {
|
|
132
|
+
y = parentBounds.y + parentBounds.height - (backgroundRectDimensions.y + backgroundRectDimensions.height); // negative = shift up
|
|
136
133
|
}
|
|
137
134
|
return {
|
|
138
135
|
x,
|
|
139
136
|
y
|
|
140
137
|
};
|
|
141
|
-
}, [
|
|
138
|
+
}, [backgroundRectDimensions, fullChartBounds, bounds, disableRepositioning]);
|
|
142
139
|
|
|
143
140
|
// Compose the final reported rect including any overflow translation applied
|
|
144
141
|
const reportedRect = useMemo(() => {
|
|
@@ -150,8 +147,6 @@ export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
|
150
147
|
height: backgroundRectDimensions.height
|
|
151
148
|
};
|
|
152
149
|
}, [backgroundRectDimensions, overflowAmount.x, overflowAmount.y]);
|
|
153
|
-
|
|
154
|
-
// send latest calculated dimensions (adjusted for translation) to parent
|
|
155
150
|
useEffect(() => {
|
|
156
151
|
if (onDimensionsChange && reportedRect !== null) {
|
|
157
152
|
onDimensionsChange(reportedRect);
|
|
@@ -196,14 +191,14 @@ export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
|
196
191
|
opacity: isDimensionsReady ? 1 : 0
|
|
197
192
|
},
|
|
198
193
|
transition: animate ? {
|
|
199
|
-
duration:
|
|
194
|
+
duration: accessoryFadeTransitionDuration,
|
|
200
195
|
ease: 'easeOut'
|
|
201
196
|
} : undefined,
|
|
202
197
|
children: [/*#__PURE__*/_jsx(Box, {
|
|
203
198
|
as: "rect",
|
|
204
199
|
className: classNames === null || classNames === void 0 ? void 0 : classNames.backgroundRect,
|
|
205
200
|
fill: background,
|
|
206
|
-
filter:
|
|
201
|
+
filter: elevated ? 'drop-shadow(var(--shadow-elevation1))' : undefined,
|
|
207
202
|
height: backgroundRectDimensions === null || backgroundRectDimensions === void 0 ? void 0 : backgroundRectDimensions.height,
|
|
208
203
|
rx: borderRadius,
|
|
209
204
|
ry: borderRadius,
|
|
@@ -36,12 +36,13 @@ const EPSILON_PX = 0.5;
|
|
|
36
36
|
*
|
|
37
37
|
* The component focuses solely on overlap prevention logic for better separation of concerns.
|
|
38
38
|
*/
|
|
39
|
-
export const
|
|
39
|
+
export const ChartTextGroup = /*#__PURE__*/memo(_ref => {
|
|
40
40
|
let {
|
|
41
41
|
labels,
|
|
42
42
|
minGap = 8,
|
|
43
43
|
prioritizeEndLabels = true,
|
|
44
|
-
chartTextProps
|
|
44
|
+
chartTextProps,
|
|
45
|
+
LabelComponent = ChartText
|
|
45
46
|
} = _ref;
|
|
46
47
|
const [boundingBoxes, setBoundingBoxes] = useState(new Map());
|
|
47
48
|
const _ref2 = chartTextProps !== null && chartTextProps !== void 0 ? chartTextProps : {},
|
|
@@ -213,7 +214,7 @@ export const SmartChartTextGroup = /*#__PURE__*/memo(_ref => {
|
|
|
213
214
|
display: 'none'
|
|
214
215
|
} : {})
|
|
215
216
|
};
|
|
216
|
-
return /*#__PURE__*/_jsx(
|
|
217
|
+
return /*#__PURE__*/_jsx(LabelComponent, _objectSpread(_objectSpread(_objectSpread({
|
|
217
218
|
x: labelData.x,
|
|
218
219
|
y: labelData.y
|
|
219
220
|
}, restChartTextProps), labelData.chartTextProps), {}, {
|
package/esm/chart/text/index.js
CHANGED
package/esm/chart/utils/axis.js
CHANGED
|
@@ -8,10 +8,41 @@ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i
|
|
|
8
8
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
9
9
|
import { useCallback, useMemo, useState } from 'react';
|
|
10
10
|
import { getChartDomain, getChartRange, isValidBounds } from './chart';
|
|
11
|
+
import { getPointOnScale } from './point';
|
|
11
12
|
import { getCategoricalScale, getNumericScale, isCategoricalScale, isNumericScale } from './scale';
|
|
12
13
|
export const defaultAxisId = 'DEFAULT_AXIS_ID';
|
|
13
14
|
export const defaultAxisScaleType = 'linear';
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Position options for band scale axis elements.
|
|
18
|
+
*
|
|
19
|
+
* - `'start'` - At the start of each step (before bar padding)
|
|
20
|
+
* - `'middle'` - At the center of each band
|
|
21
|
+
* - `'end'` - At the end of each step (after bar padding)
|
|
22
|
+
* - `'edges'` - At start of each tick, plus end for the last tick (encloses the chart)
|
|
23
|
+
*
|
|
24
|
+
* @note These properties only apply when using a band scale (`scaleType: 'band'`).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Converts an AxisBandPlacement to the corresponding PointAnchor for use with getPointOnScale.
|
|
29
|
+
*
|
|
30
|
+
* @param placement - The axis placement value
|
|
31
|
+
* @returns The corresponding PointAnchor for scale calculations
|
|
32
|
+
*/
|
|
33
|
+
export const toPointAnchor = placement => {
|
|
34
|
+
switch (placement) {
|
|
35
|
+
case 'edges': // edges uses stepStart for each tick, stepEnd handled separately
|
|
36
|
+
case 'start':
|
|
37
|
+
return 'stepStart';
|
|
38
|
+
case 'end':
|
|
39
|
+
return 'stepEnd';
|
|
40
|
+
case 'middle':
|
|
41
|
+
default:
|
|
42
|
+
return 'middle';
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
15
46
|
/**
|
|
16
47
|
* Axis configuration with computed bounds
|
|
17
48
|
*/
|
|
@@ -458,6 +489,7 @@ const generateEvenlyDistributedTicks = (scale, tickInterval, possibleTickValues,
|
|
|
458
489
|
* // Returns tick positions centered in each selected band
|
|
459
490
|
*/
|
|
460
491
|
export const getAxisTicksData = _ref4 => {
|
|
492
|
+
var _options$anchor;
|
|
461
493
|
let {
|
|
462
494
|
ticks,
|
|
463
495
|
scaleFunction,
|
|
@@ -467,53 +499,37 @@ export const getAxisTicksData = _ref4 => {
|
|
|
467
499
|
tickInterval,
|
|
468
500
|
options
|
|
469
501
|
} = _ref4;
|
|
502
|
+
const anchor = (_options$anchor = options === null || options === void 0 ? void 0 : options.anchor) !== null && _options$anchor !== void 0 ? _options$anchor : 'middle';
|
|
503
|
+
|
|
470
504
|
// Handle band scales
|
|
471
505
|
if (isCategoricalScale(scaleFunction)) {
|
|
506
|
+
const bandScale = scaleFunction;
|
|
507
|
+
|
|
472
508
|
// If explicit ticks are provided as array, use them
|
|
473
509
|
if (Array.isArray(ticks)) {
|
|
474
|
-
return ticks.filter(index => index >= 0 && index < categories.length).map(index => {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (position === undefined) return null;
|
|
479
|
-
return {
|
|
480
|
-
tick: index,
|
|
481
|
-
position: position + ((_bandwidth = (_bandwidth2 = (_ref5 = scaleFunction).bandwidth) === null || _bandwidth2 === void 0 ? void 0 : _bandwidth2.call(_ref5)) !== null && _bandwidth !== void 0 ? _bandwidth : 0) / 2
|
|
482
|
-
};
|
|
483
|
-
}).filter(Boolean);
|
|
510
|
+
return ticks.filter(index => index >= 0 && index < categories.length).map(index => ({
|
|
511
|
+
tick: index,
|
|
512
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
513
|
+
}));
|
|
484
514
|
}
|
|
485
515
|
|
|
486
516
|
// If a tick function is provided, use it to filter
|
|
487
517
|
if (typeof ticks === 'function') {
|
|
488
518
|
return categories.map((category, index) => {
|
|
489
|
-
var _bandwidth3, _bandwidth4, _ref6;
|
|
490
519
|
if (!ticks(index)) return null;
|
|
491
|
-
|
|
492
|
-
// Band scales expect numeric indices, not category strings
|
|
493
|
-
const position = scaleFunction(index);
|
|
494
|
-
if (position === undefined) return null;
|
|
495
520
|
return {
|
|
496
521
|
tick: index,
|
|
497
|
-
position:
|
|
522
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
498
523
|
};
|
|
499
524
|
}).filter(Boolean);
|
|
500
525
|
}
|
|
501
|
-
if (typeof ticks === 'boolean' && !ticks) {
|
|
502
|
-
return [];
|
|
503
|
-
}
|
|
504
526
|
|
|
505
527
|
// For band scales without explicit ticks, show all categories
|
|
506
528
|
// requestedTickCount is ignored for categorical scales - use ticks parameter to control visibility
|
|
507
|
-
return categories.map((
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (position === undefined) return null;
|
|
512
|
-
return {
|
|
513
|
-
tick: index,
|
|
514
|
-
position: position + ((_bandwidth5 = (_bandwidth6 = (_ref7 = scaleFunction).bandwidth) === null || _bandwidth6 === void 0 ? void 0 : _bandwidth6.call(_ref7)) !== null && _bandwidth5 !== void 0 ? _bandwidth5 : 0) / 2
|
|
515
|
-
};
|
|
516
|
-
}).filter(Boolean);
|
|
529
|
+
return categories.map((_, index) => ({
|
|
530
|
+
tick: index,
|
|
531
|
+
position: getPointOnScale(index, bandScale, anchor)
|
|
532
|
+
}));
|
|
517
533
|
}
|
|
518
534
|
|
|
519
535
|
// Handle numeric scales
|
package/esm/chart/utils/chart.js
CHANGED
|
@@ -19,13 +19,13 @@ export const getChartDomain = (series, min, max) => {
|
|
|
19
19
|
return domain;
|
|
20
20
|
}
|
|
21
21
|
if (series.length > 0) {
|
|
22
|
-
const
|
|
22
|
+
const dataLength = Math.max(...series.map(s => {
|
|
23
23
|
var _s$data;
|
|
24
24
|
return ((_s$data = s.data) === null || _s$data === void 0 ? void 0 : _s$data.length) || 0;
|
|
25
25
|
}));
|
|
26
|
-
if (
|
|
26
|
+
if (dataLength > 0) {
|
|
27
27
|
if (domain.min === undefined) domain.min = 0;
|
|
28
|
-
if (domain.max === undefined) domain.max =
|
|
28
|
+
if (domain.max === undefined) domain.max = dataLength - 1;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
return domain;
|
|
@@ -111,6 +111,32 @@ export const getStackedSeriesData = series => {
|
|
|
111
111
|
return stackedDataMap;
|
|
112
112
|
};
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Extracts line data values from series data that may contain tuples.
|
|
116
|
+
* For tuple data [[baseline, value]], extracts the last value.
|
|
117
|
+
* For numeric data [value], returns as-is.
|
|
118
|
+
*
|
|
119
|
+
* @param data - Array of numbers, tuples, or null values
|
|
120
|
+
* @returns Array of numbers or null values
|
|
121
|
+
*/
|
|
122
|
+
export const getLineData = data => {
|
|
123
|
+
if (!data) return [];
|
|
124
|
+
|
|
125
|
+
// Check if this is tuple data by finding first non-null entry
|
|
126
|
+
const firstNonNull = data.find(d => d !== null);
|
|
127
|
+
if (Array.isArray(firstNonNull)) {
|
|
128
|
+
return data.map(d => {
|
|
129
|
+
var _d$at;
|
|
130
|
+
if (d === null) return null;
|
|
131
|
+
if (Array.isArray(d)) return (_d$at = d.at(-1)) !== null && _d$at !== void 0 ? _d$at : null;
|
|
132
|
+
return d;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Already numeric data
|
|
137
|
+
return data;
|
|
138
|
+
};
|
|
139
|
+
|
|
114
140
|
/**
|
|
115
141
|
* Calculates the range of a chart from series data.
|
|
116
142
|
* Range represents the range of y-values from the data.
|