@mui/x-charts 8.9.0 → 8.10.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 (128) hide show
  1. package/BarChart/BarChart.js +110 -1
  2. package/BarChart/BarClipPath.d.ts +17 -12
  3. package/BarChart/BarClipPath.js +70 -57
  4. package/BarChart/BarPlot.js +4 -0
  5. package/BarChart/seriesConfig/extremums.js +2 -3
  6. package/BarChart/useBarChartProps.d.ts +1 -1
  7. package/CHANGELOG.md +245 -6
  8. package/ChartContainer/ChartContainer.js +165 -0
  9. package/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
  10. package/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
  11. package/ChartsTooltip/ChartsTooltip.d.ts +2 -1
  12. package/ChartsTooltip/ChartsTooltip.js +3 -3
  13. package/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
  14. package/ChartsTooltip/ChartsTooltipContainer.js +3 -3
  15. package/{internals/components/ChartsWrapper → ChartsWrapper}/ChartsWrapper.d.ts +13 -4
  16. package/{internals/components/ChartsWrapper → ChartsWrapper}/ChartsWrapper.js +33 -7
  17. package/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
  18. package/ChartsXAxis/ChartsGroupedXAxis.js +142 -0
  19. package/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
  20. package/ChartsXAxis/ChartsSingleXAxis.js +144 -0
  21. package/ChartsXAxis/ChartsXAxis.d.ts +1 -1
  22. package/ChartsXAxis/ChartsXAxis.js +8 -210
  23. package/ChartsXAxis/getVisibleLabels.d.ts +2 -2
  24. package/ChartsXAxis/useAxisProps.d.ts +4526 -0
  25. package/ChartsXAxis/useAxisProps.js +105 -0
  26. package/ChartsXAxis/utilities.d.ts +11 -0
  27. package/ChartsXAxis/utilities.js +43 -0
  28. package/LineChart/LineChart.js +110 -1
  29. package/LineChart/seriesConfig/extremums.js +2 -3
  30. package/LineChart/useLineChartProps.d.ts +1 -1
  31. package/PieChart/PieChart.js +1 -1
  32. package/RadarChart/RadarChart.d.ts +1 -1
  33. package/RadarChart/RadarChart.js +1 -1
  34. package/RadarChart/index.d.ts +9 -2
  35. package/RadarChart/index.js +13 -14
  36. package/RadarChart/useRadarChartProps.d.ts +1 -1
  37. package/ScatterChart/ScatterChart.d.ts +8 -1
  38. package/ScatterChart/ScatterChart.js +110 -1
  39. package/ScatterChart/seriesConfig/extremums.js +50 -23
  40. package/ScatterChart/useScatterChartProps.d.ts +1 -1
  41. package/SparkLineChart/SparkLineChart.js +109 -0
  42. package/esm/BarChart/BarChart.js +110 -1
  43. package/esm/BarChart/BarClipPath.d.ts +17 -12
  44. package/esm/BarChart/BarClipPath.js +69 -55
  45. package/esm/BarChart/BarPlot.js +4 -0
  46. package/esm/BarChart/seriesConfig/extremums.js +2 -3
  47. package/esm/BarChart/useBarChartProps.d.ts +1 -1
  48. package/esm/ChartContainer/ChartContainer.js +165 -0
  49. package/esm/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
  50. package/esm/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
  51. package/esm/ChartsTooltip/ChartsTooltip.d.ts +2 -1
  52. package/esm/ChartsTooltip/ChartsTooltip.js +3 -3
  53. package/esm/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
  54. package/esm/ChartsTooltip/ChartsTooltipContainer.js +3 -3
  55. package/esm/{internals/components/ChartsWrapper → ChartsWrapper}/ChartsWrapper.d.ts +13 -4
  56. package/esm/{internals/components/ChartsWrapper → ChartsWrapper}/ChartsWrapper.js +31 -6
  57. package/esm/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
  58. package/esm/ChartsXAxis/ChartsGroupedXAxis.js +136 -0
  59. package/esm/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
  60. package/esm/ChartsXAxis/ChartsSingleXAxis.js +140 -0
  61. package/esm/ChartsXAxis/ChartsXAxis.d.ts +1 -1
  62. package/esm/ChartsXAxis/ChartsXAxis.js +7 -207
  63. package/esm/ChartsXAxis/getVisibleLabels.d.ts +2 -2
  64. package/esm/ChartsXAxis/useAxisProps.d.ts +4526 -0
  65. package/esm/ChartsXAxis/useAxisProps.js +98 -0
  66. package/esm/ChartsXAxis/utilities.d.ts +11 -0
  67. package/esm/ChartsXAxis/utilities.js +35 -0
  68. package/esm/LineChart/LineChart.js +110 -1
  69. package/esm/LineChart/seriesConfig/extremums.js +2 -3
  70. package/esm/LineChart/useLineChartProps.d.ts +1 -1
  71. package/esm/PieChart/PieChart.js +1 -1
  72. package/esm/RadarChart/RadarChart.d.ts +1 -1
  73. package/esm/RadarChart/RadarChart.js +1 -1
  74. package/esm/RadarChart/index.d.ts +9 -2
  75. package/esm/RadarChart/index.js +12 -2
  76. package/esm/RadarChart/useRadarChartProps.d.ts +1 -1
  77. package/esm/ScatterChart/ScatterChart.d.ts +8 -1
  78. package/esm/ScatterChart/ScatterChart.js +110 -1
  79. package/esm/ScatterChart/seriesConfig/extremums.js +50 -23
  80. package/esm/ScatterChart/useScatterChartProps.d.ts +1 -1
  81. package/esm/SparkLineChart/SparkLineChart.js +109 -0
  82. package/esm/hooks/useTicksGrouped.d.ts +28 -0
  83. package/esm/hooks/useTicksGrouped.js +98 -0
  84. package/esm/index.d.ts +2 -1
  85. package/esm/index.js +6 -2
  86. package/esm/internals/findMinMax.d.ts +1 -0
  87. package/esm/internals/findMinMax.js +13 -0
  88. package/esm/internals/getScale.d.ts +1 -1
  89. package/esm/internals/getScale.js +3 -0
  90. package/esm/internals/index.d.ts +1 -1
  91. package/esm/internals/index.js +1 -1
  92. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.js +4 -1
  93. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
  94. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +32 -23
  95. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
  96. package/esm/internals/plugins/featurePlugins/useChartVoronoi/useChartVoronoi.js +17 -12
  97. package/esm/internals/symlogScale.d.ts +2 -0
  98. package/esm/internals/symlogScale.js +94 -0
  99. package/esm/models/axis.d.ts +81 -4
  100. package/esm/models/axis.js +3 -0
  101. package/hooks/useTicksGrouped.d.ts +28 -0
  102. package/hooks/useTicksGrouped.js +104 -0
  103. package/index.d.ts +2 -1
  104. package/index.js +13 -1
  105. package/internals/findMinMax.d.ts +1 -0
  106. package/internals/findMinMax.js +19 -0
  107. package/internals/getScale.d.ts +1 -1
  108. package/internals/getScale.js +3 -0
  109. package/internals/index.d.ts +1 -1
  110. package/internals/index.js +12 -12
  111. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.js +3 -0
  112. package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
  113. package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +34 -23
  114. package/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
  115. package/internals/plugins/featurePlugins/useChartVoronoi/useChartVoronoi.js +17 -12
  116. package/internals/symlogScale.d.ts +2 -0
  117. package/internals/symlogScale.js +100 -0
  118. package/models/axis.d.ts +81 -4
  119. package/models/axis.js +4 -0
  120. package/package.json +5 -7
  121. package/BarChart/getRadius.d.ts +0 -20
  122. package/BarChart/getRadius.js +0 -37
  123. package/esm/BarChart/getRadius.d.ts +0 -20
  124. package/esm/BarChart/getRadius.js +0 -30
  125. /package/{esm/internals/components/ChartsWrapper → ChartsWrapper}/index.d.ts +0 -0
  126. /package/{internals/components/ChartsWrapper → ChartsWrapper}/index.js +0 -0
  127. /package/{internals/components → esm}/ChartsWrapper/index.d.ts +0 -0
  128. /package/esm/{internals/components/ChartsWrapper → ChartsWrapper}/index.js +0 -0
