@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.
Files changed (171) hide show
  1. package/BarChartPremium/BarChartPremium.js +2 -1183
  2. package/BarChartPremium/BarChartPremium.mjs +2 -1183
  3. package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.js +2 -0
  4. package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.mjs +2 -0
  5. package/CHANGELOG.md +133 -0
  6. package/CandlestickChart/CandlestickChart.d.mts +2 -2
  7. package/CandlestickChart/CandlestickChart.d.ts +2 -2
  8. package/CandlestickChart/CandlestickChart.js +2 -1183
  9. package/CandlestickChart/CandlestickChart.mjs +2 -1183
  10. package/CandlestickChart/CandlestickWebGLProgram.d.mts +6 -11
  11. package/CandlestickChart/CandlestickWebGLProgram.d.ts +6 -11
  12. package/CandlestickChart/CandlestickWebGLProgram.js +136 -121
  13. package/CandlestickChart/CandlestickWebGLProgram.mjs +137 -122
  14. package/CandlestickChart/useCandlestickPlotData.d.mts +2 -2
  15. package/CandlestickChart/useCandlestickPlotData.d.ts +2 -2
  16. package/CandlestickChart/useCandlestickPlotData.js +121 -61
  17. package/CandlestickChart/useCandlestickPlotData.mjs +122 -61
  18. package/ChartsAxisHighlightValue/index.d.mts +1 -0
  19. package/ChartsAxisHighlightValue/index.d.ts +1 -0
  20. package/ChartsAxisHighlightValue/index.js +16 -0
  21. package/ChartsAxisHighlightValue/index.mjs +2 -0
  22. package/ChartsDataProviderPremium/ChartsDataProviderPremium.js +2 -2
  23. package/ChartsDataProviderPremium/ChartsDataProviderPremium.mjs +2 -2
  24. package/ChartsRadialAxisHighlight/index.d.mts +1 -0
  25. package/ChartsRadialAxisHighlight/index.d.ts +1 -0
  26. package/ChartsRadialAxisHighlight/index.js +16 -0
  27. package/ChartsRadialAxisHighlight/index.mjs +2 -0
  28. package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.js +2 -2
  29. package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.mjs +2 -2
  30. package/HeatmapPremium/HeatmapPremium.js +2 -155
  31. package/HeatmapPremium/HeatmapPremium.mjs +2 -155
  32. package/HeatmapPremium/webgl/HeatmapWebGLPlot.js +19 -112
  33. package/HeatmapPremium/webgl/HeatmapWebGLPlot.mjs +19 -111
  34. package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.mts +24 -0
  35. package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.ts +24 -0
  36. package/HeatmapPremium/webgl/HeatmapWebGLProgram.js +132 -0
  37. package/HeatmapPremium/webgl/HeatmapWebGLProgram.mjs +125 -0
  38. package/HeatmapPremium/webgl/useHeatmapPlotData.d.mts +3 -3
  39. package/HeatmapPremium/webgl/useHeatmapPlotData.d.ts +3 -3
  40. package/HeatmapPremium/webgl/useHeatmapPlotData.js +78 -26
  41. package/HeatmapPremium/webgl/useHeatmapPlotData.mjs +80 -26
  42. package/LICENSE +3 -1
  43. package/RadialBarChart/RadialBarChart.d.mts +60 -0
  44. package/RadialBarChart/RadialBarChart.d.ts +60 -0
  45. package/RadialBarChart/RadialBarChart.js +298 -0
  46. package/RadialBarChart/RadialBarChart.mjs +292 -0
  47. package/RadialBarChart/RadialBarChart.plugins.d.mts +4 -0
  48. package/RadialBarChart/RadialBarChart.plugins.d.ts +4 -0
  49. package/RadialBarChart/RadialBarChart.plugins.js +9 -0
  50. package/RadialBarChart/RadialBarChart.plugins.mjs +3 -0
  51. package/RadialBarChart/RadialBarElement.d.mts +16 -0
  52. package/RadialBarChart/RadialBarElement.d.ts +16 -0
  53. package/RadialBarChart/RadialBarElement.js +54 -0
  54. package/RadialBarChart/RadialBarElement.mjs +48 -0
  55. package/RadialBarChart/RadialBarPlot.d.mts +21 -0
  56. package/RadialBarChart/RadialBarPlot.d.ts +21 -0
  57. package/RadialBarChart/RadialBarPlot.js +85 -0
  58. package/RadialBarChart/RadialBarPlot.mjs +79 -0
  59. package/RadialBarChart/index.d.mts +3 -0
  60. package/RadialBarChart/index.d.ts +3 -0
  61. package/RadialBarChart/index.js +39 -0
  62. package/RadialBarChart/index.mjs +3 -0
  63. package/RadialBarChart/radialBarClasses.d.mts +15 -0
  64. package/RadialBarChart/radialBarClasses.d.ts +15 -0
  65. package/RadialBarChart/radialBarClasses.js +26 -0
  66. package/RadialBarChart/radialBarClasses.mjs +18 -0
  67. package/RadialBarChart/seriesConfig/seriesProcessor.js +4 -0
  68. package/RadialBarChart/seriesConfig/seriesProcessor.mjs +4 -0
  69. package/RadialBarChart/useRadialBarChartProps.d.mts +28 -0
  70. package/RadialBarChart/useRadialBarChartProps.d.ts +28 -0
  71. package/RadialBarChart/useRadialBarChartProps.js +100 -0
  72. package/RadialBarChart/useRadialBarChartProps.mjs +93 -0
  73. package/RadialBarChart/useRadialBarPlotData.d.mts +23 -0
  74. package/RadialBarChart/useRadialBarPlotData.d.ts +23 -0
  75. package/RadialBarChart/useRadialBarPlotData.js +94 -0
  76. package/RadialBarChart/useRadialBarPlotData.mjs +87 -0
  77. package/RadialLineChart/RadialArea.js +13 -1
  78. package/RadialLineChart/RadialArea.mjs +13 -1
  79. package/RadialLineChart/RadialLine.js +13 -1
  80. package/RadialLineChart/RadialLine.mjs +13 -1
  81. package/RadialLineChart/RadialLineChart.d.mts +11 -3
  82. package/RadialLineChart/RadialLineChart.d.ts +11 -3
  83. package/RadialLineChart/RadialLineChart.js +24 -673
  84. package/RadialLineChart/RadialLineChart.mjs +24 -673
  85. package/RadialLineChart/RadialLineHighlightElement.d.mts +15 -0
  86. package/RadialLineChart/RadialLineHighlightElement.d.ts +15 -0
  87. package/RadialLineChart/RadialLineHighlightElement.js +46 -0
  88. package/RadialLineChart/RadialLineHighlightElement.mjs +39 -0
  89. package/RadialLineChart/RadialLineHighlightPlot.d.mts +23 -0
  90. package/RadialLineChart/RadialLineHighlightPlot.d.ts +23 -0
  91. package/RadialLineChart/RadialLineHighlightPlot.js +92 -0
  92. package/RadialLineChart/RadialLineHighlightPlot.mjs +86 -0
  93. package/RadialLineChart/RadialMarkPlot.js +17 -2
  94. package/RadialLineChart/RadialMarkPlot.mjs +17 -2
  95. package/RadialLineChart/index.d.mts +3 -1
  96. package/RadialLineChart/index.d.ts +3 -1
  97. package/RadialLineChart/index.js +22 -0
  98. package/RadialLineChart/index.mjs +3 -1
  99. package/RadialLineChart/radialLineClasses.d.mts +3 -1
  100. package/RadialLineChart/radialLineClasses.d.ts +3 -1
  101. package/RadialLineChart/radialLineClasses.js +2 -1
  102. package/RadialLineChart/radialLineClasses.mjs +2 -1
  103. package/RadialLineChart/seriesConfig/getItemAtPosition.d.mts +6 -0
  104. package/RadialLineChart/seriesConfig/getItemAtPosition.d.ts +6 -0
  105. package/RadialLineChart/seriesConfig/getItemAtPosition.js +353 -0
  106. package/RadialLineChart/seriesConfig/getItemAtPosition.mjs +348 -0
  107. package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.js +2 -1
  108. package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.mjs +2 -1
  109. package/RadialLineChart/seriesConfig/index.js +2 -1
  110. package/RadialLineChart/seriesConfig/index.mjs +2 -1
  111. package/RadialLineChart/seriesConfig/seriesProcessor.js +4 -0
  112. package/RadialLineChart/seriesConfig/seriesProcessor.mjs +4 -0
  113. package/RadialLineChart/useRadialLineChartProps.d.mts +2 -0
  114. package/RadialLineChart/useRadialLineChartProps.d.ts +2 -0
  115. package/RadialLineChart/useRadialLineChartProps.js +16 -8
  116. package/RadialLineChart/useRadialLineChartProps.mjs +16 -8
  117. package/RadialLineChart/useRadialLinePlotData.js +2 -1
  118. package/RadialLineChart/useRadialLinePlotData.mjs +3 -2
  119. package/ScatterChartPremium/ScatterChartPremium.d.mts +25 -0
  120. package/ScatterChartPremium/ScatterChartPremium.d.ts +25 -0
  121. package/ScatterChartPremium/ScatterChartPremium.js +507 -0
  122. package/ScatterChartPremium/ScatterChartPremium.mjs +501 -0
  123. package/ScatterChartPremium/ScatterChartPremium.plugins.d.mts +3 -0
  124. package/ScatterChartPremium/ScatterChartPremium.plugins.d.ts +3 -0
  125. package/ScatterChartPremium/ScatterChartPremium.plugins.js +8 -0
  126. package/ScatterChartPremium/ScatterChartPremium.plugins.mjs +2 -0
  127. package/ScatterChartPremium/ScatterPlotPremium.d.mts +14 -0
  128. package/ScatterChartPremium/ScatterPlotPremium.d.ts +14 -0
  129. package/ScatterChartPremium/ScatterPlotPremium.js +28 -0
  130. package/ScatterChartPremium/ScatterPlotPremium.mjs +21 -0
  131. package/ScatterChartPremium/index.d.mts +3 -0
  132. package/ScatterChartPremium/index.d.ts +3 -0
  133. package/ScatterChartPremium/index.js +26 -0
  134. package/ScatterChartPremium/index.mjs +3 -0
  135. package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.mts +4 -0
  136. package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.ts +4 -0
  137. package/ScatterChartPremium/webgl/ScatterWebGLPlot.js +70 -0
  138. package/ScatterChartPremium/webgl/ScatterWebGLPlot.mjs +65 -0
  139. package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.mts +18 -0
  140. package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.ts +18 -0
  141. package/ScatterChartPremium/webgl/ScatterWebGLProgram.js +129 -0
  142. package/ScatterChartPremium/webgl/ScatterWebGLProgram.mjs +122 -0
  143. package/ScatterChartPremium/webgl/shaders.d.mts +2 -0
  144. package/ScatterChartPremium/webgl/shaders.d.ts +2 -0
  145. package/ScatterChartPremium/webgl/shaders.js +57 -0
  146. package/ScatterChartPremium/webgl/shaders.mjs +51 -0
  147. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.mts +7 -0
  148. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.ts +7 -0
  149. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.js +140 -0
  150. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.mjs +134 -0
  151. package/index.d.mts +3 -1
  152. package/index.d.ts +3 -1
  153. package/index.js +25 -1
  154. package/index.mjs +4 -2
  155. package/internals/index.d.mts +1 -0
  156. package/internals/index.d.ts +1 -0
  157. package/internals/index.js +13 -0
  158. package/internals/index.mjs +1 -0
  159. package/models/seriesType/radialLine.d.mts +7 -1
  160. package/models/seriesType/radialLine.d.ts +7 -1
  161. package/package.json +184 -114
  162. package/plugins/selectors/useChartCandlestickPosition.selectors.d.mts +1 -1
  163. package/plugins/selectors/useChartCandlestickPosition.selectors.d.ts +1 -1
  164. package/utils/webgl/parseColor.d.mts +2 -1
  165. package/utils/webgl/parseColor.d.ts +2 -1
  166. package/utils/webgl/parseColor.js +8 -7
  167. package/utils/webgl/parseColor.mjs +8 -7
  168. package/utils/webgl/utils.d.mts +13 -0
  169. package/utils/webgl/utils.d.ts +13 -0
  170. package/utils/webgl/utils.js +29 -0
  171. 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;