@mui/x-charts-pro 8.6.0 → 8.7.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 (78) hide show
  1. package/CHANGELOG.md +104 -1
  2. package/ChartContainerPro/index.d.ts +7 -1
  3. package/ChartContainerPro/index.js +0 -11
  4. package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  5. package/ChartZoomSlider/index.d.ts +2 -1
  6. package/ChartZoomSlider/index.js +10 -2
  7. package/ChartZoomSlider/internals/ChartAxisZoomSlider.js +4 -0
  8. package/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +7 -1
  9. package/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +9 -1
  10. package/ChartZoomSlider/internals/chartAxisZoomSliderTrackClasses.d.ts +15 -0
  11. package/ChartZoomSlider/internals/chartAxisZoomSliderTrackClasses.js +31 -0
  12. package/ChartsToolbarPro/ChartsToolbarImageExportTrigger.js +1 -1
  13. package/ChartsToolbarPro/ChartsToolbarPrintExportTrigger.js +1 -1
  14. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +43 -33
  15. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +3 -3
  16. package/{ChartContainerPro → context}/ChartProApi.d.ts +2 -3
  17. package/context/index.d.ts +2 -1
  18. package/context/index.js +4 -4
  19. package/context/useChartProApiContext.d.ts +9 -0
  20. package/context/{useChartApiContext.js → useChartProApiContext.js} +4 -4
  21. package/esm/ChartContainerPro/index.d.ts +7 -1
  22. package/esm/ChartContainerPro/index.js +4 -1
  23. package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  24. package/esm/ChartZoomSlider/index.d.ts +2 -1
  25. package/esm/ChartZoomSlider/index.js +2 -1
  26. package/esm/ChartZoomSlider/internals/ChartAxisZoomSlider.js +4 -0
  27. package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +8 -1
  28. package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +10 -1
  29. package/esm/ChartZoomSlider/internals/chartAxisZoomSliderTrackClasses.d.ts +15 -0
  30. package/esm/ChartZoomSlider/internals/chartAxisZoomSliderTrackClasses.js +21 -0
  31. package/esm/ChartsToolbarPro/ChartsToolbarImageExportTrigger.js +2 -2
  32. package/esm/ChartsToolbarPro/ChartsToolbarPrintExportTrigger.js +2 -2
  33. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +43 -33
  34. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +3 -3
  35. package/esm/{ChartContainerPro → context}/ChartProApi.d.ts +2 -3
  36. package/esm/context/index.d.ts +2 -1
  37. package/esm/context/index.js +2 -1
  38. package/esm/context/useChartProApiContext.d.ts +9 -0
  39. package/esm/context/{useChartApiContext.js → useChartProApiContext.js} +3 -3
  40. package/esm/hooks/index.d.ts +2 -1
  41. package/esm/hooks/index.js +2 -1
  42. package/esm/hooks/useChartProApiRef.d.ts +23 -0
  43. package/esm/hooks/useChartProApiRef.js +20 -0
  44. package/esm/index.d.ts +4 -2
  45. package/esm/index.js +3 -3
  46. package/esm/internals/plugins/allPlugins.d.ts +2 -2
  47. package/esm/internals/plugins/useChartProZoom/gestureHooks/usePanOnDrag.d.ts +8 -0
  48. package/esm/internals/plugins/useChartProZoom/gestureHooks/usePanOnDrag.js +58 -0
  49. package/esm/internals/plugins/useChartProZoom/{useChartProZoom.utils.d.ts → gestureHooks/useZoom.utils.d.ts} +14 -10
  50. package/esm/internals/plugins/useChartProZoom/{useChartProZoom.utils.js → gestureHooks/useZoom.utils.js} +41 -31
  51. package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoomOnPinch.d.ts +8 -0
  52. package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoomOnPinch.js +59 -0
  53. package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoomOnWheel.d.ts +8 -0
  54. package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoomOnWheel.js +79 -0
  55. package/esm/internals/plugins/useChartProZoom/useChartProZoom.js +15 -227
  56. package/esm/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +4 -4
  57. package/hooks/index.d.ts +2 -1
  58. package/hooks/index.js +11 -0
  59. package/hooks/useChartProApiRef.d.ts +23 -0
  60. package/hooks/useChartProApiRef.js +28 -0
  61. package/index.d.ts +4 -2
  62. package/index.js +58 -22
  63. package/internals/plugins/allPlugins.d.ts +2 -2
  64. package/internals/plugins/useChartProZoom/gestureHooks/usePanOnDrag.d.ts +8 -0
  65. package/internals/plugins/useChartProZoom/gestureHooks/usePanOnDrag.js +65 -0
  66. package/internals/plugins/useChartProZoom/{useChartProZoom.utils.d.ts → gestureHooks/useZoom.utils.d.ts} +14 -10
  67. package/internals/plugins/useChartProZoom/{useChartProZoom.utils.js → gestureHooks/useZoom.utils.js} +43 -34
  68. package/internals/plugins/useChartProZoom/gestureHooks/useZoomOnPinch.d.ts +8 -0
  69. package/internals/plugins/useChartProZoom/gestureHooks/useZoomOnPinch.js +66 -0
  70. package/internals/plugins/useChartProZoom/gestureHooks/useZoomOnWheel.d.ts +8 -0
  71. package/internals/plugins/useChartProZoom/gestureHooks/useZoomOnWheel.js +86 -0
  72. package/internals/plugins/useChartProZoom/useChartProZoom.js +14 -226
  73. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +4 -4
  74. package/package.json +5 -4
  75. package/context/useChartApiContext.d.ts +0 -9
  76. package/esm/context/useChartApiContext.d.ts +0 -9
  77. /package/{ChartContainerPro → context}/ChartProApi.js +0 -0
  78. /package/esm/{ChartContainerPro → context}/ChartProApi.js +0 -0