@@ -1,6 +1,3 @@
1
- const mergeMinMax = (acc, val) => {
2
- return [val[0] === null ? acc[0] : Math.min(acc[0], val[0]), val[1] === null ? acc[1] : Math.max(acc[1], val[1])];
3
- };
4
1
  export const getExtremumX = params => {
5
2
  const {
6
3
  series,
@@ -8,24 +5,39 @@ export const getExtremumX = params => {
8
5
  isDefaultAxis,
9
6
  getFilters
10
7
  } = params;
11
- return Object.keys(series).filter(seriesId => {
8
+ let min = Infinity;
9
+ let max = -Infinity;
10
+ for (const seriesId in series) {
11
+ if (!Object.hasOwn(series, seriesId)) {
12
+ continue;
13
+ }
12
14
  const axisId = series[seriesId].xAxisId;
13
- return axisId === axis.id || axisId === undefined && isDefaultAxis;
14
- }).reduce((acc, seriesId) => {
15
+ if (!(axisId === axis.id || axisId === undefined && isDefaultAxis)) {
16
+ continue;
17
+ }
15
18
  const filter = getFilters?.({
16
19
  currentAxisId: axis.id,
17
20
  isDefaultAxis,
18
21
  seriesXAxisId: series[seriesId].xAxisId,
19
22
  seriesYAxisId: series[seriesId].yAxisId
20
23
  });
21
- const seriesMinMax = series[seriesId].data?.reduce((accSeries, d, dataIndex) => {
22
- if (filter && !filter(d, dataIndex)) {
23
- return accSeries;
24
+ const seriesData = series[seriesId].data ?? [];
25
+ for (let i = 0; i < seriesData.length; i += 1) {
26
+ const d = seriesData[i];
27
+ if (filter && !filter(d, i)) {
28
+ continue;
29
+ }
30
+ if (d.x !== null) {
31
+ if (d.x < min) {
32
+ min = d.x;
33
+ }
34
+ if (d.x > max) {
35
+ max = d.x;
36
+ }
24
37
  }
25
- return mergeMinMax(accSeries, [d.x, d.x]);
26
- }, [Infinity, -Infinity]);
27
- return mergeMinMax(acc, seriesMinMax ?? [Infinity, -Infinity]);
28
- }, [Infinity, -Infinity]);
38
+ }
39
+ }
40
+ return [min, max];
29
41
  };
30
42
  export const getExtremumY = params => {
31
43
  const {
@@ -34,22 +46,37 @@ export const getExtremumY = params => {
34
46
  isDefaultAxis,
35
47
  getFilters
36
48
  } = params;
37
- return Object.keys(series).filter(seriesId => {
49
+ let min = Infinity;
50
+ let max = -Infinity;
51
+ for (const seriesId in series) {
52
+ if (!Object.hasOwn(series, seriesId)) {
53
+ continue;
54
+ }
38
55
  const axisId = series[seriesId].yAxisId;
39
- return axisId === axis.id || axisId === undefined && isDefaultAxis;
40
- }).reduce((acc, seriesId) => {
56
+ if (!(axisId === axis.id || axisId === undefined && isDefaultAxis)) {
57
+ continue;
58
+ }
41
59
  const filter = getFilters?.({
42
60
  currentAxisId: axis.id,
43
61
  isDefaultAxis,
44
62
  seriesXAxisId: series[seriesId].xAxisId,
45
63
  seriesYAxisId: series[seriesId].yAxisId
46
64
  });
47
- const seriesMinMax = series[seriesId].data?.reduce((accSeries, d, dataIndex) => {
48
- if (filter && !filter(d, dataIndex)) {
49
- return accSeries;
65
+ const seriesData = series[seriesId].data ?? [];
66
+ for (let i = 0; i < seriesData.length; i += 1) {
67
+ const d = seriesData[i];
68
+ if (filter && !filter(d, i)) {
69
+ continue;
70
+ }
71
+ if (d.y !== null) {
72
+ if (d.y < min) {
73
+ min = d.y;
74
+ }
75
+ if (d.y > max) {
76
+ max = d.y;
77
+ }
50
78
  }
51
- return mergeMinMax(accSeries, [d.y, d.y]);
52
- }, [Infinity, -Infinity]);
53
- return mergeMinMax(acc, seriesMinMax ?? [Infinity, -Infinity]);
54
- }, [Infinity, -Infinity]);
79
+ }
80
+ }
81
+ return [min, max];
55
82
  };
@@ -7,7 +7,7 @@ import { ChartsOverlayProps } from "../ChartsOverlay/index.js";
7
7
  import { ChartContainerProps } from "../ChartContainer/index.js";
8
8
  import type { ScatterChartProps } from "./ScatterChart.js";
9
9
  import type { ScatterPlotProps } from "./ScatterPlot.js";
10
- import type { ChartsWrapperProps } from "../internals/components/ChartsWrapper/index.js";
10
+ import type { ChartsWrapperProps } from "../ChartsWrapper/index.js";
11
11
  import { ScatterChartPluginsSignatures } from "./ScatterChart.plugins.js";
12
12
  /**
13
13
  * A helper function that extracts ScatterChartProps from the input props
@@ -353,6 +353,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
353
353
  disableTicks: PropTypes.bool,
354
354
  domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
355
355
  fill: PropTypes.string,
356
+ groups: PropTypes.arrayOf(PropTypes.shape({
357
+ getValue: PropTypes.func.isRequired,
358
+ tickSize: PropTypes.number
359
+ })),
356
360
  height: PropTypes.number,
357
361
  hideTooltip: PropTypes.bool,
358
362
  id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
@@ -404,6 +408,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
404
408
  disableTicks: PropTypes.bool,
405
409
  domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
406
410
  fill: PropTypes.string,
411
+ groups: PropTypes.arrayOf(PropTypes.shape({
412
+ getValue: PropTypes.func.isRequired,
413
+ tickSize: PropTypes.number
414
+ })),
407
415
  height: PropTypes.number,
408
416
  hideTooltip: PropTypes.bool,
409
417
  id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
@@ -477,6 +485,53 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
477
485
  tickPlacement: PropTypes.oneOf(['end', 'extremities', 'middle', 'start']),
478
486
  tickSize: PropTypes.number,
479
487
  valueFormatter: PropTypes.func
488
+ }), PropTypes.shape({
489
+ axis: PropTypes.oneOf(['x']),
490
+ classes: PropTypes.object,
491
+ colorMap: PropTypes.oneOfType([PropTypes.shape({
492
+ color: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string.isRequired), PropTypes.func]).isRequired,
493
+ max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
494
+ min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
495
+ type: PropTypes.oneOf(['continuous']).isRequired
496
+ }), PropTypes.shape({
497
+ colors: PropTypes.arrayOf(PropTypes.string).isRequired,
498
+ thresholds: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired).isRequired,
499
+ type: PropTypes.oneOf(['piecewise']).isRequired
500
+ })]),
501
+ constant: PropTypes.number,
502
+ data: PropTypes.array,
503
+ dataKey: PropTypes.string,
504
+ disableLine: PropTypes.bool,
505
+ disableTicks: PropTypes.bool,
506
+ domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
507
+ fill: PropTypes.string,
508
+ height: PropTypes.number,
509
+ hideTooltip: PropTypes.bool,
510
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
511
+ ignoreTooltip: PropTypes.bool,
512
+ label: PropTypes.string,
513
+ labelStyle: PropTypes.object,
514
+ max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
515
+ min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
516
+ offset: PropTypes.number,
517
+ position: PropTypes.oneOf(['bottom', 'none', 'top']),
518
+ reverse: PropTypes.bool,
519
+ scaleType: PropTypes.oneOf(['symlog']),
520
+ slotProps: PropTypes.object,
521
+ slots: PropTypes.object,
522
+ stroke: PropTypes.string,
523
+ sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
524
+ tickInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.array, PropTypes.func]),
525
+ tickLabelInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.func]),
526
+ tickLabelMinGap: PropTypes.number,
527
+ tickLabelPlacement: PropTypes.oneOf(['middle', 'tick']),
528
+ tickLabelStyle: PropTypes.object,
529
+ tickMaxStep: PropTypes.number,
530
+ tickMinStep: PropTypes.number,
531
+ tickNumber: PropTypes.number,
532
+ tickPlacement: PropTypes.oneOf(['end', 'extremities', 'middle', 'start']),
533
+ tickSize: PropTypes.number,
534
+ valueFormatter: PropTypes.func
480
535
  }), PropTypes.shape({
481
536
  axis: PropTypes.oneOf(['x']),
482
537
  classes: PropTypes.object,
@@ -738,6 +793,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
738
793
  disableTicks: PropTypes.bool,
739
794
  domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
740
795
  fill: PropTypes.string,
796
+ groups: PropTypes.arrayOf(PropTypes.shape({
797
+ getValue: PropTypes.func.isRequired,
798
+ tickSize: PropTypes.number
799
+ })),
741
800
  hideTooltip: PropTypes.bool,
742
801
  id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
743
802
  ignoreTooltip: PropTypes.bool,
@@ -788,6 +847,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
788
847
  disableTicks: PropTypes.bool,
789
848
  domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
790
849
  fill: PropTypes.string,
850
+ groups: PropTypes.arrayOf(PropTypes.shape({
851
+ getValue: PropTypes.func.isRequired,
852
+ tickSize: PropTypes.number
853
+ })),
791
854
  hideTooltip: PropTypes.bool,
792
855
  id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
793
856
  ignoreTooltip: PropTypes.bool,
@@ -859,6 +922,52 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
859
922
  tickSize: PropTypes.number,
860
923
  valueFormatter: PropTypes.func,
861
924
  width: PropTypes.number
925
+ }), PropTypes.shape({
926
+ axis: PropTypes.oneOf(['y']),
927
+ classes: PropTypes.object,
928
+ colorMap: PropTypes.oneOfType([PropTypes.shape({
929
+ color: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string.isRequired), PropTypes.func]).isRequired,
930
+ max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
931
+ min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
932
+ type: PropTypes.oneOf(['continuous']).isRequired
933
+ }), PropTypes.shape({
934
+ colors: PropTypes.arrayOf(PropTypes.string).isRequired,
935
+ thresholds: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]).isRequired).isRequired,
936
+ type: PropTypes.oneOf(['piecewise']).isRequired
937
+ })]),
938
+ constant: PropTypes.number,
939
+ data: PropTypes.array,
940
+ dataKey: PropTypes.string,
941
+ disableLine: PropTypes.bool,
942
+ disableTicks: PropTypes.bool,
943
+ domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
944
+ fill: PropTypes.string,
945
+ hideTooltip: PropTypes.bool,
946
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
947
+ ignoreTooltip: PropTypes.bool,
948
+ label: PropTypes.string,
949
+ labelStyle: PropTypes.object,
950
+ max: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
951
+ min: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]),
952
+ offset: PropTypes.number,
953
+ position: PropTypes.oneOf(['left', 'none', 'right']),
954
+ reverse: PropTypes.bool,
955
+ scaleType: PropTypes.oneOf(['symlog']),
956
+ slotProps: PropTypes.object,
957
+ slots: PropTypes.object,
958
+ stroke: PropTypes.string,
959
+ sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
960
+ tickInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.array, PropTypes.func]),
961
+ tickLabelInterval: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.func]),
962
+ tickLabelPlacement: PropTypes.oneOf(['middle', 'tick']),
963
+ tickLabelStyle: PropTypes.object,
964
+ tickMaxStep: PropTypes.number,
965
+ tickMinStep: PropTypes.number,
966
+ tickNumber: PropTypes.number,
967
+ tickPlacement: PropTypes.oneOf(['end', 'extremities', 'middle', 'start']),
968
+ tickSize: PropTypes.number,
969
+ valueFormatter: PropTypes.func,
970
+ width: PropTypes.number
862
971
  }), PropTypes.shape({
863
972
  axis: PropTypes.oneOf(['y']),
864
973
  classes: PropTypes.object,
@@ -0,0 +1,28 @@
1
+ import type { ScaleBand, ScalePoint } from '@mui/x-charts-vendor/d3-scale';
2
+ import { AxisConfig, type AxisGroup } from "../models/axis.js";
3
+ import type { TickParams } from "./useTicks.js";
4
+ export type GroupedTickItemType = {
5
+ /**
6
+ * This property is undefined only if it's the tick closing the last band
7
+ */
8
+ value?: any;
9
+ formattedValue?: string;
10
+ offset: number;
11
+ labelOffset: number;
12
+ /**
13
+ * In band scales, we remove some redundant ticks.
14
+ */
15
+ ignoreTick?: boolean;
16
+ dataIndex?: number;
17
+ /**
18
+ * The index of the group this tick belongs to. If `getGrouping` returns `[[0, 1], [2, 3]]`
19
+ * both ticks with value `0` and `2` will have `groupIndex: 0`, and both ticks with value `1` and `3` will have `groupIndex: 1`.
20
+ */
21
+ groupIndex?: number;
22
+ };
23
+ export declare function useTicksGrouped(options: {
24
+ scale: ScaleBand<any> | ScalePoint<any>;
25
+ valueFormatter?: AxisConfig['valueFormatter'];
26
+ direction: 'x' | 'y';
27
+ groups: AxisGroup[];
28
+ } & Pick<TickParams, 'tickNumber' | 'tickInterval' | 'tickPlacement' | 'tickLabelPlacement'>): GroupedTickItemType[];
@@ -0,0 +1,98 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { isBandScale } from "../internals/isBandScale.js";
5
+ const offsetRatio = {
6
+ start: 0,
7
+ extremities: 0,
8
+ end: 1,
9
+ middle: 0.5,
10
+ tick: 0
11
+ };
12
+ export function useTicksGrouped(options) {
13
+ const {
14
+ scale,
15
+ tickInterval,
16
+ tickLabelPlacement = 'middle',
17
+ tickPlacement = 'extremities',
18
+ groups
19
+ } = options;
20
+ return React.useMemo(() => {
21
+ const domain = scale.domain();
22
+ const filteredDomain = typeof tickInterval === 'function' && domain.filter(tickInterval) || typeof tickInterval === 'object' && tickInterval || domain;
23
+ if (scale.bandwidth() > 0) {
24
+ // scale type = 'band'
25
+ const entries = mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
26
+ if (entries[0]) {
27
+ entries[0].ignoreTick = true;
28
+ }
29
+ return [{
30
+ formattedValue: undefined,
31
+ offset: scale.range()[0],
32
+ labelOffset: 0,
33
+ groupIndex: groups.length - 1
34
+ }, ...entries,
35
+ // Last tick
36
+ {
37
+ formattedValue: undefined,
38
+ offset: scale.range()[1],
39
+ labelOffset: 0,
40
+ groupIndex: groups.length - 1
41
+ }];
42
+ }
43
+
44
+ // scale type = 'point'
45
+ return mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
46
+ }, [scale, tickInterval, groups, tickPlacement, tickLabelPlacement]);
47
+ }
48
+ function mapToGrouping(tickValues, groups, tickPlacement, tickLabelPlacement, scale) {
49
+ const allTickItems = [];
50
+ // Map to keep track of offsets and their corresponding tick indexes
51
+ // Used to remove redundant ticks when they are in the same position
52
+ const dataIndexToTickIndex = new Map();
53
+ let currentValueCount = 0;
54
+ for (let groupIndex = 0; groupIndex < groups.length; groupIndex += 1) {
55
+ for (let dataIndex = 0; dataIndex < tickValues.length; dataIndex += 1) {
56
+ const tickValue = tickValues[dataIndex];
57
+ const groupValue = groups[groupIndex].getValue(tickValue, dataIndex);
58
+ const lastItem = allTickItems[allTickItems.length - 1];
59
+
60
+ // Check if this is a new unique value for this group
61
+ const isNew = lastItem?.value !== groupValue || lastItem?.groupIndex !== groupIndex;
62
+ if (isNew) {
63
+ currentValueCount = 1;
64
+ // Calculate tick offset
65
+ const tickOffset = isBandScale(scale) ? scale(tickValue) - (scale.step() - scale.bandwidth()) / 2 + offsetRatio[tickPlacement] * scale.step() : scale(tickValue);
66
+
67
+ // Calculate the label offset
68
+ const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
69
+
70
+ // Add a new item
71
+ allTickItems.push({
72
+ value: groupValue,
73
+ formattedValue: `${groupValue}`,
74
+ offset: tickOffset,
75
+ groupIndex,
76
+ dataIndex,
77
+ ignoreTick: false,
78
+ labelOffset
79
+ });
80
+ if (!dataIndexToTickIndex.has(dataIndex)) {
81
+ dataIndexToTickIndex.set(dataIndex, new Set());
82
+ }
83
+ const tickIndexes = dataIndexToTickIndex.get(dataIndex);
84
+ for (const previousIndex of tickIndexes.values()) {
85
+ allTickItems[previousIndex].ignoreTick = true;
86
+ }
87
+ tickIndexes.add(allTickItems.length - 1);
88
+ } else {
89
+ currentValueCount += 1;
90
+
91
+ // Calculate the label offset
92
+ const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
93
+ lastItem.labelOffset = labelOffset;
94
+ }
95
+ }
96
+ }
97
+ return allTickItems;
98
+ }
package/esm/index.d.ts CHANGED
@@ -26,4 +26,5 @@ export * from "./ChartsSurface/index.js";
26
26
  export { ChartContainer } from "./ChartContainer/index.js";
27
27
  export type { ChartContainerProps } from "./ChartContainer/index.js";
28
28
  export * from "./ChartDataProvider/index.js";
29
- export * from "./Toolbar/index.js";
29
+ export * from "./Toolbar/index.js";
30
+ export * from "./ChartsWrapper/index.js";
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts v8.9.0
2
+ * @mui/x-charts v8.10.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -32,4 +32,8 @@ export * from "./RadarChart/index.js";
32
32
  export * from "./ChartsSurface/index.js";
33
33
  export { ChartContainer } from "./ChartContainer/index.js";
34
34
  export * from "./ChartDataProvider/index.js";
35
- export * from "./Toolbar/index.js";
35
+ export * from "./Toolbar/index.js";
36
+ export * from "./ChartsWrapper/index.js";
37
+
38
+ // Locales should be imported from `@mui/x-charts/locales`
39
+ // export * from './locales';
@@ -0,0 +1 @@
1
+ export declare function findMinMax(data: readonly number[]): [number, number];
@@ -0,0 +1,13 @@
1
+ export function findMinMax(data) {
2
+ let min = Infinity;
3
+ let max = -Infinity;
4
+ for (const value of data ?? []) {
5
+ if (value < min) {
6
+ min = value;
7
+ }
8
+ if (value > max) {
9
+ max = value;
10
+ }
11
+ }
12
+ return [min, max];
13
+ }
@@ -1,2 +1,2 @@
1
1
  import { ContinuousScaleName, D3ContinuousScale } from "../models/axis.js";
2
- export declare function getScale(scaleType: ContinuousScaleName, domain: any[], range: any[]): D3ContinuousScale;
2
+ export declare function getScale(scaleType: ContinuousScaleName, domain: readonly any[], range: readonly any[]): D3ContinuousScale;
@@ -1,4 +1,5 @@
1
1
  import { scaleLog, scalePow, scaleSqrt, scaleTime, scaleUtc, scaleLinear } from '@mui/x-charts-vendor/d3-scale';
2
+ import { scaleSymlog } from "./symlogScale.js";
2
3
  export function getScale(scaleType, domain, range) {
3
4
  switch (scaleType) {
4
5
  case 'log':
@@ -11,6 +12,8 @@ export function getScale(scaleType, domain, range) {
11
12
  return scaleTime(domain, range);
12
13
  case 'utc':
13
14
  return scaleUtc(domain, range);
15
+ case 'symlog':
16
+ return scaleSymlog(domain, range);
14
17
  default:
15
18
  return scaleLinear(domain, range);
16
19
  }
@@ -1,5 +1,4 @@
1
1
  export * from "./components/ChartsAxesGradients/index.js";
2
- export * from "./components/ChartsWrapper/index.js";
3
2
  export * from "../ChartsLabel/ChartsLabelMark.js";
4
3
  export * from "./components/NotRendered.js";
5
4
  export { useSeries } from "../hooks/useSeries.js";
@@ -54,6 +53,7 @@ export * from "./ticks.js";
54
53
  export * from "./dateHelpers.js";
55
54
  export * from "./invertScale.js";
56
55
  export * from "./isBandScale.js";
56
+ export * from "./findMinMax.js";
57
57
  export { getAxisExtremum } from "./plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.js";
58
58
  export * from "../context/ChartProvider/index.js";
59
59
  export * from "../context/ChartsSlotsContext.js";
@@ -1,6 +1,5 @@
1
1
  // Components
2
2
  export * from "./components/ChartsAxesGradients/index.js";
3
- export * from "./components/ChartsWrapper/index.js";
4
3
  export * from "../ChartsLabel/ChartsLabelMark.js";
5
4
  export * from "./components/NotRendered.js";
6
5
 
@@ -64,6 +63,7 @@ export * from "./ticks.js";
64
63
  export * from "./dateHelpers.js";
65
64
  export * from "./invertScale.js";
66
65
  export * from "./isBandScale.js";
66
+ export * from "./findMinMax.js";
67
67
 
68
68
  // contexts
69
69
  export { getAxisExtremum } from "./plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.js";
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { scaleBand, scalePoint } from '@mui/x-charts-vendor/d3-scale';
3
3
  import { createScalarFormatter } from "../../../defaultValueFormatters.js";
4
- import { isBandScaleConfig, isPointScaleConfig } from "../../../../models/axis.js";
4
+ import { isBandScaleConfig, isPointScaleConfig, isSymlogScaleConfig } from "../../../../models/axis.js";
5
5
  import { getColorScale, getOrdinalColorScale } from "../../../colorScale.js";
6
6
  import { getTickNumber, scaleTickNumberByRange } from "../../../ticks.js";
7
7
  import { getScale } from "../../../getScale.js";
@@ -114,6 +114,9 @@ export function computeAxisValue({
114
114
  const tickNumber = scaleTickNumberByRange(rawTickNumber, zoomRange);
115
115
  const zoomedRange = zoomScaleRange(range, zoomRange);
116
116
  const scale = getScale(scaleType, axisExtremums, zoomedRange);
117
+ if (isSymlogScaleConfig(axis) && axis.constant != null) {
118
+ scale.constant(axis.constant);
119
+ }
117
120
  const finalScale = domainLimit === 'nice' ? scale.nice(rawTickNumber) : scale;
118
121
  const [minDomain, maxDomain] = finalScale.domain();
119
122
  const domain = [axis.min ?? minDomain, axis.max ?? maxDomain];
@@ -1,4 +1,4 @@
1
- import { AxisId, ChartsXAxisProps, ChartsYAxisProps, ScaleName } from "../../../../models/axis.js";
1
+ import { AxisId, ChartsXAxisProps, ChartsYAxisProps, ContinuousScaleName, ScaleName } from "../../../../models/axis.js";
2
2
  import { CartesianChartSeriesType } from "../../../../models/seriesType/config.js";
3
3
  import { ProcessedSeries } from "../../corePlugins/useChartSeries/index.js";
4
4
  import { AxisConfig } from "../../../../models/index.js";
@@ -19,4 +19,6 @@ export declare function createAxisFilterMapper(params: {
19
19
  formattedSeries: ProcessedSeries;
20
20
  direction: 'y';
21
21
  }): (axis: AxisConfig<ScaleName, any, ChartsYAxisProps>, axisIndex: number) => ExtremumFilter | null;
22
+ export declare function createDiscreteScaleGetAxisFilter(axisData: AxisConfig['data'], zoomStart: number, zoomEnd: number, direction: 'x' | 'y'): ExtremumFilter;
23
+ export declare function createContinuousScaleGetAxisFilter(scaleType: ContinuousScaleName | undefined, extrema: readonly [number, number], zoomStart: number, zoomEnd: number, direction: 'x' | 'y', axisData: AxisConfig['data']): ExtremumFilter;
22
24
  export declare const createGetAxisFilters: (filters: ZoomAxisFilters) => GetZoomAxisFilters;
@@ -18,32 +18,41 @@ export function createAxisFilterMapper({
18
18
  // No zoom, or zoom with all data visible
19
19
  return null;
20
20
  }
21
- let extremums = [];
22
21
  const scaleType = axis.scaleType;
23
22
  if (scaleType === 'point' || scaleType === 'band') {
24
- extremums = [0, (axis.data?.length ?? 1) - 1];
25
- } else {
26
- extremums = getAxisExtremum(axis, direction, seriesConfig, axisIndex, formattedSeries);
23
+ return createDiscreteScaleGetAxisFilter(axis.data, zoom.start, zoom.end, direction);
27
24
  }
28
- let min;
29
- let max;
30
- const continuousScaleType = !scaleType || scaleType === 'band' || scaleType === 'point' ? 'linear' : scaleType;
31
- [min, max] = getScale(continuousScaleType, extremums, [0, 100]).nice().domain();
32
- min = min instanceof Date ? min.getTime() : min;
33
- max = max instanceof Date ? max.getTime() : max;
34
- const minVal = min + zoom.start * (max - min) / 100;
35
- const maxVal = min + zoom.end * (max - min) / 100;
36
- return (value, dataIndex) => {
37
- const val = value[direction] ?? axis.data?.[dataIndex];
38
- if (val == null) {
39
- // If the value does not exist because of missing data point, or out of range index, we just ignore.
40
- return true;
41
- }
42
- if (axis.scaleType === 'point' || axis.scaleType === 'band' || typeof val === 'string') {
43
- return dataIndex >= minVal && dataIndex <= maxVal;
44
- }
45
- return val >= minVal && val <= maxVal;
46
- };
25
+ return createContinuousScaleGetAxisFilter(scaleType, getAxisExtremum(axis, direction, seriesConfig, axisIndex, formattedSeries), zoom.start, zoom.end, direction, axis.data);
26
+ };
27
+ }
28
+ export function createDiscreteScaleGetAxisFilter(axisData, zoomStart, zoomEnd, direction) {
29
+ const maxIndex = axisData?.length ?? 0;
30
+ const minVal = Math.floor(zoomStart * maxIndex / 100);
31
+ const maxVal = Math.ceil(zoomEnd * maxIndex / 100);
32
+ return function filterAxis(value, dataIndex) {
33
+ const val = value[direction] ?? axisData?.[dataIndex];
34
+ if (val == null) {
35
+ // If the value does not exist because of missing data point, or out of range index, we just ignore.
36
+ return true;
37
+ }
38
+ return dataIndex >= minVal && dataIndex < maxVal;
39
+ };
40
+ }
41
+ export function createContinuousScaleGetAxisFilter(scaleType, extrema, zoomStart, zoomEnd, direction, axisData) {
42
+ let min;
43
+ let max;
44
+ [min, max] = getScale(scaleType ?? 'linear', extrema, [0, 100]).nice().domain();
45
+ min = min instanceof Date ? min.getTime() : min;
46
+ max = max instanceof Date ? max.getTime() : max;
47
+ const minVal = min + zoomStart * (max - min) / 100;
48
+ const maxVal = min + zoomEnd * (max - min) / 100;
49
+ return function filterAxis(value, dataIndex) {
50
+ const val = value[direction] ?? axisData?.[dataIndex];
51
+ if (val == null) {
52
+ // If the value does not exist because of missing data point, or out of range index, we just ignore.
53
+ return true;
54
+ }
55
+ return val >= minVal && val <= maxVal;
47
56
  };
48
57
  }
49
58
  export const createGetAxisFilters = filters => ({
@@ -3,4 +3,4 @@ import { CartesianChartSeriesType } from "../../../../models/seriesType/config.j
3
3
  import { ChartSeriesConfig } from "../../models/seriesConfig/index.js";
4
4
  import { ProcessedSeries } from "../../corePlugins/useChartSeries/useChartSeries.types.js";
5
5
  import { GetZoomAxisFilters } from "./zoom.types.js";
6
- export declare const getAxisExtremum: <T extends CartesianChartSeriesType>(axis: AxisConfig, axisDirection: "x" | "y", seriesConfig: ChartSeriesConfig<T>, axisIndex: number, formattedSeries: ProcessedSeries<T>, getFilters?: GetZoomAxisFilters) => number[];
6
+ export declare const getAxisExtremum: <T extends CartesianChartSeriesType>(axis: AxisConfig, axisDirection: "x" | "y", seriesConfig: ChartSeriesConfig<T>, axisIndex: number, formattedSeries: ProcessedSeries<T>, getFilters?: GetZoomAxisFilters) => [number, number];
@@ -67,22 +67,24 @@ export const useChartVoronoi = ({
67
67
  const yScale = yAxis[yAxisId ?? defaultYAxisId].scale;
68
68
  const getXPosition = getValueToPositionMapper(xScale);
69
69
  const getYPosition = getValueToPositionMapper(yScale);
70
- const seriesPoints = data.flatMap(({
71
- x,
72
- y
73
- }) => {
70
+ const seriesPoints = [];
71
+ const seriesIndexes = [];
72
+ for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) {
73
+ const {
74
+ x,
75
+ y
76
+ } = data[dataIndex];
74
77
  const pointX = getXPosition(x);
75
78
  const pointY = getYPosition(y);
76
- if (!instance.isPointInside(pointX, pointY)) {
77
- // If the point is not displayed we move them to a trash coordinate.
78
- // This avoids managing index mapping before/after filtering.
79
- // The trash point is far enough such that any point in the drawing area will be closer to the mouse than the trash coordinate.
80
- return [-drawingArea.width, -drawingArea.height];
79
+ if (instance.isPointInside(pointX, pointY)) {
80
+ seriesPoints.push(pointX);
81
+ seriesPoints.push(pointY);
82
+ seriesIndexes.push(dataIndex);
81
83
  }
82
- return [pointX, pointY];
83
- });
84
+ }
84
85
  voronoiRef.current[seriesId] = {
85
86
  seriesId,
87
+ seriesIndexes,
86
88
  startIndex: points.length,
87
89
  endIndex: points.length + seriesPoints.length
88
90
  };
@@ -117,7 +119,10 @@ export const useChartVoronoi = ({
117
119
  if (closestSeries === undefined) {
118
120
  return 'no-point-found';
119
121
  }
120
- const dataIndex = (2 * closestPointIndex - voronoiRef.current[closestSeries.seriesId].startIndex) / 2;
122
+
123
+ // The point index in the series with id=closestSeries.seriesId.
124
+ const seriesPointIndex = (2 * closestPointIndex - voronoiRef.current[closestSeries.seriesId].startIndex) / 2;
125
+ const dataIndex = voronoiRef.current[closestSeries.seriesId].seriesIndexes[seriesPointIndex];
121
126
  if (voronoiMaxRadius !== undefined) {
122
127
  const pointX = delauneyRef.current.points[2 * closestPointIndex];
123
128
  const pointY = delauneyRef.current.points[2 * closestPointIndex + 1];
@@ -0,0 +1,2 @@
1
+ import { NumberValue, ScaleSymLog } from '@mui/x-charts-vendor/d3-scale';
2
+ export declare function scaleSymlog<Range, Output = Range, Unknown = never>(_domain: Iterable<NumberValue>, _range: Iterable<Range>): ScaleSymLog<Range, Output, Unknown>;