@mui/x-charts-pro 8.18.0 → 8.19.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/BarChartPro/BarChartPro.js +6 -1
- package/CHANGELOG.md +113 -0
- package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +6 -3
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +1 -1
- package/LineChartPro/LineChartPro.js +6 -1
- package/SankeyChart/plugins/useSankeyHighlight.selectors.js +10 -10
- package/ScatterChartPro/ScatterChartPro.js +6 -1
- package/esm/BarChartPro/BarChartPro.js +6 -1
- package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +6 -3
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +3 -3
- package/esm/LineChartPro/LineChartPro.js +6 -1
- package/esm/SankeyChart/plugins/useSankeyHighlight.selectors.js +10 -10
- package/esm/ScatterChartPro/ScatterChartPro.js +6 -1
- package/esm/hooks/useFunnelSeries.js +3 -5
- package/esm/hooks/useHeatmapSeries.js +3 -5
- package/esm/hooks/useSankeySeries.js +3 -5
- package/esm/index.js +1 -1
- package/esm/internals/plugins/useChartProZoom/ZoomInteractionConfig.selectors.d.ts +4 -12
- package/esm/internals/plugins/useChartProZoom/ZoomInteractionConfig.selectors.js +5 -4
- package/esm/internals/plugins/useChartProZoom/ZoomInteractionConfig.types.d.ts +17 -2
- package/esm/internals/plugins/useChartProZoom/gestureHooks/usePanOnWheel.d.ts +8 -0
- package/esm/internals/plugins/useChartProZoom/gestureHooks/usePanOnWheel.js +98 -0
- package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoom.utils.d.ts +1 -1
- package/esm/internals/plugins/useChartProZoom/gestureHooks/useZoom.utils.js +2 -2
- package/esm/internals/plugins/useChartProZoom/initializeZoomInteractionConfig.d.ts +2 -1
- package/esm/internals/plugins/useChartProZoom/initializeZoomInteractionConfig.js +38 -5
- package/esm/internals/plugins/useChartProZoom/useChartProZoom.js +9 -3
- package/esm/internals/plugins/useChartProZoom/useChartProZoom.selectors.js +7 -6
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.js +2 -0
- package/hooks/useFunnelSeries.js +2 -5
- package/hooks/useHeatmapSeries.js +2 -5
- package/hooks/useSankeySeries.js +2 -5
- package/index.js +1 -1
- package/internals/plugins/useChartProZoom/ZoomInteractionConfig.selectors.d.ts +4 -12
- package/internals/plugins/useChartProZoom/ZoomInteractionConfig.selectors.js +4 -3
- package/internals/plugins/useChartProZoom/ZoomInteractionConfig.types.d.ts +17 -2
- package/internals/plugins/useChartProZoom/gestureHooks/usePanOnWheel.d.ts +8 -0
- package/internals/plugins/useChartProZoom/gestureHooks/usePanOnWheel.js +105 -0
- package/internals/plugins/useChartProZoom/gestureHooks/useZoom.utils.d.ts +1 -1
- package/internals/plugins/useChartProZoom/gestureHooks/useZoom.utils.js +2 -2
- package/internals/plugins/useChartProZoom/initializeZoomInteractionConfig.d.ts +2 -1
- package/internals/plugins/useChartProZoom/initializeZoomInteractionConfig.js +38 -5
- package/internals/plugins/useChartProZoom/useChartProZoom.js +9 -3
- package/internals/plugins/useChartProZoom/useChartProZoom.selectors.js +6 -5
- package/package.json +6 -6
- package/utils/index.d.ts +1 -0
- package/utils/index.js +16 -0
|
@@ -15,8 +15,9 @@ export type ZoomInteractionConfig = {
|
|
|
15
15
|
* Defines the interactions that trigger panning.
|
|
16
16
|
* - `drag`: Pans the chart when dragged with the mouse.
|
|
17
17
|
* - `pressAndDrag`: Pans the chart by pressing and holding, then dragging. Useful for avoiding conflicts with selection gestures.
|
|
18
|
+
* - `wheel`: Pans the chart when the mouse wheel is scrolled (horizontal by default).
|
|
18
19
|
*
|
|
19
|
-
* @default ['drag']
|
|
20
|
+
* @default ['drag', 'wheel']
|
|
20
21
|
*/
|
|
21
22
|
pan?: readonly (PanInteraction | PanInteraction['type'])[];
|
|
22
23
|
};
|
|
@@ -28,13 +29,14 @@ type Entry<T extends AnyInteraction> = { [K in T['type']]?: Omit<T, 'pointerMode
|
|
|
28
29
|
requiredKeys?: KeyboardKey[];
|
|
29
30
|
};
|
|
30
31
|
pointerMode?: PointerMode[];
|
|
32
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
31
33
|
} };
|
|
32
34
|
export type DefaultizedZoomInteractionConfig = {
|
|
33
35
|
zoom: Entry<ZoomInteraction>;
|
|
34
36
|
pan: Entry<PanInteraction>;
|
|
35
37
|
};
|
|
36
38
|
export type ZoomInteraction = WheelInteraction | PinchInteraction | TapAndDragInteraction | DoubleTapResetInteraction | BrushInteraction;
|
|
37
|
-
export type PanInteraction = DragInteraction | PressAndDragInteraction;
|
|
39
|
+
export type PanInteraction = DragInteraction | PressAndDragInteraction | WheelPanInteraction;
|
|
38
40
|
export type ZoomInteractionName = ZoomInteraction['type'];
|
|
39
41
|
export type PanInteractionName = PanInteraction['type'];
|
|
40
42
|
export type InteractionMode = Exclude<PointerMode, 'pen'>;
|
|
@@ -81,6 +83,17 @@ export type TapAndDragInteraction = Unpack<{
|
|
|
81
83
|
export type PressAndDragInteraction = Unpack<{
|
|
82
84
|
type: 'pressAndDrag';
|
|
83
85
|
} & AllModeProp & AllKeysProp>;
|
|
86
|
+
export type WheelPanInteraction = Unpack<{
|
|
87
|
+
type: 'wheel';
|
|
88
|
+
/**
|
|
89
|
+
* Defines which axes are affected by pan on wheel.
|
|
90
|
+
* - `'x'`: Only pan horizontally
|
|
91
|
+
* - `'y'`: Only pan vertically
|
|
92
|
+
* - `'xy'`: Pan both axes
|
|
93
|
+
* @default 'x'
|
|
94
|
+
*/
|
|
95
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
96
|
+
} & NoModeProp & AllKeysProp>;
|
|
84
97
|
export type DoubleTapResetInteraction = Unpack<{
|
|
85
98
|
type: 'doubleTapReset';
|
|
86
99
|
} & AllModeProp & AllKeysProp>;
|
|
@@ -91,6 +104,7 @@ export type AnyInteraction = {
|
|
|
91
104
|
type: string;
|
|
92
105
|
pointerMode?: InteractionMode;
|
|
93
106
|
requiredKeys?: KeyboardKey[];
|
|
107
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
94
108
|
};
|
|
95
109
|
export type AnyEntry = Omit<AnyInteraction, 'pointerMode'> & {
|
|
96
110
|
mouse: {
|
|
@@ -100,5 +114,6 @@ export type AnyEntry = Omit<AnyInteraction, 'pointerMode'> & {
|
|
|
100
114
|
requiredKeys?: KeyboardKey[];
|
|
101
115
|
};
|
|
102
116
|
pointerMode?: PointerMode[];
|
|
117
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
103
118
|
};
|
|
104
119
|
export {};
|
|
@@ -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 usePanOnWheel: ({
|
|
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,98 @@
|
|
|
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 { translateZoom } from "./useZoom.utils.js";
|
|
7
|
+
import { selectorPanInteractionConfig } from "../ZoomInteractionConfig.selectors.js";
|
|
8
|
+
export const usePanOnWheel = ({
|
|
9
|
+
store,
|
|
10
|
+
instance,
|
|
11
|
+
svgRef
|
|
12
|
+
}, setZoomDataCallback) => {
|
|
13
|
+
const drawingArea = useSelector(store, selectorChartDrawingArea);
|
|
14
|
+
const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
|
|
15
|
+
const startedOutsideRef = React.useRef(false);
|
|
16
|
+
const startedOutsideTimeoutRef = React.useRef(null);
|
|
17
|
+
const config = useSelector(store, selectorPanInteractionConfig, 'wheel');
|
|
18
|
+
const isPanOnWheelEnabled = Object.keys(optionsLookup).length > 0 && Boolean(config);
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
if (!isPanOnWheelEnabled) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
instance.updateZoomInteractionListeners('panTurnWheel', {
|
|
24
|
+
requiredKeys: config.requiredKeys
|
|
25
|
+
});
|
|
26
|
+
}, [config, isPanOnWheelEnabled, instance]);
|
|
27
|
+
|
|
28
|
+
// Add event for chart pan on wheel
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
const element = svgRef.current;
|
|
31
|
+
const accumulatedChange = {
|
|
32
|
+
x: 0,
|
|
33
|
+
y: 0
|
|
34
|
+
};
|
|
35
|
+
if (element === null || !isPanOnWheelEnabled) {
|
|
36
|
+
return () => {};
|
|
37
|
+
}
|
|
38
|
+
const rafThrottledSetZoomData = rafThrottle(setZoomDataCallback);
|
|
39
|
+
const wheelHandler = instance.addInteractionListener('panTurnWheel', event => {
|
|
40
|
+
const point = getSVGPoint(element, {
|
|
41
|
+
clientX: event.detail.centroid.x,
|
|
42
|
+
clientY: event.detail.centroid.y
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// This prevents a pan event from being triggered when the mouse is outside the chart area.
|
|
46
|
+
// The timeout is used to prevent an weird behavior where if the mouse is outside but enters due to
|
|
47
|
+
// scrolling, then the pan event is triggered.
|
|
48
|
+
if (startedOutsideRef.current || !instance.isPointInside(point.x, point.y)) {
|
|
49
|
+
startedOutsideRef.current = true;
|
|
50
|
+
if (startedOutsideTimeoutRef.current) {
|
|
51
|
+
clearTimeout(startedOutsideTimeoutRef.current);
|
|
52
|
+
}
|
|
53
|
+
startedOutsideTimeoutRef.current = setTimeout(() => {
|
|
54
|
+
startedOutsideRef.current = false;
|
|
55
|
+
startedOutsideTimeoutRef.current = null;
|
|
56
|
+
}, 100);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
event.detail.srcEvent.preventDefault();
|
|
60
|
+
const allowedDirection = config?.allowedDirection ?? 'x';
|
|
61
|
+
if (event.detail.deltaX === 0 && event.detail.deltaY === 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
accumulatedChange.x += event.detail.deltaX;
|
|
65
|
+
accumulatedChange.y += event.detail.deltaY;
|
|
66
|
+
rafThrottledSetZoomData(prev => {
|
|
67
|
+
const x = accumulatedChange.x;
|
|
68
|
+
const y = accumulatedChange.y;
|
|
69
|
+
accumulatedChange.x = 0;
|
|
70
|
+
accumulatedChange.y = 0;
|
|
71
|
+
let movementX = 0;
|
|
72
|
+
let movementY = 0;
|
|
73
|
+
if (allowedDirection === 'x' || allowedDirection === 'xy') {
|
|
74
|
+
movementX = -x;
|
|
75
|
+
}
|
|
76
|
+
if (allowedDirection === 'y' || allowedDirection === 'xy') {
|
|
77
|
+
movementY = y;
|
|
78
|
+
}
|
|
79
|
+
if (movementX === 0 && movementY === 0) {
|
|
80
|
+
return prev;
|
|
81
|
+
}
|
|
82
|
+
return translateZoom(prev, {
|
|
83
|
+
x: movementX,
|
|
84
|
+
y: movementY
|
|
85
|
+
}, drawingArea, optionsLookup, allowedDirection);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return () => {
|
|
89
|
+
wheelHandler.cleanup();
|
|
90
|
+
if (startedOutsideTimeoutRef.current) {
|
|
91
|
+
clearTimeout(startedOutsideTimeoutRef.current);
|
|
92
|
+
startedOutsideTimeoutRef.current = null;
|
|
93
|
+
}
|
|
94
|
+
startedOutsideRef.current = false;
|
|
95
|
+
rafThrottledSetZoomData.clear();
|
|
96
|
+
};
|
|
97
|
+
}, [svgRef, drawingArea, isPanOnWheelEnabled, optionsLookup, instance, setZoomDataCallback, store, config]);
|
|
98
|
+
};
|
|
@@ -46,4 +46,4 @@ export declare function translateZoom(initialZoomData: readonly ZoomData[], move
|
|
|
46
46
|
}, drawingArea: {
|
|
47
47
|
width: number;
|
|
48
48
|
height: number;
|
|
49
|
-
}, optionsLookup: Record<string | number, DefaultizedZoomOptions
|
|
49
|
+
}, optionsLookup: Record<string | number, DefaultizedZoomOptions>, filterMode?: 'x' | 'y' | 'xy'): ZoomData[];
|
|
@@ -104,10 +104,10 @@ export function getVerticalCenterRatio(point, area, reverse) {
|
|
|
104
104
|
/**
|
|
105
105
|
* Translate the zoom data by a given movement.
|
|
106
106
|
*/
|
|
107
|
-
export function translateZoom(initialZoomData, movement, drawingArea, optionsLookup) {
|
|
107
|
+
export function translateZoom(initialZoomData, movement, drawingArea, optionsLookup, filterMode = 'xy') {
|
|
108
108
|
return initialZoomData.map(zoom => {
|
|
109
109
|
const options = optionsLookup[zoom.axisId];
|
|
110
|
-
if (!options || !options.panning) {
|
|
110
|
+
if (!options || !options.panning || options.axisDirection === 'x' && filterMode === 'y' || options.axisDirection === 'y' && filterMode === 'x') {
|
|
111
111
|
return zoom;
|
|
112
112
|
}
|
|
113
113
|
const min = zoom.start;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import type { AxisId, DefaultizedZoomOptions } from '@mui/x-charts/internals';
|
|
1
2
|
import type { ZoomInteractionConfig, DefaultizedZoomInteractionConfig } from "./ZoomInteractionConfig.types.js";
|
|
2
|
-
export declare const initializeZoomInteractionConfig: (zoomInteractionConfig?: ZoomInteractionConfig) => DefaultizedZoomInteractionConfig;
|
|
3
|
+
export declare const initializeZoomInteractionConfig: (zoomInteractionConfig?: ZoomInteractionConfig, optionsLookup?: Record<AxisId, DefaultizedZoomOptions>) => DefaultizedZoomInteractionConfig;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
export const initializeZoomInteractionConfig = zoomInteractionConfig => {
|
|
3
|
+
export const initializeZoomInteractionConfig = (zoomInteractionConfig, optionsLookup) => {
|
|
4
4
|
const defaultizedConfig = {
|
|
5
5
|
zoom: {},
|
|
6
6
|
pan: {}
|
|
7
7
|
};
|
|
8
|
+
|
|
9
|
+
// Config for zoom
|
|
8
10
|
if (!zoomInteractionConfig?.zoom) {
|
|
9
11
|
defaultizedConfig.zoom = {
|
|
10
12
|
wheel: {
|
|
@@ -21,8 +23,10 @@ export const initializeZoomInteractionConfig = zoomInteractionConfig => {
|
|
|
21
23
|
}
|
|
22
24
|
};
|
|
23
25
|
} else {
|
|
24
|
-
defaultizedConfig.zoom = initializeFor(zoomInteractionConfig.zoom);
|
|
26
|
+
defaultizedConfig.zoom = initializeFor('zoom', zoomInteractionConfig.zoom);
|
|
25
27
|
}
|
|
28
|
+
|
|
29
|
+
// Config for pan
|
|
26
30
|
if (!zoomInteractionConfig?.pan) {
|
|
27
31
|
defaultizedConfig.pan = {
|
|
28
32
|
drag: {
|
|
@@ -32,12 +36,37 @@ export const initializeZoomInteractionConfig = zoomInteractionConfig => {
|
|
|
32
36
|
touch: {}
|
|
33
37
|
}
|
|
34
38
|
};
|
|
39
|
+
let hasXZoom = false;
|
|
40
|
+
let hasYZoom = false;
|
|
41
|
+
if (optionsLookup) {
|
|
42
|
+
Object.values(optionsLookup).forEach(options => {
|
|
43
|
+
if (options.axisDirection === 'x') {
|
|
44
|
+
hasXZoom = true;
|
|
45
|
+
}
|
|
46
|
+
if (options.axisDirection === 'y') {
|
|
47
|
+
hasYZoom = true;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Only add pan on wheel if the x-axis can pan (has zoom enabled) but the y-axis cannot
|
|
53
|
+
// This provides a consistent horizontal panning experience that aligns with typical scrolling behavior
|
|
54
|
+
// When both axes can pan, we avoid wheel interactions to prevent conflicts with vertical scrolling
|
|
55
|
+
if (hasXZoom && !hasYZoom) {
|
|
56
|
+
defaultizedConfig.pan.wheel = {
|
|
57
|
+
type: 'wheel',
|
|
58
|
+
requiredKeys: [],
|
|
59
|
+
allowedDirection: 'x',
|
|
60
|
+
mouse: {},
|
|
61
|
+
touch: {}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
35
64
|
} else {
|
|
36
|
-
defaultizedConfig.pan = initializeFor(zoomInteractionConfig.pan);
|
|
65
|
+
defaultizedConfig.pan = initializeFor('pan', zoomInteractionConfig.pan);
|
|
37
66
|
}
|
|
38
67
|
return defaultizedConfig;
|
|
39
68
|
};
|
|
40
|
-
function initializeFor(zoomInteractionConfig) {
|
|
69
|
+
function initializeFor(interactionType, zoomInteractionConfig) {
|
|
41
70
|
// We aggregate interactions by type
|
|
42
71
|
const aggregation = zoomInteractionConfig.reduce((acc, interaction) => {
|
|
43
72
|
if (typeof interaction === 'string') {
|
|
@@ -57,7 +86,8 @@ function initializeFor(zoomInteractionConfig) {
|
|
|
57
86
|
acc[type].push({
|
|
58
87
|
type,
|
|
59
88
|
pointerMode: interaction.pointerMode,
|
|
60
|
-
requiredKeys: interaction.requiredKeys
|
|
89
|
+
requiredKeys: interaction.requiredKeys,
|
|
90
|
+
allowedDirection: interaction.allowedDirection
|
|
61
91
|
});
|
|
62
92
|
return acc;
|
|
63
93
|
}, {});
|
|
@@ -81,6 +111,9 @@ function initializeFor(zoomInteractionConfig) {
|
|
|
81
111
|
requiredKeys: lastTouch?.requiredKeys ?? []
|
|
82
112
|
} : {}
|
|
83
113
|
};
|
|
114
|
+
if (type === 'wheel' && interactionType === 'pan') {
|
|
115
|
+
acc[type].allowedDirection = lastEmpty?.allowedDirection ?? 'x';
|
|
116
|
+
}
|
|
84
117
|
}
|
|
85
118
|
return acc;
|
|
86
119
|
}
|
|
@@ -6,10 +6,12 @@ import { useSelector, selectorChartZoomOptionsLookup, createZoomLookup, selector
|
|
|
6
6
|
import debounce from '@mui/utils/debounce';
|
|
7
7
|
import { useEffectAfterFirstRender } from '@mui/x-internals/useEffectAfterFirstRender';
|
|
8
8
|
import { useEventCallback } from '@mui/material/utils';
|
|
9
|
+
import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
|
|
9
10
|
import { calculateZoom } from "./calculateZoom.js";
|
|
10
11
|
import { useZoomOnWheel } from "./gestureHooks/useZoomOnWheel.js";
|
|
11
12
|
import { useZoomOnPinch } from "./gestureHooks/useZoomOnPinch.js";
|
|
12
13
|
import { usePanOnDrag } from "./gestureHooks/usePanOnDrag.js";
|
|
14
|
+
import { usePanOnWheel } from "./gestureHooks/usePanOnWheel.js";
|
|
13
15
|
import { useZoomOnTapAndDrag } from "./gestureHooks/useZoomOnTapAndDrag.js";
|
|
14
16
|
import { usePanOnPressAndDrag } from "./gestureHooks/usePanOnPressAndDrag.js";
|
|
15
17
|
import { useZoomOnBrush } from "./gestureHooks/useZoomOnBrush.js";
|
|
@@ -30,9 +32,9 @@ export const useChartProZoom = pluginData => {
|
|
|
30
32
|
const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);
|
|
31
33
|
useEffectAfterFirstRender(() => {
|
|
32
34
|
store.set('zoom', _extends({}, store.state.zoom, {
|
|
33
|
-
zoomInteractionConfig: initializeZoomInteractionConfig(zoomInteractionConfig)
|
|
35
|
+
zoomInteractionConfig: initializeZoomInteractionConfig(zoomInteractionConfig, optionsLookup)
|
|
34
36
|
}));
|
|
35
|
-
}, [store, zoomInteractionConfig]);
|
|
37
|
+
}, [store, zoomInteractionConfig, optionsLookup]);
|
|
36
38
|
|
|
37
39
|
// This is debounced. We want to run it only once after the interaction ends.
|
|
38
40
|
const removeIsInteracting = React.useMemo(() => debounce(() => store.set('zoom', _extends({}, store.state.zoom, {
|
|
@@ -55,6 +57,9 @@ export const useChartProZoom = pluginData => {
|
|
|
55
57
|
}, [store, paramsZoomData, removeIsInteracting]);
|
|
56
58
|
const setZoomDataCallback = React.useCallback(zoomData => {
|
|
57
59
|
const newZoomData = typeof zoomData === 'function' ? zoomData([...store.state.zoom.zoomData]) : zoomData;
|
|
60
|
+
if (isDeepEqual(store.state.zoom.zoomData, newZoomData)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
58
63
|
onZoomChange(newZoomData);
|
|
59
64
|
if (store.state.zoom.isControlled) {
|
|
60
65
|
store.set('zoom', _extends({}, store.state.zoom, {
|
|
@@ -113,6 +118,7 @@ export const useChartProZoom = pluginData => {
|
|
|
113
118
|
// Add events
|
|
114
119
|
usePanOnDrag(pluginData, setZoomDataCallback);
|
|
115
120
|
usePanOnPressAndDrag(pluginData, setZoomDataCallback);
|
|
121
|
+
usePanOnWheel(pluginData, setZoomDataCallback);
|
|
116
122
|
useZoomOnWheel(pluginData, setZoomDataCallback);
|
|
117
123
|
useZoomOnPinch(pluginData, setZoomDataCallback);
|
|
118
124
|
useZoomOnTapAndDrag(pluginData, setZoomDataCallback);
|
|
@@ -164,7 +170,7 @@ useChartProZoom.getInitialState = params => {
|
|
|
164
170
|
zoomData: initializeZoomData(optionsLookup, userZoomData),
|
|
165
171
|
isInteracting: false,
|
|
166
172
|
isControlled: zoomData !== undefined,
|
|
167
|
-
zoomInteractionConfig: initializeZoomInteractionConfig(params.zoomInteractionConfig)
|
|
173
|
+
zoomInteractionConfig: initializeZoomInteractionConfig(params.zoomInteractionConfig, optionsLookup)
|
|
168
174
|
}
|
|
169
175
|
};
|
|
170
176
|
};
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { createSelector
|
|
1
|
+
import { createSelector } from '@mui/x-internals/store';
|
|
2
|
+
import { selectorChartZoomMap, selectorChartZoomOptionsLookup } from '@mui/x-charts/internals';
|
|
2
3
|
export const selectorChartZoomState = state => state.zoom;
|
|
3
|
-
export const selectorChartZoomIsInteracting = createSelector(
|
|
4
|
-
export const selectorChartZoomIsEnabled = createSelector(
|
|
5
|
-
export const selectorChartAxisZoomData = createSelector(
|
|
6
|
-
export const selectorChartCanZoomOut = createSelector(
|
|
4
|
+
export const selectorChartZoomIsInteracting = createSelector(selectorChartZoomState, zoom => zoom.isInteracting);
|
|
5
|
+
export const selectorChartZoomIsEnabled = createSelector(selectorChartZoomOptionsLookup, optionsLookup => Object.keys(optionsLookup).length > 0);
|
|
6
|
+
export const selectorChartAxisZoomData = createSelector(selectorChartZoomMap, (zoomMap, axisId) => zoomMap?.get(axisId));
|
|
7
|
+
export const selectorChartCanZoomOut = createSelector(selectorChartZoomState, selectorChartZoomOptionsLookup, (zoomState, zoomOptions) => {
|
|
7
8
|
return zoomState.zoomData.every(zoomData => {
|
|
8
9
|
const span = zoomData.end - zoomData.start;
|
|
9
10
|
const options = zoomOptions[zoomData.axisId];
|
|
10
11
|
return zoomData.start === options.minStart && zoomData.end === options.maxEnd || span === options.maxSpan;
|
|
11
12
|
});
|
|
12
13
|
});
|
|
13
|
-
export const selectorChartCanZoomIn = createSelector(
|
|
14
|
+
export const selectorChartCanZoomIn = createSelector(selectorChartZoomState, selectorChartZoomOptionsLookup, (zoomState, zoomOptions) => {
|
|
14
15
|
return zoomState.zoomData.every(zoomData => {
|
|
15
16
|
const span = zoomData.end - zoomData.start;
|
|
16
17
|
const options = zoomOptions[zoomData.axisId];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@mui/x-charts/utils';
|
package/hooks/useFunnelSeries.js
CHANGED
|
@@ -7,9 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.useFunnelSeries = useFunnelSeries;
|
|
8
8
|
exports.useFunnelSeriesContext = useFunnelSeriesContext;
|
|
9
9
|
var _internals = require("@mui/x-charts/internals");
|
|
10
|
-
const useSelectorSeries = (0, _internals.createSeriesSelectorsOfType)('funnel');
|
|
11
|
-
const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('funnel');
|
|
12
|
-
|
|
13
10
|
/**
|
|
14
11
|
* Get access to the internal state of funnel series.
|
|
15
12
|
*
|
|
@@ -33,7 +30,7 @@ const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('
|
|
|
33
30
|
*/
|
|
34
31
|
|
|
35
32
|
function useFunnelSeries(seriesIds) {
|
|
36
|
-
return
|
|
33
|
+
return (0, _internals.useSeriesOfType)('funnel', seriesIds);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
@@ -44,5 +41,5 @@ function useFunnelSeries(seriesIds) {
|
|
|
44
41
|
* @returns the funnel series
|
|
45
42
|
*/
|
|
46
43
|
function useFunnelSeriesContext() {
|
|
47
|
-
return
|
|
44
|
+
return (0, _internals.useAllSeriesOfType)('funnel');
|
|
48
45
|
}
|
|
@@ -7,9 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.useHeatmapSeries = useHeatmapSeries;
|
|
8
8
|
exports.useHeatmapSeriesContext = useHeatmapSeriesContext;
|
|
9
9
|
var _internals = require("@mui/x-charts/internals");
|
|
10
|
-
const useSelectorSeries = (0, _internals.createSeriesSelectorsOfType)('heatmap');
|
|
11
|
-
const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('heatmap');
|
|
12
|
-
|
|
13
10
|
/**
|
|
14
11
|
* Get access to the internal state of heatmap series.
|
|
15
12
|
*
|
|
@@ -33,7 +30,7 @@ const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('
|
|
|
33
30
|
*/
|
|
34
31
|
|
|
35
32
|
function useHeatmapSeries(seriesIds) {
|
|
36
|
-
return
|
|
33
|
+
return (0, _internals.useSeriesOfType)('heatmap', seriesIds);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
@@ -44,5 +41,5 @@ function useHeatmapSeries(seriesIds) {
|
|
|
44
41
|
* @returns the heatmap series
|
|
45
42
|
*/
|
|
46
43
|
function useHeatmapSeriesContext() {
|
|
47
|
-
return
|
|
44
|
+
return (0, _internals.useAllSeriesOfType)('heatmap');
|
|
48
45
|
}
|
package/hooks/useSankeySeries.js
CHANGED
|
@@ -7,9 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.useSankeySeries = useSankeySeries;
|
|
8
8
|
exports.useSankeySeriesContext = useSankeySeriesContext;
|
|
9
9
|
var _internals = require("@mui/x-charts/internals");
|
|
10
|
-
const useSelectorSeries = (0, _internals.createSeriesSelectorsOfType)('sankey');
|
|
11
|
-
const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('sankey');
|
|
12
|
-
|
|
13
10
|
/**
|
|
14
11
|
* Get access to the internal state of sankey series.
|
|
15
12
|
*
|
|
@@ -33,7 +30,7 @@ const useSelectorSeriesContext = (0, _internals.createAllSeriesSelectorOfType)('
|
|
|
33
30
|
*/
|
|
34
31
|
|
|
35
32
|
function useSankeySeries(seriesIds) {
|
|
36
|
-
return
|
|
33
|
+
return (0, _internals.useSeriesOfType)('sankey', seriesIds);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
@@ -44,5 +41,5 @@ function useSankeySeries(seriesIds) {
|
|
|
44
41
|
* @returns the sankey series
|
|
45
42
|
*/
|
|
46
43
|
function useSankeySeriesContext() {
|
|
47
|
-
return
|
|
44
|
+
return (0, _internals.useAllSeriesOfType)('sankey');
|
|
48
45
|
}
|
package/index.js
CHANGED
|
@@ -8,10 +8,11 @@ export declare const selectorZoomInteractionConfig: (args_0: import("@mui/x-char
|
|
|
8
8
|
requiredKeys?: import("@mui/x-internal-gestures/core").KeyboardKey[];
|
|
9
9
|
};
|
|
10
10
|
pointerMode?: import("@mui/x-internal-gestures/core").PointerMode[];
|
|
11
|
+
allowedDirection?: "x" | "y" | "xy";
|
|
11
12
|
}) | null;
|
|
12
13
|
export declare const selectorPanInteractionConfig: (args_0: import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types").UseChartExperimentalFeaturesState & 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<{}> & {
|
|
13
14
|
cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
|
|
14
|
-
}, interactionName: "drag" | "pressAndDrag") => (Omit<import("./ZoomInteractionConfig.types.js").PanInteraction, "pointerMode"> & {
|
|
15
|
+
}, interactionName: "wheel" | "drag" | "pressAndDrag") => (Omit<import("./ZoomInteractionConfig.types.js").PanInteraction, "pointerMode"> & {
|
|
15
16
|
mouse: {
|
|
16
17
|
requiredKeys?: import("@mui/x-internal-gestures/core").KeyboardKey[];
|
|
17
18
|
};
|
|
@@ -19,15 +20,6 @@ export declare const selectorPanInteractionConfig: (args_0: import("@mui/x-chart
|
|
|
19
20
|
requiredKeys?: import("@mui/x-internal-gestures/core").KeyboardKey[];
|
|
20
21
|
};
|
|
21
22
|
pointerMode?: import("@mui/x-internal-gestures/core").PointerMode[];
|
|
23
|
+
allowedDirection?: "x" | "y" | "xy";
|
|
22
24
|
}) | null;
|
|
23
|
-
export declare const selectorIsZoomBrushEnabled: (args_0:
|
|
24
|
-
cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
|
|
25
|
-
}) => false | (Omit<import("./ZoomInteractionConfig.types.js").ZoomInteraction, "pointerMode"> & {
|
|
26
|
-
mouse: {
|
|
27
|
-
requiredKeys?: import("@mui/x-internal-gestures/core").KeyboardKey[];
|
|
28
|
-
};
|
|
29
|
-
touch: {
|
|
30
|
-
requiredKeys?: import("@mui/x-internal-gestures/core").KeyboardKey[];
|
|
31
|
-
};
|
|
32
|
-
pointerMode?: import("@mui/x-internal-gestures/core").PointerMode[];
|
|
33
|
-
});
|
|
25
|
+
export declare const selectorIsZoomBrushEnabled: (args_0: {}, zoomInteractionConfig: any) => any;
|
|
@@ -4,8 +4,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.selectorZoomInteractionConfig = exports.selectorPanInteractionConfig = exports.selectorIsZoomBrushEnabled = void 0;
|
|
7
|
+
var _store = require("@mui/x-internals/store");
|
|
7
8
|
var _internals = require("@mui/x-charts/internals");
|
|
8
9
|
var _useChartProZoom = require("./useChartProZoom.selectors");
|
|
9
|
-
const selectorZoomInteractionConfig = exports.selectorZoomInteractionConfig = (0,
|
|
10
|
-
const selectorPanInteractionConfig = exports.selectorPanInteractionConfig = (0,
|
|
11
|
-
const selectorIsZoomBrushEnabled = exports.selectorIsZoomBrushEnabled = (0,
|
|
10
|
+
const selectorZoomInteractionConfig = exports.selectorZoomInteractionConfig = (0, _store.createSelector)(_useChartProZoom.selectorChartZoomState, (zoomState, interactionName) => zoomState.zoomInteractionConfig.zoom[interactionName] ?? null);
|
|
11
|
+
const selectorPanInteractionConfig = exports.selectorPanInteractionConfig = (0, _store.createSelector)(_useChartProZoom.selectorChartZoomState, (zoomState, interactionName) => zoomState.zoomInteractionConfig.pan[interactionName] ?? null);
|
|
12
|
+
const selectorIsZoomBrushEnabled = exports.selectorIsZoomBrushEnabled = (0, _store.createSelector)(_internals.selectorChartZoomOptionsLookup, state => selectorZoomInteractionConfig(state, 'brush'), (zoomOptions, zoomInteractionConfig) => Object.keys(zoomOptions).length > 0 && zoomInteractionConfig || false);
|
|
@@ -15,8 +15,9 @@ export type ZoomInteractionConfig = {
|
|
|
15
15
|
* Defines the interactions that trigger panning.
|
|
16
16
|
* - `drag`: Pans the chart when dragged with the mouse.
|
|
17
17
|
* - `pressAndDrag`: Pans the chart by pressing and holding, then dragging. Useful for avoiding conflicts with selection gestures.
|
|
18
|
+
* - `wheel`: Pans the chart when the mouse wheel is scrolled (horizontal by default).
|
|
18
19
|
*
|
|
19
|
-
* @default ['drag']
|
|
20
|
+
* @default ['drag', 'wheel']
|
|
20
21
|
*/
|
|
21
22
|
pan?: readonly (PanInteraction | PanInteraction['type'])[];
|
|
22
23
|
};
|
|
@@ -28,13 +29,14 @@ type Entry<T extends AnyInteraction> = { [K in T['type']]?: Omit<T, 'pointerMode
|
|
|
28
29
|
requiredKeys?: KeyboardKey[];
|
|
29
30
|
};
|
|
30
31
|
pointerMode?: PointerMode[];
|
|
32
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
31
33
|
} };
|
|
32
34
|
export type DefaultizedZoomInteractionConfig = {
|
|
33
35
|
zoom: Entry<ZoomInteraction>;
|
|
34
36
|
pan: Entry<PanInteraction>;
|
|
35
37
|
};
|
|
36
38
|
export type ZoomInteraction = WheelInteraction | PinchInteraction | TapAndDragInteraction | DoubleTapResetInteraction | BrushInteraction;
|
|
37
|
-
export type PanInteraction = DragInteraction | PressAndDragInteraction;
|
|
39
|
+
export type PanInteraction = DragInteraction | PressAndDragInteraction | WheelPanInteraction;
|
|
38
40
|
export type ZoomInteractionName = ZoomInteraction['type'];
|
|
39
41
|
export type PanInteractionName = PanInteraction['type'];
|
|
40
42
|
export type InteractionMode = Exclude<PointerMode, 'pen'>;
|
|
@@ -81,6 +83,17 @@ export type TapAndDragInteraction = Unpack<{
|
|
|
81
83
|
export type PressAndDragInteraction = Unpack<{
|
|
82
84
|
type: 'pressAndDrag';
|
|
83
85
|
} & AllModeProp & AllKeysProp>;
|
|
86
|
+
export type WheelPanInteraction = Unpack<{
|
|
87
|
+
type: 'wheel';
|
|
88
|
+
/**
|
|
89
|
+
* Defines which axes are affected by pan on wheel.
|
|
90
|
+
* - `'x'`: Only pan horizontally
|
|
91
|
+
* - `'y'`: Only pan vertically
|
|
92
|
+
* - `'xy'`: Pan both axes
|
|
93
|
+
* @default 'x'
|
|
94
|
+
*/
|
|
95
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
96
|
+
} & NoModeProp & AllKeysProp>;
|
|
84
97
|
export type DoubleTapResetInteraction = Unpack<{
|
|
85
98
|
type: 'doubleTapReset';
|
|
86
99
|
} & AllModeProp & AllKeysProp>;
|
|
@@ -91,6 +104,7 @@ export type AnyInteraction = {
|
|
|
91
104
|
type: string;
|
|
92
105
|
pointerMode?: InteractionMode;
|
|
93
106
|
requiredKeys?: KeyboardKey[];
|
|
107
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
94
108
|
};
|
|
95
109
|
export type AnyEntry = Omit<AnyInteraction, 'pointerMode'> & {
|
|
96
110
|
mouse: {
|
|
@@ -100,5 +114,6 @@ export type AnyEntry = Omit<AnyInteraction, 'pointerMode'> & {
|
|
|
100
114
|
requiredKeys?: KeyboardKey[];
|
|
101
115
|
};
|
|
102
116
|
pointerMode?: PointerMode[];
|
|
117
|
+
allowedDirection?: 'x' | 'y' | 'xy';
|
|
103
118
|
};
|
|
104
119
|
export {};
|
|
@@ -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 usePanOnWheel: ({
|
|
5
|
+
store,
|
|
6
|
+
instance,
|
|
7
|
+
svgRef
|
|
8
|
+
}: Pick<Parameters<ChartPlugin<UseChartProZoomSignature>>[0], "store" | "instance" | "svgRef">, setZoomDataCallback: React.Dispatch<ZoomData[] | ((prev: ZoomData[]) => ZoomData[])>) => void;
|