@@ -1,3 +1,4 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
1
2
  /**
2
3
  * Helper to get the range (in percents of a reference range) corresponding to a given scale.
3
4
  * @param centerRatio {number} The ratio of the point that should not move between the previous and next range.
@@ -76,34 +77,6 @@ export function getWheelScaleRatio(event, step) {
76
77
  };
77
78
  }
78
79
 
79
- /**
80
- * Get the scale ratio and if it's a zoom in or out from a pinch gesture.
81
- */
82
- export function getPinchScaleRatio(curDiff, prevDiff, step) {
83
- const scaledStep = step / 1000;
84
- let scaleRatio = 0;
85
- let isZoomIn = false;
86
- const hasMoved = prevDiff > 0;
87
- if (hasMoved && curDiff > prevDiff) {
88
- // The distance between the two pointers has increased
89
- scaleRatio = 1 + scaledStep;
90
- isZoomIn = true;
91
- }
92
- if (hasMoved && curDiff < prevDiff) {
93
- // The distance between the two pointers has decreased
94
- scaleRatio = 1 - scaledStep;
95
- isZoomIn = false;
96
- }
97
- return {
98
- scaleRatio,
99
- isZoomIn
100
- };
101
- }
102
- export function getDiff(eventCache) {
103
- const [firstEvent, secondEvent] = eventCache;
104
- return Math.hypot(firstEvent.pageX - secondEvent.pageX, firstEvent.pageY - secondEvent.pageY);
105
- }
106
-
107
80
  /**
108
81
  * Get the ratio of the point in the horizontal center of the area.
109
82
  */
@@ -114,13 +87,50 @@ export function getHorizontalCenterRatio(point, area) {
114
87
  } = area;
115
88
  return (point.x - left) / width;
116
89
  }
