@coinbase/cds-web-visualization 3.4.0-beta.2 → 3.4.0-beta.21
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 +122 -0
- package/dts/chart/CartesianChart.d.ts +56 -3
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/ChartProvider.d.ts +3 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -1
- package/dts/chart/Path.d.ts +64 -7
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +5 -15
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +50 -25
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +46 -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 +50 -12
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +20 -8
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +3 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +41 -46
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +2 -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 +3 -1
- package/dts/chart/index.d.ts.map +1 -1
- package/dts/chart/legend/DefaultLegendEntry.d.ts +21 -0
- package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts +7 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
- package/dts/chart/legend/Legend.d.ts +169 -0
- package/dts/chart/legend/Legend.d.ts.map +1 -0
- package/dts/chart/legend/index.d.ts +4 -0
- package/dts/chart/legend/index.d.ts.map +1 -0
- 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 +84 -28
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +28 -8
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +99 -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 +217 -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 +41 -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 +303 -70
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +80 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +56 -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/bar.d.ts +34 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +45 -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 +30 -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 +40 -0
- package/dts/chart/utils/scrubber.d.ts.map +1 -0
- package/dts/chart/utils/transition.d.ts +101 -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 +170 -83
- package/esm/chart/ChartProvider.js +2 -2
- package/esm/chart/Path.js +59 -54
- package/esm/chart/PeriodSelector.js +36 -32
- package/esm/chart/area/Area.js +26 -34
- package/esm/chart/area/AreaChart.js +29 -15
- package/esm/chart/area/DottedArea.js +39 -89
- package/esm/chart/area/GradientArea.js +37 -80
- package/esm/chart/area/SolidArea.js +32 -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 +7 -1
- package/esm/chart/bar/BarChart.js +17 -32
- package/esm/chart/bar/BarPlot.js +5 -2
- package/esm/chart/bar/BarStack.js +74 -22
- package/esm/chart/bar/BarStackGroup.js +8 -18
- package/esm/chart/bar/DefaultBar.js +23 -28
- package/esm/chart/bar/DefaultBarStack.js +24 -20
- package/esm/chart/gradient/Gradient.js +104 -0
- package/esm/chart/gradient/index.js +1 -0
- package/esm/chart/index.js +3 -1
- package/esm/chart/legend/DefaultLegendEntry.css +1 -0
- package/esm/chart/legend/DefaultLegendEntry.js +50 -0
- package/esm/chart/legend/DefaultLegendShape.css +5 -0
- package/esm/chart/legend/DefaultLegendShape.js +47 -0
- package/esm/chart/legend/Legend.js +76 -0
- package/esm/chart/legend/index.js +3 -0
- package/esm/chart/line/DefaultReferenceLineLabel.js +81 -0
- package/esm/chart/line/DottedLine.js +41 -17
- package/esm/chart/line/Line.js +87 -75
- package/esm/chart/line/LineChart.js +24 -8
- package/esm/chart/line/ReferenceLine.js +45 -43
- package/esm/chart/line/SolidLine.js +39 -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} +87 -62
- package/esm/chart/point/index.js +2 -0
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +154 -0
- package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +57 -0
- package/esm/chart/scrubber/{ScrubberBeaconLabel.js → DefaultScrubberLabel.js} +15 -18
- package/esm/chart/scrubber/Scrubber.js +101 -392
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +174 -0
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +209 -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 +47 -31
- package/esm/chart/utils/bar.js +48 -0
- package/esm/chart/utils/chart.js +42 -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 +41 -9
- package/esm/chart/utils/point.js +99 -12
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +137 -0
- package/esm/chart/utils/transition.js +133 -0
- package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +8 -4
- package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
- package/package.json +12 -11
- 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
|
@@ -3,89 +3,86 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
3
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
4
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
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 React, { forwardRef, memo,
|
|
7
|
-
import { useRefMap } from '@coinbase/cds-common/hooks/useRefMap';
|
|
6
|
+
import React, { forwardRef, memo, useImperativeHandle, useMemo } from 'react';
|
|
8
7
|
import { m as motion } from 'framer-motion';
|
|
9
|
-
import { axisTickLabelsInitialAnimationVariants } from '../axis';
|
|
10
8
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
11
9
|
import { ReferenceLine } from '../line';
|
|
12
|
-
import { getPointOnScale, useScrubberContext } from '../utils';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
10
|
+
import { defaultAccessoryEnterTransition, getPointOnScale, getTransition, useScrubberContext } from '../utils';
|
|
11
|
+
import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
|
|
12
|
+
import { DefaultScrubberLabel } from './DefaultScrubberLabel';
|
|
13
|
+
import { ScrubberBeaconGroup } from './ScrubberBeaconGroup';
|
|
14
|
+
import { ScrubberBeaconLabelGroup } from './ScrubberBeaconLabelGroup';
|
|
15
15
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
-
const minGap = 2;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Configuration for scrubber functionality across chart components.
|
|
20
|
-
* Provides consistent API with smart defaults and component customization.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
16
|
/**
|
|
24
|
-
* Unified component that manages all scrubber elements (beacons, line, labels)
|
|
25
|
-
* with intelligent collision detection and consistent positioning.
|
|
17
|
+
* Unified component that manages all scrubber elements (beacons, line, labels).
|
|
26
18
|
*/
|
|
27
19
|
export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
|
|
28
20
|
let {
|
|
29
21
|
seriesIds,
|
|
22
|
+
hideBeaconLabels,
|
|
30
23
|
hideLine,
|
|
31
24
|
label,
|
|
25
|
+
accessibilityLabel,
|
|
32
26
|
lineStroke,
|
|
33
|
-
|
|
34
|
-
BeaconComponent,
|
|
27
|
+
BeaconComponent = DefaultScrubberBeacon,
|
|
35
28
|
BeaconLabelComponent,
|
|
36
29
|
LineComponent,
|
|
30
|
+
LabelComponent = DefaultScrubberLabel,
|
|
31
|
+
labelElevated,
|
|
37
32
|
hideOverlay,
|
|
38
33
|
overlayOffset = 2,
|
|
34
|
+
beaconLabelMinGap,
|
|
35
|
+
beaconLabelHorizontalOffset,
|
|
36
|
+
beaconLabelPreferredSide,
|
|
37
|
+
labelFont,
|
|
38
|
+
labelBoundsInset,
|
|
39
|
+
beaconLabelFont,
|
|
39
40
|
testID,
|
|
40
41
|
idlePulse,
|
|
42
|
+
beaconTransitions,
|
|
43
|
+
transitions = beaconTransitions,
|
|
44
|
+
beaconStroke,
|
|
41
45
|
styles,
|
|
42
46
|
classNames
|
|
43
47
|
} = _ref;
|
|
44
|
-
const
|
|
45
|
-
const ScrubberBeaconRefs = useRefMap();
|
|
48
|
+
const beaconGroupRef = React.useRef(null);
|
|
46
49
|
const {
|
|
47
50
|
scrubberPosition
|
|
48
51
|
} = useScrubberContext();
|
|
49
52
|
const {
|
|
50
53
|
getXScale,
|
|
51
|
-
getYScale,
|
|
52
|
-
getSeriesData,
|
|
53
54
|
getXAxis,
|
|
54
55
|
animate,
|
|
55
56
|
series,
|
|
56
|
-
drawingArea
|
|
57
|
+
drawingArea,
|
|
58
|
+
dataLength
|
|
57
59
|
} = useCartesianChartContext();
|
|
58
|
-
const getStackedSeriesData = getSeriesData; // getSeriesData now returns stacked data
|
|
59
|
-
|
|
60
|
-
// Track label dimensions for collision detection
|
|
61
|
-
const [labelDimensions, setLabelDimensions] = useState(new Map());
|
|
62
60
|
|
|
63
61
|
// Expose imperative handle with pulse method
|
|
64
62
|
useImperativeHandle(ref, () => ({
|
|
65
63
|
pulse: () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
beaconRef === null || beaconRef === void 0 || beaconRef.pulse();
|
|
69
|
-
});
|
|
64
|
+
var _beaconGroupRef$curre;
|
|
65
|
+
(_beaconGroupRef$curre = beaconGroupRef.current) === null || _beaconGroupRef$curre === void 0 || _beaconGroupRef$curre.pulse();
|
|
70
66
|
}
|
|
71
67
|
}));
|
|
68
|
+
const filteredSeriesIds = useMemo(() => {
|
|
69
|
+
if (seriesIds === undefined) {
|
|
70
|
+
var _series$map;
|
|
71
|
+
return (_series$map = series === null || series === void 0 ? void 0 : series.map(s => s.id)) !== null && _series$map !== void 0 ? _series$map : [];
|
|
72
|
+
}
|
|
73
|
+
return seriesIds;
|
|
74
|
+
}, [series, seriesIds]);
|
|
72
75
|
const {
|
|
73
76
|
dataX,
|
|
74
77
|
dataIndex
|
|
75
78
|
} = useMemo(() => {
|
|
76
|
-
var _series$reduce;
|
|
77
79
|
const xScale = getXScale();
|
|
78
80
|
const xAxis = getXAxis();
|
|
79
81
|
if (!xScale) return {
|
|
80
82
|
dataX: undefined,
|
|
81
83
|
dataIndex: undefined
|
|
82
84
|
};
|
|
83
|
-
const
|
|
84
|
-
var _seriesData$length;
|
|
85
|
-
const seriesData = getStackedSeriesData(s.id) || getSeriesData(s.id);
|
|
86
|
-
return Math.max(max, (_seriesData$length = seriesData === null || seriesData === void 0 ? void 0 : seriesData.length) !== null && _seriesData$length !== void 0 ? _seriesData$length : 0);
|
|
87
|
-
}, 0)) !== null && _series$reduce !== void 0 ? _series$reduce : 0;
|
|
88
|
-
const dataIndex = scrubberPosition !== null && scrubberPosition !== void 0 ? scrubberPosition : Math.max(0, maxDataLength - 1);
|
|
85
|
+
const dataIndex = scrubberPosition !== null && scrubberPosition !== void 0 ? scrubberPosition : Math.max(0, dataLength - 1);
|
|
89
86
|
|
|
90
87
|
// Convert index to actual x value if axis has data
|
|
91
88
|
let dataX;
|
|
@@ -99,317 +96,52 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
99
96
|
dataX,
|
|
100
97
|
dataIndex
|
|
101
98
|
};
|
|
102
|
-
}, [getXScale, getXAxis,
|
|
103
|
-
const beaconPositions = useMemo(() => {
|
|
104
|
-
var _series$filter$map$fi, _series$filter;
|
|
105
|
-
const xScale = getXScale();
|
|
106
|
-
if (!xScale || dataX === undefined || dataIndex === undefined) return [];
|
|
107
|
-
return (_series$filter$map$fi = series === null || series === void 0 || (_series$filter = series.filter(s => {
|
|
108
|
-
if (seriesIds === undefined) return true;
|
|
109
|
-
return seriesIds.includes(s.id);
|
|
110
|
-
})) === null || _series$filter === void 0 ? void 0 : _series$filter.map(s => {
|
|
111
|
-
const sourceData = getStackedSeriesData(s.id) || getSeriesData(s.id);
|
|
112
|
-
|
|
113
|
-
// Use dataIndex to get the y value from the series data array
|
|
114
|
-
const stuff = sourceData === null || sourceData === void 0 ? void 0 : sourceData[dataIndex];
|
|
115
|
-
let dataY;
|
|
116
|
-
if (Array.isArray(stuff)) {
|
|
117
|
-
dataY = stuff[stuff.length - 1];
|
|
118
|
-
} else if (typeof stuff === 'number') {
|
|
119
|
-
dataY = stuff;
|
|
120
|
-
}
|
|
121
|
-
if (dataY !== undefined) {
|
|
122
|
-
const yScale = getYScale(s.yAxisId);
|
|
123
|
-
if (!yScale) {
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
|
-
const pixelY = getPointOnScale(dataY, yScale);
|
|
127
|
-
const resolvedLabel = typeof s.label === 'function' ? s.label(dataIndex) : s.label;
|
|
128
|
-
return {
|
|
129
|
-
x: dataX,
|
|
130
|
-
y: dataY,
|
|
131
|
-
label: resolvedLabel,
|
|
132
|
-
pixelY,
|
|
133
|
-
targetSeries: s
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
}).filter(beacon => beacon !== undefined)) !== null && _series$filter$map$fi !== void 0 ? _series$filter$map$fi : [];
|
|
137
|
-
}, [getXScale, dataX, dataIndex, series, seriesIds, getStackedSeriesData, getSeriesData, getYScale]);
|
|
138
|
-
const labelVerticalInset = 2;
|
|
139
|
-
const labelHorizontalInset = 4;
|
|
140
|
-
|
|
141
|
-
// Calculate optimal label positioning strategy
|
|
142
|
-
const labelPositioning = useMemo(() => {
|
|
143
|
-
// Get current beacon IDs that are actually being rendered
|
|
144
|
-
const currentBeaconIds = new Set(beaconPositions.map(beacon => beacon === null || beacon === void 0 ? void 0 : beacon.targetSeries.id).filter(Boolean));
|
|
145
|
-
|
|
146
|
-
// Only use dimensions for beacons that are currently being rendered
|
|
147
|
-
const dimensions = Array.from(labelDimensions.values()).filter(dim => currentBeaconIds.has(dim.id));
|
|
148
|
-
if (dimensions.length === 0) return {
|
|
149
|
-
strategy: 'auto',
|
|
150
|
-
adjustments: new Map()
|
|
151
|
-
};
|
|
152
|
-
const adjustments = new Map();
|
|
153
|
-
|
|
154
|
-
// Sort by Y position to handle overlaps systematically
|
|
155
|
-
const sortedDimensions = [...dimensions].sort((a, b) => a.preferredY - b.preferredY);
|
|
99
|
+
}, [getXScale, getXAxis, scrubberPosition, dataLength]);
|
|
156
100
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const bufferPx = 5; // Small buffer to prevent premature switching
|
|
101
|
+
// Compute resolved accessibility label
|
|
102
|
+
const resolvedAccessibilityLabel = useMemo(() => {
|
|
103
|
+
if (dataIndex === undefined) return undefined;
|
|
161
104
|
|
|
162
|
-
//
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
} else {
|
|
166
|
-
// Check if labels would overflow when positioned on the right side
|
|
167
|
-
// Account for anchor radius and padding when calculating right edge
|
|
168
|
-
const wouldOverflow = sortedDimensions.some(dim => {
|
|
169
|
-
const labelRightEdge = dim.preferredX + anchorRadius + labelHorizontalInset + dim.width + bufferPx;
|
|
170
|
-
return labelRightEdge > drawingArea.x + drawingArea.width;
|
|
171
|
-
});
|
|
172
|
-
globalSide = wouldOverflow ? 'left' : 'right';
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Initialize all labels at their preferred positions
|
|
176
|
-
for (const dim of sortedDimensions) {
|
|
177
|
-
adjustments.set(dim.id, {
|
|
178
|
-
x: dim.preferredX,
|
|
179
|
-
y: dim.preferredY,
|
|
180
|
-
side: globalSide
|
|
181
|
-
});
|
|
105
|
+
// If accessibilityLabel is provided, use it
|
|
106
|
+
if (accessibilityLabel) {
|
|
107
|
+
return typeof accessibilityLabel === 'function' ? accessibilityLabel(dataIndex) : accessibilityLabel;
|
|
182
108
|
}
|
|
183
109
|
|
|
184
|
-
//
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
for (let i = 0; i < currentPositions.length - 1; i++) {
|
|
198
|
-
const current = currentPositions[i];
|
|
199
|
-
const next = currentPositions[i + 1];
|
|
200
|
-
const currentAdjustment = adjustments.get(current.id);
|
|
201
|
-
const nextAdjustment = adjustments.get(next.id);
|
|
202
|
-
|
|
203
|
-
// Calculate required separation
|
|
204
|
-
const requiredSeparation = current.height / 2 + next.height / 2 + minGap;
|
|
205
|
-
const currentSeparation = nextAdjustment.y - currentAdjustment.y;
|
|
206
|
-
if (currentSeparation < requiredSeparation) {
|
|
207
|
-
hasCollisions = true;
|
|
208
|
-
const deficit = requiredSeparation - currentSeparation;
|
|
209
|
-
|
|
210
|
-
// Move labels apart - split the adjustment
|
|
211
|
-
const offsetPerLabel = deficit / 2;
|
|
212
|
-
adjustments.set(current.id, _objectSpread(_objectSpread({}, currentAdjustment), {}, {
|
|
213
|
-
y: currentAdjustment.y - offsetPerLabel
|
|
214
|
-
}));
|
|
215
|
-
adjustments.set(next.id, _objectSpread(_objectSpread({}, nextAdjustment), {}, {
|
|
216
|
-
y: nextAdjustment.y + offsetPerLabel
|
|
217
|
-
}));
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (!hasCollisions) {
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// After collision resolution, ensure all labels are within bounds
|
|
226
|
-
const labelIds = Array.from(adjustments.keys());
|
|
227
|
-
|
|
228
|
-
// Group labels that are close together or overlapping
|
|
229
|
-
// This prevents distant labels from being unnecessarily shifted
|
|
230
|
-
const findConnectedGroups = () => {
|
|
231
|
-
const groups = [];
|
|
232
|
-
const visited = new Set();
|
|
233
|
-
for (const id of labelIds) {
|
|
234
|
-
if (visited.has(id)) continue;
|
|
235
|
-
const group = [id];
|
|
236
|
-
visited.add(id);
|
|
237
|
-
const queue = [id];
|
|
238
|
-
while (queue.length > 0) {
|
|
239
|
-
const currentId = queue.shift();
|
|
240
|
-
const currentAdjustment = adjustments.get(currentId);
|
|
241
|
-
const currentDim = sortedDimensions.find(d => d.id === currentId);
|
|
242
|
-
|
|
243
|
-
// Check if this label overlaps or is close to any other unvisited label
|
|
244
|
-
for (const otherId of labelIds) {
|
|
245
|
-
if (visited.has(otherId)) continue;
|
|
246
|
-
const otherAdjustment = adjustments.get(otherId);
|
|
247
|
-
const otherDim = sortedDimensions.find(d => d.id === otherId);
|
|
248
|
-
|
|
249
|
-
// Calculate distance between labels
|
|
250
|
-
const distance = Math.abs(currentAdjustment.y - otherAdjustment.y);
|
|
251
|
-
const minDistance = (currentDim.height + otherDim.height) / 2 + minGap * 2;
|
|
252
|
-
|
|
253
|
-
// Labels are considered connected if they're close enough to potentially overlap
|
|
254
|
-
if (distance <= minDistance) {
|
|
255
|
-
visited.add(otherId);
|
|
256
|
-
group.push(otherId);
|
|
257
|
-
queue.push(otherId);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
groups.push(group);
|
|
262
|
-
}
|
|
263
|
-
return groups;
|
|
264
|
-
};
|
|
265
|
-
const connectedGroups = findConnectedGroups();
|
|
266
|
-
|
|
267
|
-
// Process each connected group independently
|
|
268
|
-
for (const groupIds of connectedGroups) {
|
|
269
|
-
// Check if any labels in this group are outside bounds
|
|
270
|
-
const groupOutOfBounds = groupIds.some(id => {
|
|
271
|
-
const adjustment = adjustments.get(id);
|
|
272
|
-
const dim = sortedDimensions.find(d => d.id === id);
|
|
273
|
-
const labelTop = adjustment.y - dim.height / 2;
|
|
274
|
-
const labelBottom = adjustment.y + dim.height / 2;
|
|
275
|
-
return labelTop < drawingArea.y || labelBottom > drawingArea.y + drawingArea.height;
|
|
276
|
-
});
|
|
277
|
-
if (groupOutOfBounds) {
|
|
278
|
-
// Get labels in this group sorted by their preferred Y position
|
|
279
|
-
const groupLabels = groupIds.map(id => ({
|
|
280
|
-
id,
|
|
281
|
-
dim: sortedDimensions.find(d => d.id === id),
|
|
282
|
-
preferredY: sortedDimensions.find(d => d.id === id).preferredY,
|
|
283
|
-
currentY: adjustments.get(id).y
|
|
284
|
-
})).sort((a, b) => a.preferredY - b.preferredY);
|
|
285
|
-
|
|
286
|
-
// Calculate total height needed for this group
|
|
287
|
-
const totalLabelHeight = groupLabels.reduce((sum, label) => sum + label.dim.height, 0);
|
|
288
|
-
const totalGaps = (groupLabels.length - 1) * minGap;
|
|
289
|
-
const totalNeeded = totalLabelHeight + totalGaps;
|
|
290
|
-
if (totalNeeded > drawingArea.height) {
|
|
291
|
-
// Not enough space - use compressed equal spacing as fallback
|
|
292
|
-
const compressedGap = Math.max(2, (drawingArea.height - totalLabelHeight) / Math.max(1, groupLabels.length - 1));
|
|
293
|
-
let currentY = drawingArea.y + groupLabels[0].dim.height / 2;
|
|
294
|
-
for (const label of groupLabels) {
|
|
295
|
-
adjustments.set(label.id, _objectSpread(_objectSpread({}, adjustments.get(label.id)), {}, {
|
|
296
|
-
y: currentY
|
|
297
|
-
}));
|
|
298
|
-
currentY += label.dim.height + compressedGap;
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
// Enough space - use minimal displacement algorithm for this group
|
|
302
|
-
const finalPositions = [...groupLabels];
|
|
303
|
-
|
|
304
|
-
// Ensure minimum spacing between adjacent labels in this group
|
|
305
|
-
for (let i = 1; i < finalPositions.length; i++) {
|
|
306
|
-
const prev = finalPositions[i - 1];
|
|
307
|
-
const current = finalPositions[i];
|
|
308
|
-
|
|
309
|
-
// Calculate minimum Y position for current label
|
|
310
|
-
const minCurrentY = prev.preferredY + prev.dim.height / 2 + minGap + current.dim.height / 2;
|
|
311
|
-
if (current.preferredY < minCurrentY) {
|
|
312
|
-
// Need to push this label down
|
|
313
|
-
current.preferredY = minCurrentY;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Check if this specific group fits within bounds, if not shift only this group
|
|
318
|
-
const groupTop = finalPositions[0].preferredY - finalPositions[0].dim.height / 2;
|
|
319
|
-
const groupBottom = finalPositions[finalPositions.length - 1].preferredY + finalPositions[finalPositions.length - 1].dim.height / 2;
|
|
320
|
-
let shiftAmount = 0;
|
|
321
|
-
if (groupTop < drawingArea.y) {
|
|
322
|
-
// Group is too high, shift down
|
|
323
|
-
shiftAmount = drawingArea.y - groupTop;
|
|
324
|
-
} else if (groupBottom > drawingArea.y + drawingArea.height) {
|
|
325
|
-
// Group is too low, shift up
|
|
326
|
-
shiftAmount = drawingArea.y + drawingArea.height - groupBottom;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Apply final positions with shift only to this group
|
|
330
|
-
for (const label of finalPositions) {
|
|
331
|
-
const finalY = label.preferredY + shiftAmount;
|
|
332
|
-
|
|
333
|
-
// Final bounds check for individual labels
|
|
334
|
-
const clampedY = Math.max(drawingArea.y + label.dim.height / 2, Math.min(drawingArea.y + drawingArea.height - label.dim.height / 2, finalY));
|
|
335
|
-
adjustments.set(label.id, _objectSpread(_objectSpread({}, adjustments.get(label.id)), {}, {
|
|
336
|
-
y: clampedY
|
|
337
|
-
}));
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return {
|
|
343
|
-
strategy: globalSide,
|
|
344
|
-
adjustments
|
|
345
|
-
};
|
|
346
|
-
}, [beaconPositions, labelDimensions, drawingArea]);
|
|
347
|
-
|
|
348
|
-
// Callback for labels to register their dimensions
|
|
349
|
-
const registerLabelDimensions = useCallback((id, width, height, x, y) => {
|
|
350
|
-
setLabelDimensions(prev => {
|
|
351
|
-
const existing = prev.get(id);
|
|
352
|
-
const newDimensions = {
|
|
353
|
-
id,
|
|
354
|
-
width,
|
|
355
|
-
height,
|
|
356
|
-
preferredX: x,
|
|
357
|
-
preferredY: y
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
// Only update if dimensions actually changed
|
|
361
|
-
if (existing && existing.width === width && existing.height === height && existing.preferredX === x && existing.preferredY === y) {
|
|
362
|
-
return prev;
|
|
363
|
-
}
|
|
364
|
-
const next = new Map(prev);
|
|
365
|
-
next.set(id, newDimensions);
|
|
366
|
-
return next;
|
|
367
|
-
});
|
|
368
|
-
}, []);
|
|
369
|
-
|
|
370
|
-
// Callback to create ref handlers for scrubber beacons
|
|
371
|
-
const createScrubberBeaconRef = useCallback(seriesId => {
|
|
372
|
-
return beaconRef => {
|
|
373
|
-
if (beaconRef) {
|
|
374
|
-
ScrubberBeaconRefs.registerRef(seriesId, beaconRef);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
}, [ScrubberBeaconRefs]);
|
|
378
|
-
|
|
379
|
-
// synchronize label positioning state when the position of any scrubber beacons change
|
|
380
|
-
useEffect(() => {
|
|
381
|
-
const currentBeaconIds = new Set(beaconPositions.map(beacon => beacon === null || beacon === void 0 ? void 0 : beacon.targetSeries.id).filter(Boolean));
|
|
382
|
-
setLabelDimensions(prev => {
|
|
383
|
-
const next = new Map();
|
|
384
|
-
for (const [id, dimensions] of prev) {
|
|
385
|
-
if (currentBeaconIds.has(id)) {
|
|
386
|
-
next.set(id, dimensions);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return next;
|
|
390
|
-
});
|
|
391
|
-
}, [beaconPositions]);
|
|
110
|
+
// Otherwise, if label resolves to a string, use that
|
|
111
|
+
const resolvedLabel = typeof label === 'function' ? label(dataIndex) : label;
|
|
112
|
+
return typeof resolvedLabel === 'string' ? resolvedLabel : undefined;
|
|
113
|
+
}, [accessibilityLabel, label, dataIndex]);
|
|
114
|
+
const beaconLabels = useMemo(() => {
|
|
115
|
+
var _series$filter$filter;
|
|
116
|
+
return (_series$filter$filter = series === null || series === void 0 ? void 0 : series.filter(s => filteredSeriesIds.includes(s.id)).filter(s => s.label !== undefined && s.label.length > 0).map(s => ({
|
|
117
|
+
seriesId: s.id,
|
|
118
|
+
label: s.label,
|
|
119
|
+
color: s.color
|
|
120
|
+
}))) !== null && _series$filter$filter !== void 0 ? _series$filter$filter : [];
|
|
121
|
+
}, [series, filteredSeriesIds]);
|
|
122
|
+
const groupEnterTransition = useMemo(() => getTransition(transitions === null || transitions === void 0 ? void 0 : transitions.enter, animate, defaultAccessoryEnterTransition), [transitions === null || transitions === void 0 ? void 0 : transitions.enter, animate]);
|
|
392
123
|
|
|
393
124
|
// Check if we have at least the default X scale
|
|
394
125
|
const defaultXScale = getXScale();
|
|
395
126
|
if (!defaultXScale) return null;
|
|
396
|
-
|
|
397
|
-
// Use custom components if provided
|
|
398
|
-
const ScrubberLineComponent = LineComponent !== null && LineComponent !== void 0 ? LineComponent : ReferenceLine;
|
|
399
|
-
const ScrubberBeaconComponent = BeaconComponent !== null && BeaconComponent !== void 0 ? BeaconComponent : ScrubberBeacon;
|
|
400
|
-
const ScrubberBeaconLabelComponent = BeaconLabelComponent !== null && BeaconLabelComponent !== void 0 ? BeaconLabelComponent : ScrubberBeaconLabel;
|
|
401
127
|
const pixelX = dataX !== undefined && defaultXScale ? getPointOnScale(dataX, defaultXScale) : undefined;
|
|
402
128
|
return /*#__PURE__*/_jsxs(motion.g, _objectSpread(_objectSpread({
|
|
403
|
-
|
|
129
|
+
"aria-atomic": "true",
|
|
130
|
+
"aria-label": resolvedAccessibilityLabel,
|
|
131
|
+
"aria-live": "polite",
|
|
404
132
|
"data-component": "scrubber-group",
|
|
405
|
-
"data-testid": testID
|
|
133
|
+
"data-testid": testID,
|
|
134
|
+
role: "status"
|
|
406
135
|
}, animate ? {
|
|
407
|
-
animate:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
136
|
+
animate: {
|
|
137
|
+
opacity: 1,
|
|
138
|
+
transition: groupEnterTransition
|
|
139
|
+
},
|
|
140
|
+
initial: {
|
|
141
|
+
opacity: 0
|
|
142
|
+
}
|
|
411
143
|
} : {}), {}, {
|
|
412
|
-
children: [!hideOverlay &&
|
|
144
|
+
children: [!hideOverlay && scrubberPosition !== undefined && pixelX !== undefined && /*#__PURE__*/_jsx("rect", {
|
|
413
145
|
className: classNames === null || classNames === void 0 ? void 0 : classNames.overlay,
|
|
414
146
|
fill: "var(--color-bg)",
|
|
415
147
|
height: drawingArea.height + overlayOffset * 2,
|
|
@@ -418,66 +150,43 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
418
150
|
width: drawingArea.x + drawingArea.width - pixelX + overlayOffset,
|
|
419
151
|
x: pixelX,
|
|
420
152
|
y: drawingArea.y - overlayOffset
|
|
421
|
-
}), !hideLine && scrubberPosition !== undefined && dataX !== undefined && /*#__PURE__*/_jsx(
|
|
422
|
-
|
|
153
|
+
}), !hideLine && scrubberPosition !== undefined && dataX !== undefined && /*#__PURE__*/_jsx(ReferenceLine, {
|
|
154
|
+
LabelComponent: LabelComponent,
|
|
155
|
+
LineComponent: LineComponent,
|
|
156
|
+
classNames: {
|
|
157
|
+
label: classNames === null || classNames === void 0 ? void 0 : classNames.label,
|
|
158
|
+
line: classNames === null || classNames === void 0 ? void 0 : classNames.line
|
|
159
|
+
},
|
|
423
160
|
dataX: dataX,
|
|
424
161
|
label: typeof label === 'function' ? label(dataIndex) : label,
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
dy: -0.5 * drawingArea.y
|
|
429
|
-
}, labelProps),
|
|
162
|
+
labelBoundsInset: labelBoundsInset,
|
|
163
|
+
labelElevated: labelElevated,
|
|
164
|
+
labelFont: labelFont,
|
|
430
165
|
stroke: lineStroke,
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
bounds: drawingArea,
|
|
456
|
-
className: classNames === null || classNames === void 0 ? void 0 : classNames.beaconLabel,
|
|
457
|
-
color: dotStroke,
|
|
458
|
-
dx: finalSide === 'right' ? 16 : -16,
|
|
459
|
-
horizontalAlignment: finalSide === 'right' ? 'left' : 'right',
|
|
460
|
-
inset: {
|
|
461
|
-
left: labelHorizontalInset,
|
|
462
|
-
right: labelHorizontalInset,
|
|
463
|
-
top: labelVerticalInset,
|
|
464
|
-
bottom: labelVerticalInset
|
|
465
|
-
},
|
|
466
|
-
onDimensionsChange: _ref2 => {
|
|
467
|
-
let {
|
|
468
|
-
width,
|
|
469
|
-
height
|
|
470
|
-
} = _ref2;
|
|
471
|
-
return registerLabelDimensions(beacon.targetSeries.id, width, height, pixelX, beacon.pixelY);
|
|
472
|
-
},
|
|
473
|
-
style: styles === null || styles === void 0 ? void 0 : styles.beaconLabel,
|
|
474
|
-
testID: testID ? "".concat(testID, "-").concat(beacon.targetSeries.id, "-label") : undefined,
|
|
475
|
-
x: finalAnchorX,
|
|
476
|
-
y: finalAnchorY,
|
|
477
|
-
children: beacon.label
|
|
478
|
-
});
|
|
479
|
-
})()]
|
|
480
|
-
}, beacon.targetSeries.id);
|
|
166
|
+
styles: {
|
|
167
|
+
label: styles === null || styles === void 0 ? void 0 : styles.label,
|
|
168
|
+
line: styles === null || styles === void 0 ? void 0 : styles.line
|
|
169
|
+
}
|
|
170
|
+
}), /*#__PURE__*/_jsx(ScrubberBeaconGroup, {
|
|
171
|
+
ref: beaconGroupRef,
|
|
172
|
+
BeaconComponent: BeaconComponent,
|
|
173
|
+
className: classNames === null || classNames === void 0 ? void 0 : classNames.beacon,
|
|
174
|
+
idlePulse: idlePulse,
|
|
175
|
+
seriesIds: filteredSeriesIds,
|
|
176
|
+
stroke: beaconStroke,
|
|
177
|
+
style: styles === null || styles === void 0 ? void 0 : styles.beacon,
|
|
178
|
+
testID: testID,
|
|
179
|
+
transitions: transitions
|
|
180
|
+
}), !hideBeaconLabels && beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
|
|
181
|
+
BeaconLabelComponent: BeaconLabelComponent,
|
|
182
|
+
className: classNames === null || classNames === void 0 ? void 0 : classNames.beaconLabel,
|
|
183
|
+
labelFont: beaconLabelFont,
|
|
184
|
+
labelHorizontalOffset: beaconLabelHorizontalOffset,
|
|
185
|
+
labelMinGap: beaconLabelMinGap,
|
|
186
|
+
labelPreferredSide: beaconLabelPreferredSide,
|
|
187
|
+
labels: beaconLabels,
|
|
188
|
+
style: styles === null || styles === void 0 ? void 0 : styles.beaconLabel,
|
|
189
|
+
transitions: transitions
|
|
481
190
|
})]
|
|
482
191
|
}));
|
|
483
192
|
}));
|