@mui/x-charts-premium 9.0.4 → 9.1.0
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/BarChartPremium/BarChartPremium.js +2 -1183
- package/BarChartPremium/BarChartPremium.mjs +2 -1183
- package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.js +2 -0
- package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.mjs +2 -0
- package/CHANGELOG.md +133 -0
- package/CandlestickChart/CandlestickChart.d.mts +2 -2
- package/CandlestickChart/CandlestickChart.d.ts +2 -2
- package/CandlestickChart/CandlestickChart.js +2 -1183
- package/CandlestickChart/CandlestickChart.mjs +2 -1183
- package/CandlestickChart/CandlestickWebGLProgram.d.mts +6 -11
- package/CandlestickChart/CandlestickWebGLProgram.d.ts +6 -11
- package/CandlestickChart/CandlestickWebGLProgram.js +136 -121
- package/CandlestickChart/CandlestickWebGLProgram.mjs +137 -122
- package/CandlestickChart/useCandlestickPlotData.d.mts +2 -2
- package/CandlestickChart/useCandlestickPlotData.d.ts +2 -2
- package/CandlestickChart/useCandlestickPlotData.js +121 -61
- package/CandlestickChart/useCandlestickPlotData.mjs +122 -61
- package/ChartsAxisHighlightValue/index.d.mts +1 -0
- package/ChartsAxisHighlightValue/index.d.ts +1 -0
- package/ChartsAxisHighlightValue/index.js +16 -0
- package/ChartsAxisHighlightValue/index.mjs +2 -0
- package/ChartsDataProviderPremium/ChartsDataProviderPremium.js +2 -2
- package/ChartsDataProviderPremium/ChartsDataProviderPremium.mjs +2 -2
- package/ChartsRadialAxisHighlight/index.d.mts +1 -0
- package/ChartsRadialAxisHighlight/index.d.ts +1 -0
- package/ChartsRadialAxisHighlight/index.js +16 -0
- package/ChartsRadialAxisHighlight/index.mjs +2 -0
- package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.js +2 -2
- package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.mjs +2 -2
- package/HeatmapPremium/HeatmapPremium.js +2 -155
- package/HeatmapPremium/HeatmapPremium.mjs +2 -155
- package/HeatmapPremium/webgl/HeatmapWebGLPlot.js +19 -112
- package/HeatmapPremium/webgl/HeatmapWebGLPlot.mjs +19 -111
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.mts +24 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.ts +24 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.js +132 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.mjs +125 -0
- package/HeatmapPremium/webgl/useHeatmapPlotData.d.mts +3 -3
- package/HeatmapPremium/webgl/useHeatmapPlotData.d.ts +3 -3
- package/HeatmapPremium/webgl/useHeatmapPlotData.js +78 -26
- package/HeatmapPremium/webgl/useHeatmapPlotData.mjs +80 -26
- package/LICENSE +3 -1
- package/RadialBarChart/RadialBarChart.d.mts +60 -0
- package/RadialBarChart/RadialBarChart.d.ts +60 -0
- package/RadialBarChart/RadialBarChart.js +298 -0
- package/RadialBarChart/RadialBarChart.mjs +292 -0
- package/RadialBarChart/RadialBarChart.plugins.d.mts +4 -0
- package/RadialBarChart/RadialBarChart.plugins.d.ts +4 -0
- package/RadialBarChart/RadialBarChart.plugins.js +9 -0
- package/RadialBarChart/RadialBarChart.plugins.mjs +3 -0
- package/RadialBarChart/RadialBarElement.d.mts +16 -0
- package/RadialBarChart/RadialBarElement.d.ts +16 -0
- package/RadialBarChart/RadialBarElement.js +54 -0
- package/RadialBarChart/RadialBarElement.mjs +48 -0
- package/RadialBarChart/RadialBarPlot.d.mts +21 -0
- package/RadialBarChart/RadialBarPlot.d.ts +21 -0
- package/RadialBarChart/RadialBarPlot.js +85 -0
- package/RadialBarChart/RadialBarPlot.mjs +79 -0
- package/RadialBarChart/index.d.mts +3 -0
- package/RadialBarChart/index.d.ts +3 -0
- package/RadialBarChart/index.js +39 -0
- package/RadialBarChart/index.mjs +3 -0
- package/RadialBarChart/radialBarClasses.d.mts +15 -0
- package/RadialBarChart/radialBarClasses.d.ts +15 -0
- package/RadialBarChart/radialBarClasses.js +26 -0
- package/RadialBarChart/radialBarClasses.mjs +18 -0
- package/RadialBarChart/seriesConfig/seriesProcessor.js +4 -0
- package/RadialBarChart/seriesConfig/seriesProcessor.mjs +4 -0
- package/RadialBarChart/useRadialBarChartProps.d.mts +28 -0
- package/RadialBarChart/useRadialBarChartProps.d.ts +28 -0
- package/RadialBarChart/useRadialBarChartProps.js +100 -0
- package/RadialBarChart/useRadialBarChartProps.mjs +93 -0
- package/RadialBarChart/useRadialBarPlotData.d.mts +23 -0
- package/RadialBarChart/useRadialBarPlotData.d.ts +23 -0
- package/RadialBarChart/useRadialBarPlotData.js +94 -0
- package/RadialBarChart/useRadialBarPlotData.mjs +87 -0
- package/RadialLineChart/RadialArea.js +13 -1
- package/RadialLineChart/RadialArea.mjs +13 -1
- package/RadialLineChart/RadialLine.js +13 -1
- package/RadialLineChart/RadialLine.mjs +13 -1
- package/RadialLineChart/RadialLineChart.d.mts +11 -3
- package/RadialLineChart/RadialLineChart.d.ts +11 -3
- package/RadialLineChart/RadialLineChart.js +24 -673
- package/RadialLineChart/RadialLineChart.mjs +24 -673
- package/RadialLineChart/RadialLineHighlightElement.d.mts +15 -0
- package/RadialLineChart/RadialLineHighlightElement.d.ts +15 -0
- package/RadialLineChart/RadialLineHighlightElement.js +46 -0
- package/RadialLineChart/RadialLineHighlightElement.mjs +39 -0
- package/RadialLineChart/RadialLineHighlightPlot.d.mts +23 -0
- package/RadialLineChart/RadialLineHighlightPlot.d.ts +23 -0
- package/RadialLineChart/RadialLineHighlightPlot.js +92 -0
- package/RadialLineChart/RadialLineHighlightPlot.mjs +86 -0
- package/RadialLineChart/RadialMarkPlot.js +17 -2
- package/RadialLineChart/RadialMarkPlot.mjs +17 -2
- package/RadialLineChart/index.d.mts +3 -1
- package/RadialLineChart/index.d.ts +3 -1
- package/RadialLineChart/index.js +22 -0
- package/RadialLineChart/index.mjs +3 -1
- package/RadialLineChart/radialLineClasses.d.mts +3 -1
- package/RadialLineChart/radialLineClasses.d.ts +3 -1
- package/RadialLineChart/radialLineClasses.js +2 -1
- package/RadialLineChart/radialLineClasses.mjs +2 -1
- package/RadialLineChart/seriesConfig/getItemAtPosition.d.mts +6 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.d.ts +6 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.js +353 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.mjs +348 -0
- package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.js +2 -1
- package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.mjs +2 -1
- package/RadialLineChart/seriesConfig/index.js +2 -1
- package/RadialLineChart/seriesConfig/index.mjs +2 -1
- package/RadialLineChart/seriesConfig/seriesProcessor.js +4 -0
- package/RadialLineChart/seriesConfig/seriesProcessor.mjs +4 -0
- package/RadialLineChart/useRadialLineChartProps.d.mts +2 -0
- package/RadialLineChart/useRadialLineChartProps.d.ts +2 -0
- package/RadialLineChart/useRadialLineChartProps.js +16 -8
- package/RadialLineChart/useRadialLineChartProps.mjs +16 -8
- package/RadialLineChart/useRadialLinePlotData.js +2 -1
- package/RadialLineChart/useRadialLinePlotData.mjs +3 -2
- package/ScatterChartPremium/ScatterChartPremium.d.mts +25 -0
- package/ScatterChartPremium/ScatterChartPremium.d.ts +25 -0
- package/ScatterChartPremium/ScatterChartPremium.js +507 -0
- package/ScatterChartPremium/ScatterChartPremium.mjs +501 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.d.mts +3 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.d.ts +3 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.js +8 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.mjs +2 -0
- package/ScatterChartPremium/ScatterPlotPremium.d.mts +14 -0
- package/ScatterChartPremium/ScatterPlotPremium.d.ts +14 -0
- package/ScatterChartPremium/ScatterPlotPremium.js +28 -0
- package/ScatterChartPremium/ScatterPlotPremium.mjs +21 -0
- package/ScatterChartPremium/index.d.mts +3 -0
- package/ScatterChartPremium/index.d.ts +3 -0
- package/ScatterChartPremium/index.js +26 -0
- package/ScatterChartPremium/index.mjs +3 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.mts +4 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.ts +4 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.js +70 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.mjs +65 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.mts +18 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.ts +18 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.js +129 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.mjs +122 -0
- package/ScatterChartPremium/webgl/shaders.d.mts +2 -0
- package/ScatterChartPremium/webgl/shaders.d.ts +2 -0
- package/ScatterChartPremium/webgl/shaders.js +57 -0
- package/ScatterChartPremium/webgl/shaders.mjs +51 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.mts +7 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.ts +7 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.js +140 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.mjs +134 -0
- package/index.d.mts +3 -1
- package/index.d.ts +3 -1
- package/index.js +25 -1
- package/index.mjs +4 -2
- package/internals/index.d.mts +1 -0
- package/internals/index.d.ts +1 -0
- package/internals/index.js +13 -0
- package/internals/index.mjs +1 -0
- package/models/seriesType/radialLine.d.mts +7 -1
- package/models/seriesType/radialLine.d.ts +7 -1
- package/package.json +184 -114
- package/plugins/selectors/useChartCandlestickPosition.selectors.d.mts +1 -1
- package/plugins/selectors/useChartCandlestickPosition.selectors.d.ts +1 -1
- package/utils/webgl/parseColor.d.mts +2 -1
- package/utils/webgl/parseColor.d.ts +2 -1
- package/utils/webgl/parseColor.js +8 -7
- package/utils/webgl/parseColor.mjs +8 -7
- package/utils/webgl/utils.d.mts +13 -0
- package/utils/webgl/utils.d.ts +13 -0
- package/utils/webgl/utils.js +29 -0
- package/utils/webgl/utils.mjs +27 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = getItemAtPosition;
|
|
7
|
+
var _hooks = require("@mui/x-charts/hooks");
|
|
8
|
+
var _internals = require("@mui/x-charts/internals");
|
|
9
|
+
/**
|
|
10
|
+
* For a continuous rotation axis, find the two data indices that bracket the pointer's angle position.
|
|
11
|
+
* For ordinal axes, returns the single matching index (left === right).
|
|
12
|
+
* Returns null if the pointer is outside the data range.
|
|
13
|
+
*/
|
|
14
|
+
function getBracketIndices(rotationAxis, angle) {
|
|
15
|
+
const {
|
|
16
|
+
scale,
|
|
17
|
+
data: axisData,
|
|
18
|
+
isFullCircle
|
|
19
|
+
} = rotationAxis;
|
|
20
|
+
if (!axisData || axisData.length === 0) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if ((0, _internals.isOrdinalScale)(scale)) {
|
|
24
|
+
const index = (0, _internals.getPolarAxisIndex)(rotationAxis, angle);
|
|
25
|
+
if (index === -1) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const valueAngle = (0, _hooks.getValueToPositionMapper)(scale)(axisData[index]);
|
|
29
|
+
const gapAngle = (0, _internals.clampAngleRad)(angle - valueAngle);
|
|
30
|
+
if (gapAngle > Math.PI) {
|
|
31
|
+
// We are between the previous and current rotation point.
|
|
32
|
+
if (index === 0 && !isFullCircle) {
|
|
33
|
+
return null; // Only relevant for band scales.
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
left: index > 0 ? index - 1 : axisData.length - 1,
|
|
37
|
+
right: index
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// We are between the next and current rotation point.
|
|
42
|
+
if (index === rotationAxis.data.length - 1 && !isFullCircle) {
|
|
43
|
+
return null; // Only relevant for band scales.
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
left: index,
|
|
47
|
+
right: (index + 1) % axisData.length
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// For continuous axes, find the two adjacent data points surrounding pointX.
|
|
52
|
+
const rotationValue = scale.invert(scale.range()[0] + (0, _internals.clampAngleRad)(angle - scale.range()[0]));
|
|
53
|
+
const rotationAsNumber = rotationValue instanceof Date ? rotationValue.getTime() : rotationValue;
|
|
54
|
+
|
|
55
|
+
// Find the rightmost index where data[i] <= rotationValue.
|
|
56
|
+
let leftIndex = -1;
|
|
57
|
+
for (let i = 0; i < axisData.length; i += 1) {
|
|
58
|
+
if ((0, _internals.getAsNumber)(axisData[i]) <= rotationAsNumber) {
|
|
59
|
+
leftIndex = i;
|
|
60
|
+
} else {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (leftIndex === -1) {
|
|
65
|
+
// Pointer is before the first data point.
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (leftIndex === axisData.length - 1) {
|
|
69
|
+
// Pointer is at or after the last data point — check if it's close enough.
|
|
70
|
+
return {
|
|
71
|
+
left: leftIndex,
|
|
72
|
+
right: leftIndex
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
left: leftIndex,
|
|
77
|
+
right: leftIndex + 1
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Compute the r0 (baseline) for a given data point,
|
|
83
|
+
* replicating the logic from useAreaPlotData.
|
|
84
|
+
*/
|
|
85
|
+
function getBaselineRadius(baseline, radiusScale, stackedY0) {
|
|
86
|
+
if (typeof baseline === 'number') {
|
|
87
|
+
return radiusScale(baseline);
|
|
88
|
+
}
|
|
89
|
+
if (baseline === 'max') {
|
|
90
|
+
return radiusScale.range()[1];
|
|
91
|
+
}
|
|
92
|
+
if (baseline === 'min') {
|
|
93
|
+
return radiusScale.range()[0];
|
|
94
|
+
}
|
|
95
|
+
// Default: use the stacked baseline value.
|
|
96
|
+
const value = radiusScale(stackedY0);
|
|
97
|
+
if (Number.isNaN(value)) {
|
|
98
|
+
return radiusScale.range()[0];
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Collect the pixel-coordinate points for a contiguous (non-null) segment
|
|
104
|
+
// of a series that contains the bracket indices.
|
|
105
|
+
//
|
|
106
|
+
// When connectNulls is true, all non-null points are returned.
|
|
107
|
+
// When connectNulls is false, only the contiguous run containing [left, right] is returned.
|
|
108
|
+
function collectCurvePoints(data, getPosition, left, right, connectNulls) {
|
|
109
|
+
const points = [];
|
|
110
|
+
if (connectNulls) {
|
|
111
|
+
// All non-null points form one continuous curve.
|
|
112
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
113
|
+
if (data[i] != null) {
|
|
114
|
+
const position = getPosition(i);
|
|
115
|
+
if (position != null && !Number.isNaN(position.y) && !Number.isNaN(position.x)) {
|
|
116
|
+
points.push(position);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return points;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Find the contiguous non-null run containing [left, right].
|
|
124
|
+
let start = left;
|
|
125
|
+
while (start > 0 && data[start - 1] != null) {
|
|
126
|
+
start -= 1;
|
|
127
|
+
}
|
|
128
|
+
let end = right;
|
|
129
|
+
while (end < data.length - 1 && data[end + 1] != null) {
|
|
130
|
+
end += 1;
|
|
131
|
+
}
|
|
132
|
+
for (let i = start; i <= end; i += 1) {
|
|
133
|
+
const position = getPosition(i);
|
|
134
|
+
if (position != null && !Number.isNaN(position.y) && !Number.isNaN(position.x)) {
|
|
135
|
+
points.push(position);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return points;
|
|
139
|
+
}
|
|
140
|
+
function isInRadiusRange(pointerRadius, radiusAxis) {
|
|
141
|
+
const range = radiusAxis.scale.range();
|
|
142
|
+
const minRadius = Math.min(range[0], range[1]);
|
|
143
|
+
const maxRadius = Math.max(range[0], range[1]);
|
|
144
|
+
return pointerRadius >= minRadius && pointerRadius <= maxRadius;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The maximum pixel distance (in the radial direction) from a line at which
|
|
148
|
+
* the line is still considered "close enough" to be selected over an area.
|
|
149
|
+
*/
|
|
150
|
+
const LINE_PROXIMITY_THRESHOLD = 15;
|
|
151
|
+
function getItemAtPosition(state, point) {
|
|
152
|
+
const {
|
|
153
|
+
axis: rotationAxes,
|
|
154
|
+
axisIds: rotationAxisIds
|
|
155
|
+
} = (0, _internals.selectorChartRotationAxis)(state);
|
|
156
|
+
const {
|
|
157
|
+
axis: radiusAxes,
|
|
158
|
+
axisIds: radiusAxisIds
|
|
159
|
+
} = (0, _internals.selectorChartRadiusAxis)(state);
|
|
160
|
+
const center = (0, _internals.selectorChartPolarCenter)(state);
|
|
161
|
+
const series = (0, _internals.selectorAllSeriesOfType)(state, 'radialLine');
|
|
162
|
+
if (!series || series.seriesOrder.length === 0) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
const defaultRotationAxisId = rotationAxisIds[0];
|
|
166
|
+
const defaultRadiusAxisId = radiusAxisIds[0];
|
|
167
|
+
|
|
168
|
+
// Convert the pointer position to polar coordinates.
|
|
169
|
+
const dx = point.x - center.cx;
|
|
170
|
+
const dy = center.cy - point.y;
|
|
171
|
+
const pointerRadius = Math.sqrt(dx * dx + dy * dy);
|
|
172
|
+
const pointerAngle = Math.atan2(dx, dy);
|
|
173
|
+
|
|
174
|
+
// Step 1: Find the closest line across all series (measured as radial distance).
|
|
175
|
+
let closestDistance = Infinity;
|
|
176
|
+
let closestItem;
|
|
177
|
+
for (const seriesId of series.seriesOrder) {
|
|
178
|
+
const seriesItem = series.series[seriesId];
|
|
179
|
+
if (seriesItem.hidden) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const rotationAxisId = seriesItem.rotationAxisId ?? defaultRotationAxisId;
|
|
183
|
+
const radiusAxisId = seriesItem.radiusAxisId ?? defaultRadiusAxisId;
|
|
184
|
+
const rotationAxis = rotationAxes[rotationAxisId];
|
|
185
|
+
const radiusAxis = radiusAxes[radiusAxisId];
|
|
186
|
+
if (!isInRadiusRange(pointerRadius, radiusAxis)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const bracket = getBracketIndices(rotationAxis, pointerAngle);
|
|
190
|
+
if (!bracket) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const {
|
|
194
|
+
left,
|
|
195
|
+
right
|
|
196
|
+
} = bracket;
|
|
197
|
+
const {
|
|
198
|
+
visibleStackedData,
|
|
199
|
+
data,
|
|
200
|
+
connectNulls,
|
|
201
|
+
curve
|
|
202
|
+
} = seriesItem;
|
|
203
|
+
const dataIndex = (0, _internals.getPolarAxisIndex)(rotationAxis, pointerAngle);
|
|
204
|
+
if (dataIndex === -1) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Evaluate the actual curve at the pointer's angle for precise distance.
|
|
209
|
+
const rotationData = rotationAxis.data;
|
|
210
|
+
if (!rotationData) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const rotationPosition = (0, _hooks.getValueToPositionMapper)(rotationAxis.scale);
|
|
214
|
+
const getRotation = idx => rotationPosition(rotationData[idx]);
|
|
215
|
+
const getRadius = idx => {
|
|
216
|
+
const stacked = visibleStackedData[idx];
|
|
217
|
+
return stacked ? radiusAxis.scale(stacked[1]) : null;
|
|
218
|
+
};
|
|
219
|
+
const getPosition = idx => {
|
|
220
|
+
const rotation = getRotation(idx);
|
|
221
|
+
const radius = getRadius(idx);
|
|
222
|
+
if (rotation == null || radius == null) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
radius,
|
|
227
|
+
rotation,
|
|
228
|
+
// coordinate centered at (0, 0)
|
|
229
|
+
x: radius * Math.sin(rotation),
|
|
230
|
+
y: -radius * Math.cos(rotation)
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
const curvePoints = collectCurvePoints(data, getPosition, left, right, connectNulls);
|
|
234
|
+
if (curvePoints.length < 2) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const closestPoint = (0, _internals.evaluateCurveAtAngle)(curvePoints, pointerAngle, curve);
|
|
238
|
+
if (closestPoint == null) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const distance = Math.abs(pointerRadius - Math.sqrt(closestPoint.x ** 2 + closestPoint.y ** 2));
|
|
242
|
+
if (distance < closestDistance) {
|
|
243
|
+
closestDistance = distance;
|
|
244
|
+
closestItem = {
|
|
245
|
+
type: 'radialLine',
|
|
246
|
+
seriesId,
|
|
247
|
+
dataIndex
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Step 2: If the closest line is within the proximity threshold, pick it.
|
|
253
|
+
if (closestItem && closestDistance <= LINE_PROXIMITY_THRESHOLD && !series.series[closestItem.seriesId].area) {
|
|
254
|
+
return closestItem;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Step 3: Check area series — iterate stacking groups in reverse
|
|
258
|
+
// so that topmost (last rendered) area is checked first.
|
|
259
|
+
const {
|
|
260
|
+
stackingGroups
|
|
261
|
+
} = series;
|
|
262
|
+
for (let g = stackingGroups.length - 1; g >= 0; g -= 1) {
|
|
263
|
+
const groupIds = stackingGroups[g].ids;
|
|
264
|
+
for (let i = 0; i <= groupIds.length - 1; i += 1) {
|
|
265
|
+
const seriesId = groupIds[i];
|
|
266
|
+
const seriesItem = series.series[seriesId];
|
|
267
|
+
if (seriesItem.hidden || !seriesItem.area) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const rotationAxisId = seriesItem.rotationAxisId ?? defaultRotationAxisId;
|
|
271
|
+
const radiusAxisId = seriesItem.radiusAxisId ?? defaultRadiusAxisId;
|
|
272
|
+
const rotationAxis = rotationAxes[rotationAxisId];
|
|
273
|
+
const radiusAxis = radiusAxes[radiusAxisId];
|
|
274
|
+
if (!rotationAxis || !radiusAxis) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const bracket = getBracketIndices(rotationAxis, pointerAngle);
|
|
278
|
+
if (!bracket) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const {
|
|
282
|
+
left,
|
|
283
|
+
right
|
|
284
|
+
} = bracket;
|
|
285
|
+
const {
|
|
286
|
+
visibleStackedData,
|
|
287
|
+
data,
|
|
288
|
+
connectNulls,
|
|
289
|
+
baseline,
|
|
290
|
+
curve
|
|
291
|
+
} = seriesItem;
|
|
292
|
+
|
|
293
|
+
// Check for null gaps at bracket points.
|
|
294
|
+
if ((data[left] == null || data[right] == null) && !connectNulls) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const rotationScale = rotationAxis.scale;
|
|
298
|
+
const radiusScale = radiusAxis.scale;
|
|
299
|
+
const rotationPosition = (0, _hooks.getValueToPositionMapper)(rotationScale);
|
|
300
|
+
const rotationData = rotationAxis.data;
|
|
301
|
+
if (!rotationData) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const getRotation = idx => rotationPosition(rotationData[idx]);
|
|
305
|
+
const getRadius = (idx, position) => {
|
|
306
|
+
const stacked = visibleStackedData[idx];
|
|
307
|
+
return position === 0 ? getBaselineRadius(baseline, radiusScale, stacked ? stacked[0] : 0) : radiusScale(stacked[1]);
|
|
308
|
+
};
|
|
309
|
+
const getPosition = position => idx => {
|
|
310
|
+
const rotation = getRotation(idx);
|
|
311
|
+
const radius = getRadius(idx, position);
|
|
312
|
+
if (rotation == null || radius == null) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
radius,
|
|
317
|
+
rotation,
|
|
318
|
+
// coordinate centered at (0, 0)
|
|
319
|
+
x: radius * Math.sin(rotation),
|
|
320
|
+
y: -radius * Math.cos(rotation)
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// Build pixel-coordinate points for the top and bottom curves,
|
|
325
|
+
// then evaluate them at the pointer's x using the actual d3 curve.
|
|
326
|
+
const topPoints = collectCurvePoints(data, getPosition(1), left, right, connectNulls);
|
|
327
|
+
const bottomPoints = collectCurvePoints(data, getPosition(0), left, right, connectNulls);
|
|
328
|
+
if (topPoints.length < 2 || bottomPoints.length < 2) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const outerPoint = (0, _internals.evaluateCurveAtAngle)(topPoints, pointerAngle, curve);
|
|
332
|
+
const innerPoint = (0, _internals.evaluateCurveAtAngle)(bottomPoints, pointerAngle, curve);
|
|
333
|
+
if (outerPoint == null || innerPoint == null) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const innerRadius = Math.sqrt(innerPoint.x ** 2 + innerPoint.y ** 2);
|
|
337
|
+
const outerRadius = Math.sqrt(outerPoint.x ** 2 + outerPoint.y ** 2);
|
|
338
|
+
const radiusMin = Math.min(innerRadius, outerRadius);
|
|
339
|
+
const radiusMax = Math.max(innerRadius, outerRadius);
|
|
340
|
+
if (pointerRadius >= radiusMin && pointerRadius <= radiusMax) {
|
|
341
|
+
const dataIndex = (0, _internals.getPolarAxisIndex)(rotationAxis, pointerAngle);
|
|
342
|
+
return {
|
|
343
|
+
type: 'radialLine',
|
|
344
|
+
seriesId,
|
|
345
|
+
dataIndex: dataIndex === -1 ? left : dataIndex
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Step 4: No area matched — return the closest line regardless of threshold.
|
|
352
|
+
return closestItem;
|
|
353
|
+
}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { getValueToPositionMapper } from '@mui/x-charts/hooks';
|
|
2
|
+
import { selectorAllSeriesOfType, selectorChartPolarCenter, selectorChartRadiusAxis, selectorChartRotationAxis, getPolarAxisIndex, isOrdinalScale } from '@mui/x-charts/internals';
|
|
3
|
+
import { evaluateCurveAtAngle, clampAngleRad, getAsNumber } from '@mui/x-charts/internals';
|
|
4
|
+
/**
|
|
5
|
+
* For a continuous rotation axis, find the two data indices that bracket the pointer's angle position.
|
|
6
|
+
* For ordinal axes, returns the single matching index (left === right).
|
|
7
|
+
* Returns null if the pointer is outside the data range.
|
|
8
|
+
*/
|
|
9
|
+
function getBracketIndices(rotationAxis, angle) {
|
|
10
|
+
const {
|
|
11
|
+
scale,
|
|
12
|
+
data: axisData,
|
|
13
|
+
isFullCircle
|
|
14
|
+
} = rotationAxis;
|
|
15
|
+
if (!axisData || axisData.length === 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
if (isOrdinalScale(scale)) {
|
|
19
|
+
const index = getPolarAxisIndex(rotationAxis, angle);
|
|
20
|
+
if (index === -1) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const valueAngle = getValueToPositionMapper(scale)(axisData[index]);
|
|
24
|
+
const gapAngle = clampAngleRad(angle - valueAngle);
|
|
25
|
+
if (gapAngle > Math.PI) {
|
|
26
|
+
// We are between the previous and current rotation point.
|
|
27
|
+
if (index === 0 && !isFullCircle) {
|
|
28
|
+
return null; // Only relevant for band scales.
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
left: index > 0 ? index - 1 : axisData.length - 1,
|
|
32
|
+
right: index
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// We are between the next and current rotation point.
|
|
37
|
+
if (index === rotationAxis.data.length - 1 && !isFullCircle) {
|
|
38
|
+
return null; // Only relevant for band scales.
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
left: index,
|
|
42
|
+
right: (index + 1) % axisData.length
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// For continuous axes, find the two adjacent data points surrounding pointX.
|
|
47
|
+
const rotationValue = scale.invert(scale.range()[0] + clampAngleRad(angle - scale.range()[0]));
|
|
48
|
+
const rotationAsNumber = rotationValue instanceof Date ? rotationValue.getTime() : rotationValue;
|
|
49
|
+
|
|
50
|
+
// Find the rightmost index where data[i] <= rotationValue.
|
|
51
|
+
let leftIndex = -1;
|
|
52
|
+
for (let i = 0; i < axisData.length; i += 1) {
|
|
53
|
+
if (getAsNumber(axisData[i]) <= rotationAsNumber) {
|
|
54
|
+
leftIndex = i;
|
|
55
|
+
} else {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (leftIndex === -1) {
|
|
60
|
+
// Pointer is before the first data point.
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (leftIndex === axisData.length - 1) {
|
|
64
|
+
// Pointer is at or after the last data point — check if it's close enough.
|
|
65
|
+
return {
|
|
66
|
+
left: leftIndex,
|
|
67
|
+
right: leftIndex
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
left: leftIndex,
|
|
72
|
+
right: leftIndex + 1
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Compute the r0 (baseline) for a given data point,
|
|
78
|
+
* replicating the logic from useAreaPlotData.
|
|
79
|
+
*/
|
|
80
|
+
function getBaselineRadius(baseline, radiusScale, stackedY0) {
|
|
81
|
+
if (typeof baseline === 'number') {
|
|
82
|
+
return radiusScale(baseline);
|
|
83
|
+
}
|
|
84
|
+
if (baseline === 'max') {
|
|
85
|
+
return radiusScale.range()[1];
|
|
86
|
+
}
|
|
87
|
+
if (baseline === 'min') {
|
|
88
|
+
return radiusScale.range()[0];
|
|
89
|
+
}
|
|
90
|
+
// Default: use the stacked baseline value.
|
|
91
|
+
const value = radiusScale(stackedY0);
|
|
92
|
+
if (Number.isNaN(value)) {
|
|
93
|
+
return radiusScale.range()[0];
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Collect the pixel-coordinate points for a contiguous (non-null) segment
|
|
99
|
+
// of a series that contains the bracket indices.
|
|
100
|
+
//
|
|
101
|
+
// When connectNulls is true, all non-null points are returned.
|
|
102
|
+
// When connectNulls is false, only the contiguous run containing [left, right] is returned.
|
|
103
|
+
function collectCurvePoints(data, getPosition, left, right, connectNulls) {
|
|
104
|
+
const points = [];
|
|
105
|
+
if (connectNulls) {
|
|
106
|
+
// All non-null points form one continuous curve.
|
|
107
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
108
|
+
if (data[i] != null) {
|
|
109
|
+
const position = getPosition(i);
|
|
110
|
+
if (position != null && !Number.isNaN(position.y) && !Number.isNaN(position.x)) {
|
|
111
|
+
points.push(position);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return points;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Find the contiguous non-null run containing [left, right].
|
|
119
|
+
let start = left;
|
|
120
|
+
while (start > 0 && data[start - 1] != null) {
|
|
121
|
+
start -= 1;
|
|
122
|
+
}
|
|
123
|
+
let end = right;
|
|
124
|
+
while (end < data.length - 1 && data[end + 1] != null) {
|
|
125
|
+
end += 1;
|
|
126
|
+
}
|
|
127
|
+
for (let i = start; i <= end; i += 1) {
|
|
128
|
+
const position = getPosition(i);
|
|
129
|
+
if (position != null && !Number.isNaN(position.y) && !Number.isNaN(position.x)) {
|
|
130
|
+
points.push(position);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return points;
|
|
134
|
+
}
|
|
135
|
+
function isInRadiusRange(pointerRadius, radiusAxis) {
|
|
136
|
+
const range = radiusAxis.scale.range();
|
|
137
|
+
const minRadius = Math.min(range[0], range[1]);
|
|
138
|
+
const maxRadius = Math.max(range[0], range[1]);
|
|
139
|
+
return pointerRadius >= minRadius && pointerRadius <= maxRadius;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The maximum pixel distance (in the radial direction) from a line at which
|
|
143
|
+
* the line is still considered "close enough" to be selected over an area.
|
|
144
|
+
*/
|
|
145
|
+
const LINE_PROXIMITY_THRESHOLD = 15;
|
|
146
|
+
export default function getItemAtPosition(state, point) {
|
|
147
|
+
const {
|
|
148
|
+
axis: rotationAxes,
|
|
149
|
+
axisIds: rotationAxisIds
|
|
150
|
+
} = selectorChartRotationAxis(state);
|
|
151
|
+
const {
|
|
152
|
+
axis: radiusAxes,
|
|
153
|
+
axisIds: radiusAxisIds
|
|
154
|
+
} = selectorChartRadiusAxis(state);
|
|
155
|
+
const center = selectorChartPolarCenter(state);
|
|
156
|
+
const series = selectorAllSeriesOfType(state, 'radialLine');
|
|
157
|
+
if (!series || series.seriesOrder.length === 0) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const defaultRotationAxisId = rotationAxisIds[0];
|
|
161
|
+
const defaultRadiusAxisId = radiusAxisIds[0];
|
|
162
|
+
|
|
163
|
+
// Convert the pointer position to polar coordinates.
|
|
164
|
+
const dx = point.x - center.cx;
|
|
165
|
+
const dy = center.cy - point.y;
|
|
166
|
+
const pointerRadius = Math.sqrt(dx * dx + dy * dy);
|
|
167
|
+
const pointerAngle = Math.atan2(dx, dy);
|
|
168
|
+
|
|
169
|
+
// Step 1: Find the closest line across all series (measured as radial distance).
|
|
170
|
+
let closestDistance = Infinity;
|
|
171
|
+
let closestItem;
|
|
172
|
+
for (const seriesId of series.seriesOrder) {
|
|
173
|
+
const seriesItem = series.series[seriesId];
|
|
174
|
+
if (seriesItem.hidden) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const rotationAxisId = seriesItem.rotationAxisId ?? defaultRotationAxisId;
|
|
178
|
+
const radiusAxisId = seriesItem.radiusAxisId ?? defaultRadiusAxisId;
|
|
179
|
+
const rotationAxis = rotationAxes[rotationAxisId];
|
|
180
|
+
const radiusAxis = radiusAxes[radiusAxisId];
|
|
181
|
+
if (!isInRadiusRange(pointerRadius, radiusAxis)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const bracket = getBracketIndices(rotationAxis, pointerAngle);
|
|
185
|
+
if (!bracket) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const {
|
|
189
|
+
left,
|
|
190
|
+
right
|
|
191
|
+
} = bracket;
|
|
192
|
+
const {
|
|
193
|
+
visibleStackedData,
|
|
194
|
+
data,
|
|
195
|
+
connectNulls,
|
|
196
|
+
curve
|
|
197
|
+
} = seriesItem;
|
|
198
|
+
const dataIndex = getPolarAxisIndex(rotationAxis, pointerAngle);
|
|
199
|
+
if (dataIndex === -1) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Evaluate the actual curve at the pointer's angle for precise distance.
|
|
204
|
+
const rotationData = rotationAxis.data;
|
|
205
|
+
if (!rotationData) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const rotationPosition = getValueToPositionMapper(rotationAxis.scale);
|
|
209
|
+
const getRotation = idx => rotationPosition(rotationData[idx]);
|
|
210
|
+
const getRadius = idx => {
|
|
211
|
+
const stacked = visibleStackedData[idx];
|
|
212
|
+
return stacked ? radiusAxis.scale(stacked[1]) : null;
|
|
213
|
+
};
|
|
214
|
+
const getPosition = idx => {
|
|
215
|
+
const rotation = getRotation(idx);
|
|
216
|
+
const radius = getRadius(idx);
|
|
217
|
+
if (rotation == null || radius == null) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
radius,
|
|
222
|
+
rotation,
|
|
223
|
+
// coordinate centered at (0, 0)
|
|
224
|
+
x: radius * Math.sin(rotation),
|
|
225
|
+
y: -radius * Math.cos(rotation)
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
const curvePoints = collectCurvePoints(data, getPosition, left, right, connectNulls);
|
|
229
|
+
if (curvePoints.length < 2) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const closestPoint = evaluateCurveAtAngle(curvePoints, pointerAngle, curve);
|
|
233
|
+
if (closestPoint == null) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const distance = Math.abs(pointerRadius - Math.sqrt(closestPoint.x ** 2 + closestPoint.y ** 2));
|
|
237
|
+
if (distance < closestDistance) {
|
|
238
|
+
closestDistance = distance;
|
|
239
|
+
closestItem = {
|
|
240
|
+
type: 'radialLine',
|
|
241
|
+
seriesId,
|
|
242
|
+
dataIndex
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Step 2: If the closest line is within the proximity threshold, pick it.
|
|
248
|
+
if (closestItem && closestDistance <= LINE_PROXIMITY_THRESHOLD && !series.series[closestItem.seriesId].area) {
|
|
249
|
+
return closestItem;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Step 3: Check area series — iterate stacking groups in reverse
|
|
253
|
+
// so that topmost (last rendered) area is checked first.
|
|
254
|
+
const {
|
|
255
|
+
stackingGroups
|
|
256
|
+
} = series;
|
|
257
|
+
for (let g = stackingGroups.length - 1; g >= 0; g -= 1) {
|
|
258
|
+
const groupIds = stackingGroups[g].ids;
|
|
259
|
+
for (let i = 0; i <= groupIds.length - 1; i += 1) {
|
|
260
|
+
const seriesId = groupIds[i];
|
|
261
|
+
const seriesItem = series.series[seriesId];
|
|
262
|
+
if (seriesItem.hidden || !seriesItem.area) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const rotationAxisId = seriesItem.rotationAxisId ?? defaultRotationAxisId;
|
|
266
|
+
const radiusAxisId = seriesItem.radiusAxisId ?? defaultRadiusAxisId;
|
|
267
|
+
const rotationAxis = rotationAxes[rotationAxisId];
|
|
268
|
+
const radiusAxis = radiusAxes[radiusAxisId];
|
|
269
|
+
if (!rotationAxis || !radiusAxis) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const bracket = getBracketIndices(rotationAxis, pointerAngle);
|
|
273
|
+
if (!bracket) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const {
|
|
277
|
+
left,
|
|
278
|
+
right
|
|
279
|
+
} = bracket;
|
|
280
|
+
const {
|
|
281
|
+
visibleStackedData,
|
|
282
|
+
data,
|
|
283
|
+
connectNulls,
|
|
284
|
+
baseline,
|
|
285
|
+
curve
|
|
286
|
+
} = seriesItem;
|
|
287
|
+
|
|
288
|
+
// Check for null gaps at bracket points.
|
|
289
|
+
if ((data[left] == null || data[right] == null) && !connectNulls) {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const rotationScale = rotationAxis.scale;
|
|
293
|
+
const radiusScale = radiusAxis.scale;
|
|
294
|
+
const rotationPosition = getValueToPositionMapper(rotationScale);
|
|
295
|
+
const rotationData = rotationAxis.data;
|
|
296
|
+
if (!rotationData) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const getRotation = idx => rotationPosition(rotationData[idx]);
|
|
300
|
+
const getRadius = (idx, position) => {
|
|
301
|
+
const stacked = visibleStackedData[idx];
|
|
302
|
+
return position === 0 ? getBaselineRadius(baseline, radiusScale, stacked ? stacked[0] : 0) : radiusScale(stacked[1]);
|
|
303
|
+
};
|
|
304
|
+
const getPosition = position => idx => {
|
|
305
|
+
const rotation = getRotation(idx);
|
|
306
|
+
const radius = getRadius(idx, position);
|
|
307
|
+
if (rotation == null || radius == null) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
radius,
|
|
312
|
+
rotation,
|
|
313
|
+
// coordinate centered at (0, 0)
|
|
314
|
+
x: radius * Math.sin(rotation),
|
|
315
|
+
y: -radius * Math.cos(rotation)
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// Build pixel-coordinate points for the top and bottom curves,
|
|
320
|
+
// then evaluate them at the pointer's x using the actual d3 curve.
|
|
321
|
+
const topPoints = collectCurvePoints(data, getPosition(1), left, right, connectNulls);
|
|
322
|
+
const bottomPoints = collectCurvePoints(data, getPosition(0), left, right, connectNulls);
|
|
323
|
+
if (topPoints.length < 2 || bottomPoints.length < 2) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const outerPoint = evaluateCurveAtAngle(topPoints, pointerAngle, curve);
|
|
327
|
+
const innerPoint = evaluateCurveAtAngle(bottomPoints, pointerAngle, curve);
|
|
328
|
+
if (outerPoint == null || innerPoint == null) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const innerRadius = Math.sqrt(innerPoint.x ** 2 + innerPoint.y ** 2);
|
|
332
|
+
const outerRadius = Math.sqrt(outerPoint.x ** 2 + outerPoint.y ** 2);
|
|
333
|
+
const radiusMin = Math.min(innerRadius, outerRadius);
|
|
334
|
+
const radiusMax = Math.max(innerRadius, outerRadius);
|
|
335
|
+
if (pointerRadius >= radiusMin && pointerRadius <= radiusMax) {
|
|
336
|
+
const dataIndex = getPolarAxisIndex(rotationAxis, pointerAngle);
|
|
337
|
+
return {
|
|
338
|
+
type: 'radialLine',
|
|
339
|
+
seriesId,
|
|
340
|
+
dataIndex: dataIndex === -1 ? left : dataIndex
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Step 4: No area matched — return the closest line regardless of threshold.
|
|
347
|
+
return closestItem;
|
|
348
|
+
}
|
|
@@ -8,6 +8,7 @@ exports.default = void 0;
|
|
|
8
8
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
9
|
const getSeriesWithDefaultValues = (seriesData, seriesIndex, colors) => (0, _extends2.default)({}, seriesData, {
|
|
10
10
|
id: seriesData.id ?? `auto-generated-id-${seriesIndex}`,
|
|
11
|
-
color: seriesData.color ?? colors[seriesIndex % colors.length]
|
|
11
|
+
color: seriesData.color ?? colors[seriesIndex % colors.length],
|
|
12
|
+
curve: seriesData.curve ?? 'linear'
|
|
12
13
|
});
|
|
13
14
|
var _default = exports.default = getSeriesWithDefaultValues;
|