117
- export function preventDefault(event) {
118
- event.preventDefault();
119
- }
90
+
91
+ /**
92
+ * Get the ratio of the point in the vertical center of the area.
93
+ */
120
94
  export function getVerticalCenterRatio(point, area) {
121
95
  const {
122
96
  top,
123
97
  height
124
98
  } = area;
125
99
  return (point.y - top) / height * -1 + 1;
100
+ }
101
+
102
+ /**
103
+ * Translate the zoom data by a given movement.
104
+ */
105
+ export function translateZoom(initialZoomData, movement, drawingArea, optionsLookup) {
106
+ return initialZoomData.map(zoom => {
107
+ const options = optionsLookup[zoom.axisId];
108
+ if (!options || !options.panning) {
109
+ return zoom;
110
+ }
111
+ const min = zoom.start;
112
+ const max = zoom.end;
113
+ const span = max - min;
114
+ const MIN_PERCENT = options.minStart;
115
+ const MAX_PERCENT = options.maxEnd;
116
+ const displacement = options.axisDirection === 'x' ? movement.x : movement.y;
117
+ const dimension = options.axisDirection === 'x' ? drawingArea.width : drawingArea.height;
118
+ let newMinPercent = min - displacement / dimension * span;
119
+ let newMaxPercent = max - displacement / dimension * span;
120
+ if (newMinPercent < MIN_PERCENT) {
121
+ newMinPercent = MIN_PERCENT;
122
+ newMaxPercent = newMinPercent + span;
123
+ }
124
+ if (newMaxPercent > MAX_PERCENT) {
125
+ newMaxPercent = MAX_PERCENT;
126
+ newMinPercent = newMaxPercent - span;
127
+ }
128
+ if (newMinPercent < MIN_PERCENT || newMaxPercent > MAX_PERCENT || span < options.minSpan || span > options.maxSpan) {
129
+ return zoom;
130
+ }
131
+ return _extends({}, zoom, {
132
+ start: newMinPercent,
133
+ end: newMaxPercent
134
+ });
135
+ });
126
136
  }
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import { ChartPlugin, ZoomData } from '@mui/x-charts/internals';
3
+ import { UseChartProZoomSignature } from "../useChartProZoom.types.js";
4
+ export declare const useZoomOnPinch: ({
5
+ store,
6
+ instance,
7
+ svgRef
8
+ }: Pick<Parameters<ChartPlugin<UseChartProZoomSignature>>[0], "store" | "instance" | "svgRef">, setZoomDataCallback: React.Dispatch<ZoomData[] | ((prev: ZoomData[]) => ZoomData[])>) => void;
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { useSelector, getSVGPoint, selectorChartDrawingArea, selectorChartZoomOptionsLookup } from '@mui/x-charts/internals';
5
+ import { rafThrottle } from '@mui/x-internals/rafThrottle';
6
+ import { getHorizontalCenterRatio, getVerticalCenterRatio, isSpanValid, zoomAtPoint } from "./useZoom.utils.js";
7
+ export const useZoomOnPinch = ({
8
+ store,
9
+ instance,
10
+ svgRef
11
+ }, setZoomDataCallback) => {
12
+ const drawingArea = useSelector(store, selectorChartDrawingArea);
13
+ const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
14
+ const isZoomEnabled = Object.keys(optionsLookup).length > 0;
15
+
16
+ // Zoom on pinch
17
+ React.useEffect(() => {
18
+ const element = svgRef.current;
19
+ if (element === null || !isZoomEnabled) {
20
+ return () => {};
21
+ }
22
+ const rafThrottledCallback = rafThrottle(event => {
23
+ setZoomDataCallback(prev => {
24
+ return prev.map(zoom => {
25
+ const option = optionsLookup[zoom.axisId];
26
+ if (!option) {
27
+ return zoom;
28
+ }
29
+ const isZoomIn = event.detail.direction > 0;
30
+ const scaleRatio = 1 + event.detail.deltaScale;
31
+
32
+ // If the delta is 0, it means the pinch gesture is not valid.
33
+ if (event.detail.direction === 0) {
34
+ return zoom;
35
+ }
36
+ const point = getSVGPoint(element, {
37
+ clientX: event.detail.centroid.x,
38
+ clientY: event.detail.centroid.y
39
+ });
40
+ const centerRatio = option.axisDirection === 'x' ? getHorizontalCenterRatio(point, drawingArea) : getVerticalCenterRatio(point, drawingArea);
41
+ const [newMinRange, newMaxRange] = zoomAtPoint(centerRatio, scaleRatio, zoom, option);
42
+ if (!isSpanValid(newMinRange, newMaxRange, isZoomIn, option)) {
43
+ return zoom;
44
+ }
45
+ return {
46
+ axisId: zoom.axisId,
47
+ start: newMinRange,
48
+ end: newMaxRange
49
+ };
50
+ });
51
+ });
52
+ });
53
+ const zoomHandler = instance.addInteractionListener('pinch', rafThrottledCallback);
54
+ return () => {
55
+ zoomHandler.cleanup();
56
+ rafThrottledCallback.clear();
57
+ };
58
+ }, [svgRef, drawingArea, isZoomEnabled, optionsLookup, store, instance, setZoomDataCallback]);
59
+ };
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import { ChartPlugin, ZoomData } from '@mui/x-charts/internals';
3
+ import { UseChartProZoomSignature } from "../useChartProZoom.types.js";
4
+ export declare const useZoomOnWheel: ({
5
+ store,
6
+ instance,
7
+ svgRef
8
+ }: Pick<Parameters<ChartPlugin<UseChartProZoomSignature>>[0], "store" | "instance" | "svgRef">, setZoomDataCallback: React.Dispatch<ZoomData[] | ((prev: ZoomData[]) => ZoomData[])>) => void;
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { useSelector, getSVGPoint, selectorChartDrawingArea, selectorChartZoomOptionsLookup } from '@mui/x-charts/internals';
5
+ import { rafThrottle } from '@mui/x-internals/rafThrottle';
6
+ import { getHorizontalCenterRatio, getVerticalCenterRatio, getWheelScaleRatio, isSpanValid, zoomAtPoint } from "./useZoom.utils.js";
7
+ export const useZoomOnWheel = ({
8
+ store,
9
+ instance,
10
+ svgRef
11
+ }, setZoomDataCallback) => {
12
+ const drawingArea = useSelector(store, selectorChartDrawingArea);
13
+ const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
14
+ const isZoomEnabled = Object.keys(optionsLookup).length > 0;
15
+ const startedOutsideRef = React.useRef(false);
16
+ const startedOutsideTimeoutRef = React.useRef(null);
17
+
18
+ // Add event for chart zoom in/out
19
+ React.useEffect(() => {
20
+ const element = svgRef.current;
21
+ if (element === null || !isZoomEnabled) {
22
+ return () => {};
23
+ }
24
+ const rafThrottledSetZoomData = rafThrottle(setZoomDataCallback);
25
+ const zoomOnWheelHandler = instance.addInteractionListener('turnWheel', event => {
26
+ const point = getSVGPoint(element, {
27
+ clientX: event.detail.centroid.x,
28
+ clientY: event.detail.centroid.y
29
+ });
30
+
31
+ // This prevents a zoom event from being triggered when the mouse is outside the chart area.
32
+ // The timeout is used to prevent an weird behavior where if the mouse is outside but enters due to
33
+ // scrolling, then the zoom event is triggered.
34
+ if (startedOutsideRef.current || !instance.isPointInside(point.x, point.y)) {
35
+ startedOutsideRef.current = true;
36
+ if (startedOutsideTimeoutRef.current) {
37
+ clearTimeout(startedOutsideTimeoutRef.current);
38
+ }
39
+ startedOutsideTimeoutRef.current = setTimeout(() => {
40
+ startedOutsideRef.current = false;
41
+ startedOutsideTimeoutRef.current = null;
42
+ }, 100);
43
+ return;
44
+ }
45
+ event.detail.srcEvent.preventDefault();
46
+ rafThrottledSetZoomData(prev => {
47
+ return prev.map(zoom => {
48
+ const option = optionsLookup[zoom.axisId];
49
+ if (!option) {
50
+ return zoom;
51
+ }
52
+ const centerRatio = option.axisDirection === 'x' ? getHorizontalCenterRatio(point, drawingArea) : getVerticalCenterRatio(point, drawingArea);
53
+ const {
54
+ scaleRatio,
55
+ isZoomIn
56
+ } = getWheelScaleRatio(event.detail.srcEvent, option.step);
57
+ const [newMinRange, newMaxRange] = zoomAtPoint(centerRatio, scaleRatio, zoom, option);
58
+ if (!isSpanValid(newMinRange, newMaxRange, isZoomIn, option)) {
59
+ return zoom;
60
+ }
61
+ return {
62
+ axisId: zoom.axisId,
63
+ start: newMinRange,
64
+ end: newMaxRange
65
+ };
66
+ });
67
+ });
68
+ });
69
+ return () => {
70
+ zoomOnWheelHandler.cleanup();
71
+ if (startedOutsideTimeoutRef.current) {
72
+ clearTimeout(startedOutsideTimeoutRef.current);
73
+ startedOutsideTimeoutRef.current = null;
74
+ }
75
+ startedOutsideRef.current = false;
76
+ rafThrottledSetZoomData.clear();
77
+ };
78
+ }, [svgRef, drawingArea, isZoomEnabled, optionsLookup, instance, setZoomDataCallback, store]);
79
+ };
@@ -2,12 +2,13 @@
2
2
 
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
- import { useSelector, getSVGPoint, selectorChartDrawingArea, createZoomLookup, selectorChartZoomOptionsLookup, selectorChartAxisZoomOptionsLookup } from '@mui/x-charts/internals';
6
- import { useEventCallback } from '@mui/material/utils';
7
- import { rafThrottle } from '@mui/x-internals/rafThrottle';
5
+ import { useSelector, selectorChartZoomOptionsLookup, createZoomLookup, selectorChartAxisZoomOptionsLookup } from '@mui/x-charts/internals';
8
6
  import debounce from '@mui/utils/debounce';
