@mui/x-charts 7.13.0 → 7.14.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 (88) hide show
  1. package/BarChart/BarPlot.js +4 -3
  2. package/BarChart/extremums.js +42 -7
  3. package/CHANGELOG.md +82 -2
  4. package/ChartContainer/useChartContainerProps.js +1 -1
  5. package/ChartContainer/useDefaultizeAxis.d.ts +2 -1
  6. package/ChartContainer/useDefaultizeAxis.js +16 -5
  7. package/ChartsAxisHighlight/ChartsAxisHighlight.js +23 -9
  8. package/ChartsGrid/ChartsGrid.js +6 -4
  9. package/ChartsXAxis/ChartsXAxis.js +14 -3
  10. package/ChartsYAxis/ChartsYAxis.js +8 -2
  11. package/LineChart/extremums.js +20 -4
  12. package/ScatterChart/extremums.js +26 -10
  13. package/context/CartesianProvider/Cartesian.types.d.ts +59 -0
  14. package/context/CartesianProvider/Cartesian.types.js +5 -0
  15. package/context/CartesianProvider/CartesianContext.d.ts +1 -22
  16. package/context/CartesianProvider/CartesianProvider.d.ts +1 -21
  17. package/context/CartesianProvider/CartesianProvider.js +2 -5
  18. package/context/CartesianProvider/computeValue.d.ts +18 -31
  19. package/context/CartesianProvider/computeValue.js +20 -23
  20. package/context/CartesianProvider/getAxisExtremum.d.ts +3 -2
  21. package/context/CartesianProvider/getAxisExtremum.js +11 -5
  22. package/context/CartesianProvider/index.d.ts +1 -0
  23. package/context/CartesianProvider/index.js +12 -0
  24. package/context/CartesianProvider/useCartesianContext.d.ts +1 -1
  25. package/context/CartesianProvider/zoom.d.ts +10 -0
  26. package/context/CartesianProvider/zoom.js +26 -0
  27. package/context/DrawingProvider.d.ts +7 -2
  28. package/context/DrawingProvider.js +11 -3
  29. package/context/PluginProvider/ExtremumGetter.types.d.ts +11 -1
  30. package/esm/BarChart/BarPlot.js +4 -3
  31. package/esm/BarChart/extremums.js +42 -7
  32. package/esm/ChartContainer/useChartContainerProps.js +1 -1
  33. package/esm/ChartContainer/useDefaultizeAxis.js +16 -5
  34. package/esm/ChartsAxisHighlight/ChartsAxisHighlight.js +23 -9
  35. package/esm/ChartsGrid/ChartsGrid.js +6 -4
  36. package/esm/ChartsXAxis/ChartsXAxis.js +14 -3
  37. package/esm/ChartsYAxis/ChartsYAxis.js +8 -2
  38. package/esm/LineChart/extremums.js +20 -4
  39. package/esm/ScatterChart/extremums.js +26 -10
  40. package/esm/context/CartesianProvider/Cartesian.types.js +1 -0
  41. package/esm/context/CartesianProvider/CartesianProvider.js +2 -5
  42. package/esm/context/CartesianProvider/computeValue.js +20 -23
  43. package/esm/context/CartesianProvider/getAxisExtremum.js +11 -5
  44. package/esm/context/CartesianProvider/index.js +1 -0
  45. package/esm/context/CartesianProvider/zoom.js +19 -0
  46. package/esm/context/DrawingProvider.js +11 -3
  47. package/esm/hooks/useAxisEvents.js +3 -1
  48. package/esm/internals/domUtils.js +16 -3
  49. package/esm/internals/index.js +3 -0
  50. package/esm/models/axis.js +5 -0
  51. package/esm/tests/firePointerEvent.js +35 -0
  52. package/hooks/useAxisEvents.js +3 -1
  53. package/index.js +1 -1
  54. package/internals/domUtils.d.ts +2 -0
  55. package/internals/domUtils.js +19 -5
  56. package/internals/index.d.ts +2 -0
  57. package/internals/index.js +17 -1
  58. package/models/axis.d.ts +4 -0
  59. package/models/axis.js +5 -0
  60. package/modern/BarChart/BarPlot.js +4 -3
  61. package/modern/BarChart/extremums.js +42 -7
  62. package/modern/ChartContainer/useChartContainerProps.js +1 -1
  63. package/modern/ChartContainer/useDefaultizeAxis.js +16 -5
  64. package/modern/ChartsAxisHighlight/ChartsAxisHighlight.js +23 -9
  65. package/modern/ChartsGrid/ChartsGrid.js +6 -4
  66. package/modern/ChartsXAxis/ChartsXAxis.js +14 -3
  67. package/modern/ChartsYAxis/ChartsYAxis.js +8 -2
  68. package/modern/LineChart/extremums.js +20 -4
  69. package/modern/ScatterChart/extremums.js +26 -10
  70. package/modern/context/CartesianProvider/Cartesian.types.js +1 -0
  71. package/modern/context/CartesianProvider/CartesianProvider.js +2 -5
  72. package/modern/context/CartesianProvider/computeValue.js +20 -23
  73. package/modern/context/CartesianProvider/getAxisExtremum.js +11 -5
  74. package/modern/context/CartesianProvider/index.js +1 -0
  75. package/modern/context/CartesianProvider/zoom.js +19 -0
  76. package/modern/context/DrawingProvider.js +11 -3
  77. package/modern/hooks/useAxisEvents.js +3 -1
  78. package/modern/index.js +1 -1
  79. package/modern/internals/domUtils.js +16 -3
  80. package/modern/internals/index.js +3 -0
  81. package/modern/models/axis.js +5 -0
  82. package/modern/tests/firePointerEvent.js +35 -0
  83. package/package.json +4 -4
  84. package/tests/firePointerEvent.js +42 -0
  85. package/context/CartesianProvider/normalizeAxis.d.ts +0 -5
  86. package/context/CartesianProvider/normalizeAxis.js +0 -23
  87. package/esm/context/CartesianProvider/normalizeAxis.js +0 -15
  88. package/modern/context/CartesianProvider/normalizeAxis.js +0 -15