7
+ import { useEventCallback } from '@mui/material/utils';
9
8
  import { calculateZoom } from "./calculateZoom.js";
10
- import { getDiff, getHorizontalCenterRatio, getPinchScaleRatio, getVerticalCenterRatio, getWheelScaleRatio, isSpanValid, preventDefault, zoomAtPoint } from "./useChartProZoom.utils.js";
9
+ import { useZoomOnWheel } from "./gestureHooks/useZoomOnWheel.js";
10
+ import { useZoomOnPinch } from "./gestureHooks/useZoomOnPinch.js";
11
+ import { usePanOnDrag } from "./gestureHooks/usePanOnDrag.js";
11
12
 
12
13
  // It is helpful to avoid the need to provide the possibly auto-generated id for each axis.
13
14
  export function initializeZoomData(options, zoomData) {
@@ -43,10 +44,8 @@ export const useChartProZoom = ({
43
44
  zoomData: paramsZoomData,
44
45
  onZoomChange: onZoomChangeProp
45
46
  } = params;
46
- const drawingArea = useSelector(store, selectorChartDrawingArea);
47
- const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
48
- const isZoomEnabled = Object.keys(optionsLookup).length > 0;
49
47
  const onZoomChange = useEventCallback(onZoomChangeProp ?? (() => {}));
48
+ const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
50
49
 
51
50
  // Manage controlled state
52
51
  React.useEffect(() => {
@@ -142,228 +141,17 @@ export const useChartProZoom = ({
142
141
  return () => {
143
142
  removeIsInteracting.clear();
144
143
  };
145
- }, [setZoomDataCallback, removeIsInteracting]);
144
+ }, [removeIsInteracting]);
146
145
 
147
146
  // Add events
148
- const panningEventCacheRef = React.useRef([]);
149
- const zoomEventCacheRef = React.useRef([]);
150
- const eventPrevDiff = React.useRef(0);
151
-
152
- // Add event for chart panning
153
- const isPanEnabled = React.useMemo(() => Object.values(optionsLookup).some(v => v.panning) || false, [optionsLookup]);
154
- const isDraggingRef = React.useRef(false);
155
- const touchStartRef = React.useRef(null);
156
- React.useEffect(() => {
157
- const element = svgRef.current;
158
- if (element === null || !isPanEnabled) {
159
- return () => {};
160
- }
161
- const throttledHandlePan = rafThrottle((touchStart, point) => {
162
- const movementX = point.x - touchStart.x;
163
- const movementY = (point.y - touchStart.y) * -1;
164
- const newZoomData = touchStart.zoomData.map(zoom => {
165
- const options = optionsLookup[zoom.axisId];
166
- if (!options || !options.panning) {
167
- return zoom;
168
- }
169
- const min = zoom.start;
170
- const max = zoom.end;
171
- const span = max - min;
172
- const MIN_PERCENT = options.minStart;
173
- const MAX_PERCENT = options.maxEnd;
174
- const movement = options.axisDirection === 'x' ? movementX : movementY;
175
- const dimension = options.axisDirection === 'x' ? drawingArea.width : drawingArea.height;
176
- let newMinPercent = min - movement / dimension * span;
177
- let newMaxPercent = max - movement / dimension * span;
178
- if (newMinPercent < MIN_PERCENT) {
179
- newMinPercent = MIN_PERCENT;
180
- newMaxPercent = newMinPercent + span;
181
- }
182
- if (newMaxPercent > MAX_PERCENT) {
183
- newMaxPercent = MAX_PERCENT;
184
- newMinPercent = newMaxPercent - span;
185
- }
186
- if (newMinPercent < MIN_PERCENT || newMaxPercent > MAX_PERCENT || span < options.minSpan || span > options.maxSpan) {
187
- return zoom;
188
- }
189
- return _extends({}, zoom, {
190
- start: newMinPercent,
191
- end: newMaxPercent
192
- });
193
- });
194
- setZoomDataCallback(newZoomData);
195
- });
196
- const handlePan = event => {
197
- if (element === null || !isDraggingRef.current || panningEventCacheRef.current.length > 1) {
198
- return;
199
- }
200
- if (touchStartRef.current == null) {
201
- return;
202
- }
203
- const touchStart = touchStartRef.current;
204
- const point = getSVGPoint(element, event);
205
- throttledHandlePan(touchStart, point);
206
- };
207
- const handleDown = event => {
208
- panningEventCacheRef.current.push(event);
209
- const point = getSVGPoint(element, event);
210
- if (!instance.isPointInside(point.x, point.y)) {
211
- return;
212
- }
213
- // If there is only one pointer, prevent selecting text
214
- if (panningEventCacheRef.current.length === 1) {
215
- event.preventDefault();
216
- }
217
- isDraggingRef.current = true;
218
- touchStartRef.current = {
219
- x: point.x,
220
- y: point.y,
221
- zoomData: store.getSnapshot().zoom.zoomData
222
- };
223
- };
224
- const handleUp = event => {
225
- panningEventCacheRef.current.splice(panningEventCacheRef.current.findIndex(cachedEvent => cachedEvent.pointerId === event.pointerId), 1);
226
- isDraggingRef.current = false;
227
- touchStartRef.current = null;
228
- };
229
- element.addEventListener('pointerdown', handleDown);
230
- document.addEventListener('pointermove', handlePan);
231
- document.addEventListener('pointerup', handleUp);
232
- document.addEventListener('pointercancel', handleUp);
233
- document.addEventListener('pointerleave', handleUp);
234
- return () => {
235
- element.removeEventListener('pointerdown', handleDown);
236
- document.removeEventListener('pointermove', handlePan);
237
- document.removeEventListener('pointerup', handleUp);
238
- document.removeEventListener('pointercancel', handleUp);
239
- document.removeEventListener('pointerleave', handleUp);
240
- throttledHandlePan.clear();
241
- };
242
- }, [instance, svgRef, isDraggingRef, isPanEnabled, optionsLookup, drawingArea.width, drawingArea.height, setZoomDataCallback, store]);
243
-
244
- // Add event for chart zoom in/out
245
- React.useEffect(() => {
246
- const element = svgRef.current;
247
- if (element === null || !isZoomEnabled) {
248
- return () => {};
249
- }
250
- const rafThrottledSetZoomData = rafThrottle(setZoomDataCallback);
251
- const wheelHandler = event => {
252
- if (element === null) {
253
- return;
254
- }
255
- const point = getSVGPoint(element, event);
256
- if (!instance.isPointInside(point.x, point.y)) {
257
- return;
258
- }
259
- event.preventDefault();
260
-
261
- /*
262
- * Need to throttle `setZoomDataCallback` instead of `wheelHandler` because we're calling `event.preventDefault()`.
263
- * If we throttle the event, then some events' default behavior won't be prevented and the page will scroll while
264
- * the user is trying to zoom in.
265
- */
266
- rafThrottledSetZoomData(prevZoomData => {
267
- return prevZoomData.map(zoom => {
268
- const option = optionsLookup[zoom.axisId];
269
- if (!option) {
270
- return zoom;
271
- }
272
- const centerRatio = option.axisDirection === 'x' ? getHorizontalCenterRatio(point, drawingArea) : getVerticalCenterRatio(point, drawingArea);
273
- const {
274
- scaleRatio,
275
- isZoomIn
276
- } = getWheelScaleRatio(event, option.step);
277
- const [newMinRange, newMaxRange] = zoomAtPoint(centerRatio, scaleRatio, zoom, option);
278
- if (!isSpanValid(newMinRange, newMaxRange, isZoomIn, option)) {
279
- return zoom;
280
- }
281
- return {
282
- axisId: zoom.axisId,
283
- start: newMinRange,
284
- end: newMaxRange
285
- };
286
- });
287
- });
288
- };
289
- function pointerDownHandler(event) {
290
- zoomEventCacheRef.current.push(event);
291
- }
292
- const pointerMoveHandler = rafThrottle(function pointerMoveHandler(event) {
293
- if (element === null) {
294
- return;
295
- }
296
- const index = zoomEventCacheRef.current.findIndex(cachedEv => cachedEv.pointerId === event.pointerId);
297
- zoomEventCacheRef.current[index] = event;
298
-
299
- // Not a pinch gesture
300
- if (zoomEventCacheRef.current.length !== 2) {
301
- return;
302
- }
303
- const firstEvent = zoomEventCacheRef.current[0];
304
- const curDiff = getDiff(zoomEventCacheRef.current);
305
- setZoomDataCallback(prevZoomData => {
306
- const newZoomData = prevZoomData.map(zoom => {
307
- const option = optionsLookup[zoom.axisId];
308
- if (!option) {
309
- return zoom;
310
- }
311
- const {
312
- scaleRatio,
313
- isZoomIn
314
- } = getPinchScaleRatio(curDiff, eventPrevDiff.current, option.step);
315
-
316
- // If the scale ratio is 0, it means the pinch gesture is not valid.
317
- if (scaleRatio === 0) {
318
- return zoom;
319
- }
320
- const point = getSVGPoint(element, firstEvent);
321
- const centerRatio = option.axisDirection === 'x' ? getHorizontalCenterRatio(point, drawingArea) : getVerticalCenterRatio(point, drawingArea);
322
- const [newMinRange, newMaxRange] = zoomAtPoint(centerRatio, scaleRatio, zoom, option);
323
- if (!isSpanValid(newMinRange, newMaxRange, isZoomIn, option)) {
324
- return zoom;
325
- }
326
- return {
327
- axisId: zoom.axisId,
328
- start: newMinRange,
329
- end: newMaxRange
330
- };
331
- });
332
- eventPrevDiff.current = curDiff;
333
- return newZoomData;
334
- });
335
- });
336
- function pointerUpHandler(event) {
337
- zoomEventCacheRef.current.splice(zoomEventCacheRef.current.findIndex(cachedEvent => cachedEvent.pointerId === event.pointerId), 1);
338
- if (zoomEventCacheRef.current.length < 2) {
339
- eventPrevDiff.current = 0;
340
- }
341
- }
342
- element.addEventListener('wheel', wheelHandler);
343
- element.addEventListener('pointerdown', pointerDownHandler);
344
- element.addEventListener('pointermove', pointerMoveHandler);
345
- element.addEventListener('pointerup', pointerUpHandler);
346
- element.addEventListener('pointercancel', pointerUpHandler);
347
- element.addEventListener('pointerout', pointerUpHandler);
348
- element.addEventListener('pointerleave', pointerUpHandler);
349
-
350
- // Prevent zooming the entire page on touch devices
351
- element.addEventListener('touchstart', preventDefault);
352
- element.addEventListener('touchmove', preventDefault);
353
- return () => {
354
- element.removeEventListener('wheel', wheelHandler);
355
- element.removeEventListener('pointerdown', pointerDownHandler);
356
- element.removeEventListener('pointermove', pointerMoveHandler);
357
- element.removeEventListener('pointerup', pointerUpHandler);
358
- element.removeEventListener('pointercancel', pointerUpHandler);
359
- element.removeEventListener('pointerout', pointerUpHandler);
360
- element.removeEventListener('pointerleave', pointerUpHandler);
361
- element.removeEventListener('touchstart', preventDefault);
362
- element.removeEventListener('touchmove', preventDefault);
363
- pointerMoveHandler.clear();
364
- rafThrottledSetZoomData.clear();
365
- };
366
- }, [svgRef, drawingArea, isZoomEnabled, optionsLookup, instance, setZoomDataCallback]);
147
+ const pluginData = {
148
+ store,
149
+ instance,
150
+ svgRef
151
+ };
152
+ usePanOnDrag(pluginData, setZoomDataCallback);
153
+ useZoomOnWheel(pluginData, setZoomDataCallback);
154
+ useZoomOnPinch(pluginData, setZoomDataCallback);
367
155
  const zoom = React.useCallback(step => {
368
156
  setZoomDataCallback(prev => prev.map(zoomData => {
369
157
  const zoomOptions = selectorChartAxisZoomOptionsLookup(store.getSnapshot(), zoomData.axisId);
@@ -1,12 +1,12 @@
1
1
  import { AxisId, ChartRootSelector } from '@mui/x-charts/internals';
2
2
  import { UseChartProZoomSignature } from "./useChartProZoom.types.js";
3
3
  export declare const selectorChartZoomState: ChartRootSelector<UseChartProZoomSignature>;
4
- export declare const selectorChartZoomIsInteracting: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
4
+ export declare const selectorChartZoomIsInteracting: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("@mui/x-charts/internals").UseChartInteractionListenerState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
5
5
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
6
6
  } & {
7
7
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
8
8
  }, boolean, any[]>;
9
- export declare const selectorChartZoomIsEnabled: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
9
+ export declare const selectorChartZoomIsEnabled: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("@mui/x-charts/internals").UseChartInteractionListenerState & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
10
10
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
11
11
  } & {
12
12
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
@@ -14,7 +14,7 @@ export declare const selectorChartZoomIsEnabled: import("reselect").Selector<imp
14
14
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
15
15
  }, boolean, []>;
16
16
  export declare const selectorChartAxisZoomData: import("reselect").Selector<any, import("@mui/x-charts/internals").ZoomData | undefined, [axisId: AxisId]>;
17
- export declare const selectorChartCanZoomOut: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
17
+ export declare const selectorChartCanZoomOut: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("@mui/x-charts/internals").UseChartInteractionListenerState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
18
18
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
19
19
  } & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
20
20
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
@@ -23,7 +23,7 @@ export declare const selectorChartCanZoomOut: import("reselect").Selector<import
23
23
  } & {
24
24
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
25
25
  }, boolean, any[]>;
26
- export declare const selectorChartCanZoomIn: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
26
+ export declare const selectorChartCanZoomIn: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & import("@mui/x-charts/internals").UseChartInteractionListenerState & import("./useChartProZoom.types.js").UseChartProZoomState & Partial<{}> & {
27
27
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
28
28
  } & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
29
29
  cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
package/hooks/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./useHeatmapSeries.js";
2
2
  export * from "./useFunnelSeries.js";
3
- export * from "./zoom/index.js";
3
+ export * from "./zoom/index.js";
4
+ export * from "./useChartProApiRef.js";
package/hooks/index.js CHANGED
@@ -35,4 +35,15 @@ Object.keys(_zoom).forEach(function (key) {
35
35
  return _zoom[key];
36
36
  }
37
37
  });
38
+ });
39
+ var _useChartProApiRef = require("./useChartProApiRef");
40
+ Object.keys(_useChartProApiRef).forEach(function (key) {
41
+ if (key === "default" || key === "__esModule") return;
42
+ if (key in exports && exports[key] === _useChartProApiRef[key]) return;
43
+ Object.defineProperty(exports, key, {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _useChartProApiRef[key];
47
+ }
48
+ });
38
49
  });
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import { ChartAnyPluginSignature } from '@mui/x-charts/internals';
3
+ import { AllPluginSignatures } from "../internals/plugins/allPlugins.js";
4
+ import { ProPluginsPerSeriesType, type ChartProApi } from "../context/ChartProApi.js";
5
+ /**
6
+ * Hook that instantiates a [[ChartProApiRef]].
7
+ * The chart type needs to be given as the generic parameter to narrow down the API to the specific chart type.
8
+ * @example
9
+ * ```tsx
10
+ * const barApiRef = useChartProApiRef<'bar'>();
11
+ * ```
12
+ * @example
13
+ * ```tsx
14
+ * // The API can be passed to the chart component and used to interact with the chart.
15
+ * <BarChart apiRef={barApiRef} />
16
+ * ```
17
+ * @example
18
+ * ```tsx
19
+ * // The API can be used to access chart methods and properties.
20
+ * barApiRef.current?.getSeries();
21
+ * ```
22
+ */
23
+ export declare const useChartProApiRef: <ChartType extends keyof ProPluginsPerSeriesType = never, Signatures extends readonly ChartAnyPluginSignature[] = (ChartType extends keyof ProPluginsPerSeriesType ? ProPluginsPerSeriesType[ChartType] : AllPluginSignatures)>() => React.RefObject<ChartProApi<ChartType, Signatures> | undefined>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useChartProApiRef = void 0;
8
+ var React = _interopRequireWildcard(require("react"));
9
+ /**
10
+ * Hook that instantiates a [[ChartProApiRef]].
11
+ * The chart type needs to be given as the generic parameter to narrow down the API to the specific chart type.
12
+ * @example
13
+ * ```tsx
14
+ * const barApiRef = useChartProApiRef<'bar'>();
15
+ * ```
16
+ * @example
17
+ * ```tsx
18
+ * // The API can be passed to the chart component and used to interact with the chart.
19
+ * <BarChart apiRef={barApiRef} />
20
+ * ```
21
+ * @example
22
+ * ```tsx
23
+ * // The API can be used to access chart methods and properties.
24
+ * barApiRef.current?.getSeries();
25
+ * ```
26
+ */
27
+ const useChartProApiRef = () => React.useRef(undefined);
28
+ exports.useChartProApiRef = useChartProApiRef;
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./typeOverloads/modules.js";
2
2
  export * from '@mui/x-charts/constants';