@@ -191,6 +191,7 @@ function BarPlot(props) {
191
191
  barLabel
192
192
  } = props,
193
193
  other = _objectWithoutPropertiesLoose(props, _excluded);
194
+ const withoutBorderRadius = !borderRadius || borderRadius <= 0;
194
195
  const transition = useTransition(completedData, {
195
196
  keys: bar => `${bar.seriesId}-${bar.dataIndex}`,
196
197
  from: leaveStyle,
@@ -199,7 +200,7 @@ function BarPlot(props) {
199
200
  update: enterStyle,
200
201
  immediate: skipAnimation
201
202
  });
202
- const maskTransition = useTransition(masksData, {
203
+ const maskTransition = useTransition(withoutBorderRadius ? [] : masksData, {
203
204
  keys: v => v.id,
204
205
  from: leaveStyle,
205
206
  leave: leaveStyle,
@@ -208,7 +209,7 @@ function BarPlot(props) {
208
209
  immediate: skipAnimation
209
210
  });
210
211
  return /*#__PURE__*/_jsxs(React.Fragment, {
211
- children: [maskTransition((style, {
212
+ children: [!withoutBorderRadius && maskTransition((style, {
212
213
  id,
213
214
  hasPositive,
214
215
  hasNegative,
@@ -242,7 +243,7 @@ function BarPlot(props) {
242
243
  }),
243
244
  style: style
244
245
  }));
245
- if (!borderRadius || borderRadius <= 0) {
246
+ if (withoutBorderRadius) {
246
247
  return barElement;
247
248
  }
248
249
  return /*#__PURE__*/_jsx("g", {
@@ -1,22 +1,57 @@
1
+ const createResult = (data, direction) => {
2
+ if (direction === 'x') {
3
+ return {
4
+ x: data,
5
+ y: null
6
+ };
7
+ }
8
+ return {
9
+ x: null,
10
+ y: data
11
+ };
12
+ };
1
13
  const getBaseExtremum = params => {
2
14
  const {
3
- axis
15
+ axis,
16
+ getFilters,
17
+ isDefaultAxis
4
18
  } = params;
5
- const minX = Math.min(...(axis.data ?? []));
6
- const maxX = Math.max(...(axis.data ?? []));
19
+ const filter = getFilters?.({
20
+ currentAxisId: axis.id,
21
+ isDefaultAxis
22
+ });
23
+ const data = filter ? axis.data?.filter((_, i) => filter({
24
+ x: null,
25
+ y: null
26
+ }, i)) : axis.data;
27
+ const minX = Math.min(...(data ?? []));
28
+ const maxX = Math.max(...(data ?? []));
7
29
  return [minX, maxX];
8
30
  };
9
- const getValueExtremum = params => {
31
+ const getValueExtremum = direction => params => {
10
32
  const {
11
33
  series,
12
34
  axis,
35
+ getFilters,
13
36
  isDefaultAxis
14
37
  } = params;
15
38
  return Object.keys(series).filter(seriesId => {
16
39
  const yAxisId = series[seriesId].yAxisId ?? series[seriesId].yAxisKey;
17
40
  return yAxisId === axis.id || isDefaultAxis && yAxisId === undefined;
18
41
  }).reduce((acc, seriesId) => {
19
- const [seriesMin, seriesMax] = series[seriesId].stackedData?.reduce((seriesAcc, values) => {
42
+ const {
43
+ stackedData
44
+ } = series[seriesId];
45
+ const filter = getFilters?.({
46
+ currentAxisId: axis.id,
47
+ isDefaultAxis,
48
+ seriesXAxisId: series[seriesId].xAxisId ?? series[seriesId].xAxisKey,
49
+ seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey
50
+ });
51
+ const [seriesMin, seriesMax] = stackedData?.reduce((seriesAcc, values, index) => {
52
+ if (filter && (!filter(createResult(values[0], direction), index) || !filter(createResult(values[1], direction), index))) {
53
+ return seriesAcc;
54
+ }
20
55
  return [Math.min(...values, seriesAcc[0]), Math.max(...values, seriesAcc[1])];
21
56
  }, [Infinity, -Infinity]) ?? [Infinity, -Infinity];
22
57
  return [Math.min(seriesMin, acc[0]), Math.max(seriesMax, acc[1])];
@@ -27,7 +62,7 @@ export const getExtremumX = params => {
27
62
  // Don't think it's a problem for now
28
63
  const isHorizontal = Object.keys(params.series).some(seriesId => params.series[seriesId].layout === 'horizontal');
29
64
  if (isHorizontal) {
30
- return getValueExtremum(params);
65
+ return getValueExtremum('x')(params);
31
66
  }
32
67
  return getBaseExtremum(params);
33
68
  };
@@ -36,5 +71,5 @@ export const getExtremumY = params => {
36
71
  if (isHorizontal) {
37
72
  return getBaseExtremum(params);
38
73
  }
39
- return getValueExtremum(params);
74
+ return getValueExtremum('y')(params);
40
75
  };
@@ -30,7 +30,7 @@ export const useChartContainerProps = (props, ref) => {
30
30
  const chartSurfaceRef = useForkRef(ref, svgRef);
31
31
  useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion)
32
32
 
33
- const [defaultizedXAxis, defaultizedYAxis] = useDefaultizeAxis(xAxis, yAxis);
33
+ const [defaultizedXAxis, defaultizedYAxis] = useDefaultizeAxis(xAxis, yAxis, dataset);
34
34
  const drawingProviderProps = {
35
35
  width,
36
36
  height,
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants';
4
- const defaultizeAxis = (inAxis, axisName) => {
4
+ const defaultizeAxis = (inAxis, dataset, axisName) => {
5
5
  const DEFAULT_AXIS_KEY = axisName === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY;
6
6
  return [...(inAxis?.map((axis, index) => _extends({
7
7
  id: `defaultized-${axisName}-axis-${index}`
@@ -10,10 +10,21 @@ const defaultizeAxis = (inAxis, axisName) => {
10
10
  }) => id === DEFAULT_AXIS_KEY) === -1 ? [{
11
11
  id: DEFAULT_AXIS_KEY,
12
12
  scaleType: 'linear'
13
- }] : [])];
13
+ }] : [])].map(axisConfig => {
14
+ const dataKey = axisConfig.dataKey;
15
+ if (dataKey === undefined || axisConfig.data !== undefined) {
16
+ return axisConfig;
17
+ }
18
+ if (dataset === undefined) {
19
+ throw Error(`MUI X: ${axisName}-axis uses \`dataKey\` but no \`dataset\` is provided.`);
20
+ }
21
+ return _extends({}, axisConfig, {
22
+ data: dataset.map(d => d[dataKey])
23
+ });
24
+ });
14
25
  };
15
- export const useDefaultizeAxis = (inXAxis, inYAxis) => {
16
- const xAxis = React.useMemo(() => defaultizeAxis(inXAxis, 'x'), [inXAxis]);
17
- const yAxis = React.useMemo(() => defaultizeAxis(inYAxis, 'y'), [inYAxis]);
26
+ export const useDefaultizeAxis = (inXAxis, inYAxis, dataset) => {
27
+ const xAxis = React.useMemo(() => defaultizeAxis(inXAxis, dataset, 'x'), [inXAxis, dataset]);
28
+ const yAxis = React.useMemo(() => defaultizeAxis(inYAxis, dataset, 'y'), [inYAxis, dataset]);
18
29
  return [xAxis, yAxis];
19
30
  };
@@ -25,16 +25,30 @@ export const ChartsAxisHighlightPath = styled('path', {
25
25
  slot: 'Root',
26
26
  overridesResolver: (_, styles) => styles.root
27
27
  })(({
28
- ownerState,
29
28
  theme
30
- }) => _extends({
31
- pointerEvents: 'none'
32
- }, ownerState.axisHighlight === 'band' && {
33
- fill: theme.palette.mode === 'light' ? 'gray' : 'white',
34
- fillOpacity: 0.1
35
- }, ownerState.axisHighlight === 'line' && {
36
- strokeDasharray: '5 2',
37
- stroke: theme.palette.mode === 'light' ? '#000000' : '#ffffff'
29
+ }) => ({
30
+ pointerEvents: 'none',
31
+ variants: [{
32
+ props: {
33
+ axisHighlight: 'band'
34
+ },
35
+ style: _extends({
36
+ fill: 'white',
37
+ fillOpacity: 0.1
38
+ }, theme.applyStyles('light', {
39
+ fill: 'gray'
40
+ }))
41
+ }, {
42
+ props: {
43
+ axisHighlight: 'line'
44
+ },
45
+ style: _extends({
46
+ strokeDasharray: '5 2',
47
+ stroke: '#ffffff'
48
+ }, theme.applyStyles('light', {
49
+ stroke: '#000000'
50
+ }))
51
+ }]
38
52
  }));
39
53
  /**
40
54
  * Demos:
@@ -8,6 +8,7 @@ import { styled, useThemeProps } from '@mui/material/styles';
8
8
  import { useCartesianContext } from '../context/CartesianProvider';
9
9
  import { useTicks } from '../hooks/useTicks';
10
10
  import { getChartsGridUtilityClass, chartsGridClasses } from './chartsGridClasses';
11
+ import { useDrawingArea } from '../hooks/useDrawingArea';
11
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
13
  const GridRoot = styled('g', {
13
14
  name: 'MuiChartsGrid',
@@ -53,6 +54,7 @@ function ChartsGrid(props) {
53
54
  props,
54
55
  name: 'MuiChartsGrid'
55
56
  });
57
+ const drawingArea = useDrawingArea();
56
58
  const {
57
59
  vertical,
58
60
  horizontal
@@ -93,8 +95,8 @@ function ChartsGrid(props) {
93
95
  formattedValue,
94
96
  offset
95
97
  }) => /*#__PURE__*/_jsx(GridLine, {
96
- y1: yScale.range()[0],
97
- y2: yScale.range()[1],
98
+ y1: drawingArea.top,
99
+ y2: drawingArea.top + drawingArea.height,
98
100
  x1: offset,
99
101
  x2: offset,
100
102
  className: classes.verticalLine
@@ -104,8 +106,8 @@ function ChartsGrid(props) {
104
106
  }) => /*#__PURE__*/_jsx(GridLine, {
105
107
  y1: offset,
106
108
  y2: offset,
107
- x1: xScale.range()[0],
108
- x2: xScale.range()[1],
109
+ x1: drawingArea.left,
110
+ x2: drawingArea.left + drawingArea.width,
109
111
  className: classes.horizontalLine
110
112
  }, `horizontal-${formattedValue}`))]
111
113
  }));
@@ -150,7 +150,8 @@ function ChartsXAxis(inProps) {
150
150
  left,
151
151
  top,
152
152
  width,
153
- height
153
+ height,
154
+ isPointInside
154
155
  } = useDrawingArea();
155
156
  const tickSize = disableTicks ? 4 : tickSizeProp;
156
157
  const positionSign = position === 'bottom' ? 1 : -1;
@@ -225,8 +226,18 @@ function ChartsXAxis(inProps) {
225
226
  }, index) => {
226
227
  const xTickLabel = labelOffset ?? 0;
227
228
  const yTickLabel = positionSign * (tickSize + 3);
228
- const showTick = offset >= left - 1 && offset <= left + width + 1;
229
- const showTickLabel = offset + xTickLabel >= left - 1 && offset + xTickLabel <= left + width + 1;
229
+ const showTick = isPointInside({
230
+ x: offset,
231
+ y: -1
232
+ }, {
233
+ direction: 'x'
234
+ });
235
+ const showTickLabel = isPointInside({
236
+ x: offset + xTickLabel,
237
+ y: -1
238
+ }, {
239
+ direction: 'x'
240
+ });
230
241
  return /*#__PURE__*/_jsxs("g", {
231
242
  transform: `translate(${offset}, 0)`,
232
243
  className: classes.tickContainer,
@@ -92,7 +92,8 @@ function ChartsYAxis(inProps) {
92
92
  left,
93
93
  top,
94
94
  width,
95
- height
95
+ height,
96
+ isPointInside
96
97
  } = useDrawingArea();
97
98
  const tickSize = disableTicks ? 4 : tickSizeProp;
98
99
  const yTicks = useTicks({
@@ -172,7 +173,12 @@ function ChartsYAxis(inProps) {
172
173
  const xTickLabel = positionSign * (tickSize + 2);
173
174
  const yTickLabel = labelOffset;
174
175
  const skipLabel = typeof tickLabelInterval === 'function' && !tickLabelInterval?.(value, index);
175
- const showLabel = offset >= top - 1 && offset <= height + top + 1;
176
+ const showLabel = isPointInside({
177
+ x: -1,
178
+ y: offset
179
+ }, {
180
+ direction: 'y'
181
+ });
176
182
  if (!showLabel) {
177
183
  return null;
178
184
  }
@@ -6,9 +6,18 @@ export const getExtremumX = params => {
6
6
  const maxX = Math.max(...(axis.data ?? []));
7
7
  return [minX, maxX];
8
8
  };
9
- function getSeriesExtremums(getValues, stackedData) {
10
- return stackedData.reduce((seriesAcc, stackedValue) => {
9
+ function getSeriesExtremums(getValues, stackedData, filter) {
10
+ return stackedData.reduce((seriesAcc, stackedValue, index) => {
11
11
  const [base, value] = getValues(stackedValue);
12
+ if (filter && (!filter({
13
+ y: base,
14
+ x: null
15
+ }, index) || !filter({
16
+ y: value,
17
+ x: null
18
+ }, index))) {
19
+ return seriesAcc;
20
+ }
12
21
  return [Math.min(base, value, seriesAcc[0]), Math.max(base, value, seriesAcc[1])];
13
22
  }, [Infinity, -Infinity]);
14
23
  }
@@ -16,7 +25,8 @@ export const getExtremumY = params => {
16
25
  const {
17
26
  series,
18
27
  axis,
19
- isDefaultAxis
28
+ isDefaultAxis,
29
+ getFilters
20
30
  } = params;
21
31
  return Object.keys(series).filter(seriesId => {
22
32
  const yAxisId = series[seriesId].yAxisId ?? series[seriesId].yAxisKey;
@@ -27,10 +37,16 @@ export const getExtremumY = params => {
27
37
  stackedData
28
38
  } = series[seriesId];
29
39
  const isArea = area !== undefined;
40
+ const filter = getFilters?.({
41
+ currentAxisId: axis.id,
42
+ isDefaultAxis,
43
+ seriesXAxisId: series[seriesId].xAxisId ?? series[seriesId].xAxisKey,
44
+ seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey
45
+ });
30
46
 
31
47
  // Since this series is not used to display an area, we do not consider the base (the d[0]).
32
48
  const getValues = isArea && axis.scaleType !== 'log' && typeof series[seriesId].baseline !== 'string' ? d => d : d => [d[1], d[1]];
33
- const seriesExtremums = getSeriesExtremums(getValues, stackedData);
49
+ const seriesExtremums = getSeriesExtremums(getValues, stackedData, filter);
34
50
  const [seriesMin, seriesMax] = seriesExtremums;
35
51
  return [Math.min(seriesMin, acc[0]), Math.max(seriesMax, acc[1])];
36
52
  }, [Infinity, -Infinity]);
@@ -5,16 +5,24 @@ export const getExtremumX = params => {
5
5
  const {
6
6
  series,
7
7
  axis,
8
- isDefaultAxis
8
+ isDefaultAxis,
9
+ getFilters
9
10
  } = params;
10
11
  return Object.keys(series).filter(seriesId => {
11
12
  const axisId = series[seriesId].xAxisId ?? series[seriesId].xAxisKey;
12
13
  return axisId === axis.id || axisId === undefined && isDefaultAxis;
13
14
  }).reduce((acc, seriesId) => {
14
- const seriesMinMax = series[seriesId].data.reduce((accSeries, {
15
- x
16
- }) => {
17
- return mergeMinMax(accSeries, [x, x]);
15
+ const filter = getFilters?.({
16
+ currentAxisId: axis.id,
17
+ isDefaultAxis,
18
+ seriesXAxisId: series[seriesId].xAxisId ?? series[seriesId].xAxisKey,
19
+ seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey
20
+ });
21
+ const seriesMinMax = series[seriesId].data.reduce((accSeries, d, dataIndex) => {
22
+ if (filter && !filter(d, dataIndex)) {
23
+ return accSeries;
24
+ }
25
+ return mergeMinMax(accSeries, [d.x, d.x]);
18
26
  }, [Infinity, -Infinity]);
19
27
  return mergeMinMax(acc, seriesMinMax);
20
28
  }, [Infinity, -Infinity]);
@@ -23,16 +31,24 @@ export const getExtremumY = params => {
23
31
  const {
24
32
  series,
25
33
  axis,
26
- isDefaultAxis
34
+ isDefaultAxis,
35
+ getFilters
27
36
  } = params;
28
37
  return Object.keys(series).filter(seriesId => {
29
38
  const axisId = series[seriesId].yAxisId ?? series[seriesId].yAxisKey;
30
39
  return axisId === axis.id || axisId === undefined && isDefaultAxis;
31
40
  }).reduce((acc, seriesId) => {
32
- const seriesMinMax = series[seriesId].data.reduce((accSeries, {
33
- y
34
- }) => {
35
- return mergeMinMax(accSeries, [y, y]);
41
+ const filter = getFilters?.({
42
+ currentAxisId: axis.id,
43
+ isDefaultAxis,
44
+ seriesXAxisId: series[seriesId].xAxisId ?? series[seriesId].xAxisKey,
45
+ seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey
46
+ });
47
+ const seriesMinMax = series[seriesId].data.reduce((accSeries, d, dataIndex) => {
48
+ if (filter && !filter(d, dataIndex)) {
49
+ return accSeries;
50
+ }
51
+ return mergeMinMax(accSeries, [d.y, d.y]);
36
52
  }, [Infinity, -Infinity]);
37
53
  return mergeMinMax(acc, seriesMinMax);
38
54
  }, [Infinity, -Infinity]);
@@ -10,7 +10,6 @@ function CartesianProvider(props) {
10
10
  const {
11
11
  xAxis,
12
12
  yAxis,
13
- dataset,
14
13
  children
15
14
  } = props;
16
15
  const formattedSeries = useSeries();
@@ -22,17 +21,15 @@ function CartesianProvider(props) {
22
21
  formattedSeries,
23
22
  axis: xAxis,
24
23
  extremumGetters: xExtremumGetters,
25
- dataset,
26
24
  axisDirection: 'x'
27
- }), [drawingArea, formattedSeries, xAxis, xExtremumGetters, dataset]);
25
+ }), [drawingArea, formattedSeries, xAxis, xExtremumGetters]);
28
26
  const yValues = React.useMemo(() => computeValue({
29
27
  drawingArea,
30
28
  formattedSeries,
31
29
  axis: yAxis,
32
30
  extremumGetters: yExtremumGetters,
33
- dataset,
34
31
  axisDirection: 'y'
35
- }), [drawingArea, formattedSeries, yAxis, yExtremumGetters, dataset]);
32
+ }), [drawingArea, formattedSeries, yAxis, yExtremumGetters]);
36
33
  const value = React.useMemo(() => ({
37
34
  isInitialized: true,
38
35
  data: {
@@ -4,22 +4,12 @@ import { isBandScaleConfig, isPointScaleConfig } from '../../models/axis';
4
4
  import { getColorScale, getOrdinalColorScale } from '../../internals/colorScale';
5
5
  import { getTickNumber } from '../../hooks/useTicks';
6
6
  import { getScale } from '../../internals/getScale';
7
+ import { zoomScaleRange } from './zoom';
7
8
  import { getAxisExtremum } from './getAxisExtremum';
8
- import { normalizeAxis } from './normalizeAxis';
9
9
  const getRange = (drawingArea, axisDirection, isReverse) => {
10
10
  const range = axisDirection === 'x' ? [drawingArea.left, drawingArea.left + drawingArea.width] : [drawingArea.top + drawingArea.height, drawingArea.top];
11
11
  return isReverse ? range.reverse() : range;
12
12
  };
13
- const zoomedScaleRange = (scaleRange, zoomRange) => {
14
- const rangeGap = scaleRange[1] - scaleRange[0];
15
- const zoomGap = zoomRange[1] - zoomRange[0];
16
-
17
- // If current zoom show the scale between p1 and p2 percents
18
- // The range should be extended by adding [0, p1] and [p2, 100] segments
19
- const min = scaleRange[0] - zoomRange[0] * rangeGap / zoomGap;
20
- const max = scaleRange[1] + (100 - zoomRange[1]) * rangeGap / zoomGap;
21
- return [min, max];
22
- };
23
13
  const isDateData = data => data?.[0] instanceof Date;
24
14
  function createDateFormatter(axis, range) {
25
15
  const timeScale = scaleTime(axis.data, range);
@@ -32,32 +22,37 @@ const DEFAULT_BAR_GAP_RATIO = 0.1;
32
22
  export function computeValue({
33
23
  drawingArea,
34
24
  formattedSeries,
35
- axis: inAxis,
25
+ axis: allAxis,
36
26
  extremumGetters,
37
- dataset,
38
27
  axisDirection,
39
- zoomData
28
+ zoomData,
29
+ zoomOptions,
30
+ getFilters
40
31
  }) {
41
- const allAxis = normalizeAxis(inAxis, dataset, axisDirection);
42
32
  const completeAxis = {};
43
- allAxis.forEach((axis, axisIndex) => {
33
+ allAxis.forEach((eachAxis, axisIndex) => {
34
+ const axis = eachAxis;
44
35
  const isDefaultAxis = axisIndex === 0;
45
- const [minData, maxData] = getAxisExtremum(axis, extremumGetters, isDefaultAxis, formattedSeries);
36
+ const zoomOption = zoomOptions?.[axis.id];
46
37
  const zoom = zoomData?.find(({
47
38
  axisId
48
39
  }) => axisId === axis.id);
49
40
  const zoomRange = zoom ? [zoom.start, zoom.end] : [0, 100];
50
41
  const range = getRange(drawingArea, axisDirection, axis.reverse);
42
+ const [minData, maxData] = getAxisExtremum(axis, extremumGetters, isDefaultAxis, formattedSeries, zoom === undefined && !zoomOption ? getFilters : undefined // Do not apply filtering if zoom is already defined.
43
+ );
44
+ const data = axis.data ?? [];
51
45
  if (isBandScaleConfig(axis)) {
52
46
  const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO;
53
47
  const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO;
54
48
  // Reverse range because ordinal scales are presented from top to bottom on y-axis
55
49
  const scaleRange = axisDirection === 'x' ? range : [range[1], range[0]];
56
- const zoomedRange = zoomedScaleRange(scaleRange, zoomRange);
50
+ const zoomedRange = zoomScaleRange(scaleRange, zoomRange);
57
51
  completeAxis[axis.id] = _extends({
58
52
  categoryGapRatio,
59
53
  barGapRatio
60
54
  }, axis, {
55
+ data,
61
56
  scale: scaleBand(axis.data, zoomedRange).paddingInner(categoryGapRatio).paddingOuter(categoryGapRatio / 2),
62
57
  tickNumber: axis.data.length,
63
58
  colorScale: axis.colorMap && (axis.colorMap.type === 'ordinal' ? getOrdinalColorScale(_extends({
@@ -71,8 +66,9 @@ export function computeValue({
71
66
  }
72
67
  if (isPointScaleConfig(axis)) {
73
68
  const scaleRange = axisDirection === 'x' ? range : [...range].reverse();
74
- const zoomedRange = zoomedScaleRange(scaleRange, zoomRange);
69
+ const zoomedRange = zoomScaleRange(scaleRange, zoomRange);
75
70
  completeAxis[axis.id] = _extends({}, axis, {
71
+ data,
76
72
  scale: scalePoint(axis.data, zoomedRange),
77
73
  tickNumber: axis.data.length,
78
74
  colorScale: axis.colorMap && (axis.colorMap.type === 'ordinal' ? getOrdinalColorScale(_extends({
@@ -89,19 +85,20 @@ export function computeValue({
89
85
  return;
90
86
  }
91
87
  const scaleType = axis.scaleType ?? 'linear';
92
- const extremums = [axis.min ?? minData, axis.max ?? maxData];
88
+ const axisExtremums = [axis.min ?? minData, axis.max ?? maxData];
93
89
  const rawTickNumber = getTickNumber(_extends({}, axis, {
94
90
  range,
95
- domain: extremums
91
+ domain: axisExtremums
96
92
  }));
97
93
  const tickNumber = rawTickNumber / ((zoomRange[1] - zoomRange[0]) / 100);
98
- const zoomedRange = zoomedScaleRange(range, zoomRange);
94
+ const zoomedRange = zoomScaleRange(range, zoomRange);
99
95
 
100
96
  // TODO: move nice to prop? Disable when there is zoom?
101
- const scale = getScale(scaleType, extremums, zoomedRange).nice(rawTickNumber);
97
+ const scale = getScale(scaleType, axisExtremums, zoomedRange).nice(rawTickNumber);
102
98
  const [minDomain, maxDomain] = scale.domain();
103
99
  const domain = [axis.min ?? minDomain, axis.max ?? maxDomain];
104
100
  completeAxis[axis.id] = _extends({}, axis, {
101
+ data,
105
102
  scaleType: scaleType,
106
103
  scale: scale.domain(domain),
107
104
  tickNumber,
@@ -1,14 +1,20 @@
1
- const axisExtremumCallback = (acc, chartType, axis, getters, isDefaultAxis, formattedSeries) => {
1
+ const axisExtremumCallback = (acc, chartType, axis, getters, isDefaultAxis, formattedSeries, getFilters) => {
2
2
  const getter = getters[chartType];
3
3
  const series = formattedSeries[chartType]?.series ?? {};
4
4
  const [minChartTypeData, maxChartTypeData] = getter?.({
5
5
  series,
6
6
  axis,
7
- isDefaultAxis
7
+ isDefaultAxis,
8
+ getFilters
8
9
  }) ?? [Infinity, -Infinity];
9
- return [Math.min(minChartTypeData, acc[0]), Math.max(maxChartTypeData, acc[1])];
10
+ const [minData, maxData] = acc;
11
+ return [Math.min(minChartTypeData, minData), Math.max(maxChartTypeData, maxData)];
10
12
  };
11
- export const getAxisExtremum = (axis, getters, isDefaultAxis, formattedSeries) => {
13
+ export const getAxisExtremum = (axis, getters, isDefaultAxis, formattedSeries, getFilters) => {
12
14
  const charTypes = Object.keys(getters);
13
- return charTypes.reduce((acc, charType) => axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis, formattedSeries), [Infinity, -Infinity]);
15
+ const extremums = charTypes.reduce((acc, charType) => axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis, formattedSeries, getFilters), [Infinity, -Infinity]);
16
+ if (Number.isNaN(extremums[0]) || Number.isNaN(extremums[1])) {
17
+ return [Infinity, -Infinity];
18
+ }
19
+ return extremums;
14
20
  };
@@ -2,6 +2,7 @@ import { computeValue } from './computeValue';
2
2
  export * from './CartesianProvider';
3
3
  export * from './CartesianContext';
4
4
  export * from './useCartesianContext';
5
+ export * from './Cartesian.types';
5
6
  const cartesianProviderUtils = {
6
7
  computeValue
7
8
  };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Applies the zoom into the scale range.
3
+ * It changes the screen coordinates that the scale covers.
4
+ * Not the data that is displayed.
5
+ *
6
+ * @param scaleRange the original range in real screen coordinates.
7
+ * @param zoomRange the zoom range in percentage.
8
+ * @returns zoomed range in real screen coordinates.
9
+ */
10
+ export const zoomScaleRange = (scaleRange, zoomRange) => {
11
+ const rangeGap = scaleRange[1] - scaleRange[0];
12
+ const zoomGap = zoomRange[1] - zoomRange[0];
13
+
14
+ // If current zoom show the scale between p1 and p2 percents
15
+ // The range should be extended by adding [0, p1] and [p2, 100] segments
16
+ const min = scaleRange[0] - zoomRange[0] * rangeGap / zoomGap;
17
+ const max = scaleRange[1] + (100 - zoomRange[1]) * rangeGap / zoomGap;
18
+ return [min, max];
19
+ };
@@ -42,12 +42,20 @@ export function DrawingProvider(props) {
42
42
  const isPointInside = React.useCallback(({
43
43
  x,
44
44
  y
45
- }, targetElement) => {
45
+ }, options) => {
46
46
  // For element allowed to overflow, wrapping them in <g data-drawing-container /> make them fully part of the drawing area.
47
- if (targetElement && targetElement.closest('[data-drawing-container]')) {
47
+ if (options?.targetElement && options?.targetElement.closest('[data-drawing-container]')) {
48
48
  return true;
49
49
  }
50
- return x >= drawingArea.left && x <= drawingArea.left + drawingArea.width && y >= drawingArea.top && y <= drawingArea.top + drawingArea.height;
50
+ const isInsideX = x >= drawingArea.left - 1 && x <= drawingArea.left + drawingArea.width;
51
+ const isInsideY = y >= drawingArea.top - 1 && y <= drawingArea.top + drawingArea.height;
52
+ if (options?.direction === 'x') {
53
+ return isInsideX;
54
+ }
55
+ if (options?.direction === 'y') {
56
+ return isInsideY;
57
+ }
58
+ return isInsideX && isInsideY;
51
59
  }, [drawingArea]);
52
60
  const value = React.useMemo(() => _extends({
53
61
  chartId: chartId ?? ''
@@ -98,7 +98,9 @@ export const useAxisEvents = disableAxisListener => {
98
98
  const svgPoint = getSVGPoint(element, target);
99
99
  mousePosition.current.x = svgPoint.x;
100
100
  mousePosition.current.y = svgPoint.y;
101
- if (!drawingArea.isPointInside(svgPoint, event.target)) {
101
+ if (!drawingArea.isPointInside(svgPoint, {
102
+ targetElement: event.target
103
+ })) {
102
104
  if (mousePosition.current.isInChart) {
103
105
  dispatch({
104
106
  type: 'exitChart'
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts v7.13.0
2
+ * @mui/x-charts v7.14.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the