3
- export * from '@mui/x-charts/context';
3
+ export type { FadeOptions, HighlightItemData, HighlightOptions, HighlightScope } from '@mui/x-charts/context';
4
4
  export * from '@mui/x-charts/hooks';
5
5
  export * from '@mui/x-charts/colorPalettes';
6
6
  export * from '@mui/x-charts/models';
@@ -26,9 +26,11 @@ export * from '@mui/x-charts/ChartsSurface';
26
26
  export * from '@mui/x-charts/ChartDataProvider';
27
27
  export * from '@mui/x-charts/ChartsLabel';
28
28
  export type { ZoomData, ZoomFilterMode, ZoomSliderShowTooltip, ZoomOptions, ZoomSliderOptions } from '@mui/x-charts/internals';
29
+ export * from "./context/index.js";
29
30
  export * from "./hooks/index.js";
30
31
  export * from "./Heatmap/index.js";
31
- export * from "./ChartContainerPro/index.js";
32
+ export { ChartContainerPro } from "./ChartContainerPro/index.js";
33
+ export type { ChartContainerProProps } from "./ChartContainerPro/index.js";
32
34
  export * from "./ChartDataProviderPro/index.js";
33
35
  export * from "./ScatterChartPro/index.js";
34
36
  export * from "./BarChartPro/index.js";