@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
@@ -0,0 +1,94 @@
1
+ import { scaleSymlog as originalScaleSymlog, scaleLog, scaleLinear } from '@mui/x-charts-vendor/d3-scale';
2
+ export function scaleSymlog(_domain, _range) {
3
+ const scale = originalScaleSymlog(_domain, _range);
4
+ const originalTicks = scale.ticks;
5
+ const {
6
+ negativeScale,
7
+ linearScale,
8
+ positiveScale
9
+ } = generateScales(scale);
10
+
11
+ // Workaround for https://github.com/d3/d3-scale/issues/162
12
+ scale.ticks = count => {
13
+ const ticks = originalTicks(count);
14
+ const constant = scale.constant();
15
+ let negativeLogTickCount = 0;
16
+ let linearTickCount = 0;
17
+ let positiveLogTickCount = 0;
18
+ ticks.forEach(tick => {
19
+ if (tick > -constant && tick < constant) {
20
+ linearTickCount += 1;
21
+ }
22
+ if (tick <= -constant) {
23
+ negativeLogTickCount += 1;
24
+ }
25
+ if (tick >= constant) {
26
+ positiveLogTickCount += 1;
27
+ }
28
+ });
29
+ const finalTicks = [];
30
+ if (negativeLogTickCount > 0) {
31
+ finalTicks.push(...negativeScale.ticks(negativeLogTickCount));
32
+ }
33
+ if (linearTickCount > 0) {
34
+ const linearTicks = linearScale.ticks(linearTickCount);
35
+ if (finalTicks.at(-1) === linearTicks[0]) {
36
+ finalTicks.push(...linearTicks.slice(1));
37
+ } else {
38
+ finalTicks.push(...linearTicks);
39
+ }
40
+ }
41
+ if (positiveLogTickCount > 0) {
42
+ const positiveTicks = positiveScale.ticks(positiveLogTickCount);
43
+ if (finalTicks.at(-1) === positiveTicks[0]) {
44
+ finalTicks.push(...positiveTicks.slice(1));
45
+ } else {
46
+ finalTicks.push(...positiveTicks);
47
+ }
48
+ }
49
+ return finalTicks;
50
+ };
51
+ scale.tickFormat = (count = 10, specifier) => {
52
+ // Calculates the proportion of the domain that each scale occupies, and use that ratio to determine the number of ticks for each scale.
53
+ const constant = scale.constant();
54
+ const [start, end] = scale.domain();
55
+ const extent = end - start;
56
+ const negativeScaleDomain = negativeScale.domain();
57
+ const negativeScaleExtent = negativeScaleDomain[1] - negativeScaleDomain[0];
58
+ const negativeScaleRatio = extent === 0 ? 0 : negativeScaleExtent / extent;
59
+ const negativeScaleTickCount = negativeScaleRatio * count;
60
+ const linearScaleDomain = linearScale.domain();
61
+ const linearScaleExtent = linearScaleDomain[1] - linearScaleDomain[0];
62
+ const linearScaleRatio = extent === 0 ? 0 : linearScaleExtent / extent;
63
+ const linearScaleTickCount = linearScaleRatio * count;
64
+ const positiveScaleDomain = positiveScale.domain();
65
+ const positiveScaleExtent = positiveScaleDomain[1] - positiveScaleDomain[0];
66
+ const positiveScaleRatio = extent === 0 ? 0 : positiveScaleExtent / extent;
67
+ const positiveScaleTickCount = positiveScaleRatio * count;
68
+ const negativeTickFormat = negativeScale.tickFormat(negativeScaleTickCount, specifier);
69
+ const linearTickFormat = linearScale.tickFormat(linearScaleTickCount, specifier);
70
+ const positiveTickFormat = positiveScale.tickFormat(positiveScaleTickCount, specifier);
71
+ return tick => {
72
+ const tickFormat =
73
+ // eslint-disable-next-line no-nested-ternary
74
+ tick.valueOf() <= -constant ? negativeTickFormat : tick.valueOf() >= constant ? positiveTickFormat : linearTickFormat;
75
+ return tickFormat(tick);
76
+ };
77
+ };
78
+ return scale;
79
+ }
80
+ function generateScales(scale) {
81
+ const constant = scale.constant();
82
+ const domain = scale.domain();
83
+ const negativeDomain = [domain[0], Math.min(domain[1], -constant)];
84
+ const negativeLogScale = scaleLog(negativeDomain, scale.range());
85
+ const linearDomain = [Math.max(domain[0], -constant), Math.min(domain[1], constant)];
86
+ const linearScale = scaleLinear(linearDomain, scale.range());
87
+ const positiveDomain = [Math.max(domain[0], constant), domain[1]];
88
+ const positiveLogScale = scaleLog(positiveDomain, scale.range());
89
+ return {
90
+ negativeScale: negativeLogScale,
91
+ linearScale,
92
+ positiveScale: positiveLogScale
93
+ };
94
+ }
@@ -1,4 +1,4 @@
1
- import type { ScaleBand, ScaleLinear, ScaleLogarithmic, ScaleOrdinal, ScalePoint, ScalePower, ScaleSequential, ScaleThreshold, ScaleTime } from '@mui/x-charts-vendor/d3-scale';
1
+ import type { ScaleBand, ScaleLinear, ScaleLogarithmic, ScaleOrdinal, ScalePoint, ScalePower, ScaleSequential, ScaleThreshold, ScaleTime, ScaleSymLog } from '@mui/x-charts-vendor/d3-scale';
2
2
  import { SxProps } from '@mui/system/styleFunctionSx';
3
3
  import { type MakeOptional, MakeRequired } from '@mui/x-internals/types';
4
4
  import type { DefaultizedZoomOptions } from "../internals/plugins/featurePlugins/useChartCartesianAxis/index.js";
@@ -9,8 +9,8 @@ import { ContinuousColorConfig, OrdinalColorConfig, PiecewiseColorConfig } from
9
9
  export type AxisId = string | number;
10
10
  export type D3Scale<Domain extends {
11
11
  toString(): string;
12
- } = number | Date | string, Range = number, Output = number> = ScaleBand<Domain> | ScaleLogarithmic<Range, Output> | ScalePoint<Domain> | ScalePower<Range, Output> | ScaleTime<Range, Output> | ScaleLinear<Range, Output>;
13
- export type D3ContinuousScale<Range = number, Output = number> = ScaleLogarithmic<Range, Output> | ScalePower<Range, Output> | ScaleTime<Range, Output> | ScaleLinear<Range, Output>;
12
+ } = number | Date | string, Range = number, Output = number> = ScaleBand<Domain> | ScaleSymLog<Range, Output> | ScaleLogarithmic<Range, Output> | ScalePoint<Domain> | ScalePower<Range, Output> | ScaleTime<Range, Output> | ScaleLinear<Range, Output>;
13
+ export type D3ContinuousScale<Range = number, Output = number> = ScaleSymLog<Range, Output> | ScaleLogarithmic<Range, Output> | ScalePower<Range, Output> | ScaleTime<Range, Output> | ScaleLinear<Range, Output>;
14
14
  export interface ChartsAxisSlots {
15
15
  /**
16
16
  * Custom component for the axis main line.
@@ -179,7 +179,22 @@ export interface ChartsRadiusAxisProps extends ChartsAxisProps {
179
179
  maxRadius?: number;
180
180
  }
181
181
  export type ScaleName = keyof AxisScaleConfig;
182
- export type ContinuousScaleName = 'linear' | 'log' | 'pow' | 'sqrt' | 'time' | 'utc';
182
+ export type ContinuousScaleName = 'linear' | 'log' | 'symlog' | 'pow' | 'sqrt' | 'time' | 'utc';
183
+ export type AxisGroup = {
184
+ /**
185
+ * The function used to return the value for this group.
186
+ *
187
+ * @param {any} value The value of the axis item.
188
+ * @param {number} dataIndex The index of the data item.
189
+ * @returns {string | number | Date} The value that will be used to group the axis items.
190
+ */
191
+ getValue: (value: any, dataIndex: number) => string | number | Date;
192
+ /**
193
+ * The size of the tick in pixels.
194
+ * @default 6
195
+ */
196
+ tickSize?: number;
197
+ };
183
198
  export interface AxisScaleConfig {
184
199
  band: {
185
200
  scaleType: 'band';
@@ -197,17 +212,73 @@ export interface AxisScaleConfig {
197
212
  */
198
213
  barGapRatio: number;
199
214
  colorMap?: OrdinalColorConfig | ContinuousColorConfig | PiecewiseColorConfig;
215
+ /**
216
+ * Each group will have a label that is the stringified value of the group.
217
+ *
218
+ * @example
219
+ * If the axis is grouped by day, month and year.
220
+ *
221
+ * ```tsx
222
+ * [
223
+ * { getValue: getDate },
224
+ * { getValue: getMonth },
225
+ * { getValue: getFullYear }
226
+ * ]
227
+ * ```
228
+ *
229
+ * Then the axis will have three rows, one for each group.
230
+ *
231
+ * ```bash
232
+ * | 31 | 1 | 2 |
233
+ * | Jan | Feb |
234
+ * | 2021 |
235
+ * ```
236
+ */
237
+ groups?: AxisGroup[];
200
238
  } & Pick<TickParams, 'tickPlacement' | 'tickLabelPlacement'>;
201
239
  point: {
202
240
  scaleType: 'point';
203
241
  scale: ScalePoint<number | Date | string>;
204
242
  colorMap?: OrdinalColorConfig | ContinuousColorConfig | PiecewiseColorConfig;
243
+ /**
244
+ * Each group will have a label that is the stringified value of the group.
245
+ *
246
+ * @example
247
+ * If the axis is grouped by day, month and year.
248
+ *
249
+ * ```tsx
250
+ * [
251
+ * { getValue: getDate },
252
+ * { getValue: getMonth },
253
+ * { getValue: getFullYear }
254
+ * ]
255
+ * ```
256
+ *
257
+ * Then the axis will have three rows, one for each group.
258
+ *
259
+ * ```bash
260
+ * | 31 | 1 | 2 |
261
+ * | Jan | Feb |
262
+ * | 2021 |
263
+ * ```
264
+ */
265
+ groups?: AxisGroup[];
205
266
  };
206
267
  log: {
207
268
  scaleType: 'log';
208
269
  scale: ScaleLogarithmic<number, number>;
209
270
  colorMap?: ContinuousColorConfig | PiecewiseColorConfig;
210
271
  };
272
+ symlog: {
273
+ scaleType: 'symlog';
274
+ scale: ScaleSymLog<number, number>;
275
+ colorMap?: ContinuousColorConfig | PiecewiseColorConfig;
276
+ /**
277
+ * The constant used to define the zero point of the symlog scale.
278
+ * @default 1
279
+ */
280
+ constant?: number;
281
+ };
211
282
  pow: {
212
283
  scaleType: 'pow';
213
284
  scale: ScalePower<number, number>;
@@ -248,6 +319,9 @@ export interface AxisScaleComputedConfig {
248
319
  log: {
249
320
  colorScale?: ScaleSequential<string, string | null> | ScaleThreshold<number, string | null>;
250
321
  };
322
+ symlog: {
323
+ colorScale?: ScaleSequential<string, string | null> | ScaleThreshold<number, string | null>;
324
+ };
251
325
  pow: {
252
326
  colorScale?: ScaleSequential<string, string | null> | ScaleThreshold<number, string | null>;
253
327
  };
@@ -417,6 +491,9 @@ export declare function isBandScaleConfig(scaleConfig: AxisConfig<ScaleName>): s
417
491
  export declare function isPointScaleConfig(scaleConfig: AxisConfig<ScaleName>): scaleConfig is AxisConfig<'point'> & {
418
492
  scaleType: 'point';
419
493
  };
494
+ export declare function isSymlogScaleConfig(scaleConfig: AxisConfig<ScaleName>): scaleConfig is AxisConfig<'symlog'> & {
495
+ scaleType: 'symlog';
496
+ };
420
497
  /**
421
498
  * The data format returned by onAxisClick.
422
499
  */
@@ -17,6 +17,9 @@ export function isBandScaleConfig(scaleConfig) {
17
17
  export function isPointScaleConfig(scaleConfig) {
18
18
  return scaleConfig.scaleType === 'point';
19
19
  }
20
+ export function isSymlogScaleConfig(scaleConfig) {
21
+ return scaleConfig.scaleType === 'symlog';
22
+ }
20
23
 
21
24
  /**
22
25
  * The data format returned by onAxisClick.
@@ -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,104 @@
1
+ "use strict";
2
+ 'use client';
3
+
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.useTicksGrouped = useTicksGrouped;
9
+ var React = _interopRequireWildcard(require("react"));
10
+ var _isBandScale = require("../internals/isBandScale");
11
+ const offsetRatio = {
12
+ start: 0,
13
+ extremities: 0,
14
+ end: 1,
15
+ middle: 0.5,
16
+ tick: 0
17
+ };
18
+ function useTicksGrouped(options) {
19
+ const {
20
+ scale,
21
+ tickInterval,
22
+ tickLabelPlacement = 'middle',
23
+ tickPlacement = 'extremities',
24
+ groups
25
+ } = options;
26
+ return React.useMemo(() => {
27
+ const domain = scale.domain();
28
+ const filteredDomain = typeof tickInterval === 'function' && domain.filter(tickInterval) || typeof tickInterval === 'object' && tickInterval || domain;
29
+ if (scale.bandwidth() > 0) {
30
+ // scale type = 'band'
31
+ const entries = mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
32
+ if (entries[0]) {
33
+ entries[0].ignoreTick = true;
34
+ }
35
+ return [{
36
+ formattedValue: undefined,
37
+ offset: scale.range()[0],
38
+ labelOffset: 0,
39
+ groupIndex: groups.length - 1
40
+ }, ...entries,
41
+ // Last tick
42
+ {
43
+ formattedValue: undefined,
44
+ offset: scale.range()[1],
45
+ labelOffset: 0,
46
+ groupIndex: groups.length - 1
47
+ }];
48
+ }
49
+
50
+ // scale type = 'point'
51
+ return mapToGrouping(filteredDomain, groups, tickPlacement, tickLabelPlacement, scale);
52
+ }, [scale, tickInterval, groups, tickPlacement, tickLabelPlacement]);
53
+ }
54
+ function mapToGrouping(tickValues, groups, tickPlacement, tickLabelPlacement, scale) {
55
+ const allTickItems = [];
56
+ // Map to keep track of offsets and their corresponding tick indexes
57
+ // Used to remove redundant ticks when they are in the same position
58
+ const dataIndexToTickIndex = new Map();
59
+ let currentValueCount = 0;
60
+ for (let groupIndex = 0; groupIndex < groups.length; groupIndex += 1) {
61
+ for (let dataIndex = 0; dataIndex < tickValues.length; dataIndex += 1) {
62
+ const tickValue = tickValues[dataIndex];
63
+ const groupValue = groups[groupIndex].getValue(tickValue, dataIndex);
64
+ const lastItem = allTickItems[allTickItems.length - 1];
65
+
66
+ // Check if this is a new unique value for this group
67
+ const isNew = lastItem?.value !== groupValue || lastItem?.groupIndex !== groupIndex;
68
+ if (isNew) {
69
+ currentValueCount = 1;
70
+ // Calculate tick offset
71
+ const tickOffset = (0, _isBandScale.isBandScale)(scale) ? scale(tickValue) - (scale.step() - scale.bandwidth()) / 2 + offsetRatio[tickPlacement] * scale.step() : scale(tickValue);
72
+
73
+ // Calculate the label offset
74
+ const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
75
+
76
+ // Add a new item
77
+ allTickItems.push({
78
+ value: groupValue,
79
+ formattedValue: `${groupValue}`,
80
+ offset: tickOffset,
81
+ groupIndex,
82
+ dataIndex,
83
+ ignoreTick: false,
84
+ labelOffset
85
+ });
86
+ if (!dataIndexToTickIndex.has(dataIndex)) {
87
+ dataIndexToTickIndex.set(dataIndex, new Set());
88
+ }
89
+ const tickIndexes = dataIndexToTickIndex.get(dataIndex);
90
+ for (const previousIndex of tickIndexes.values()) {
91
+ allTickItems[previousIndex].ignoreTick = true;
92
+ }
93
+ tickIndexes.add(allTickItems.length - 1);
94
+ } else {
95
+ currentValueCount += 1;
96
+
97
+ // Calculate the label offset
98
+ const labelOffset = scale.step() * currentValueCount * (offsetRatio[tickLabelPlacement] - offsetRatio[tickPlacement]);
99
+ lastItem.labelOffset = labelOffset;
100
+ }
101
+ }
102
+ }
103
+ return allTickItems;
104
+ }
package/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/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
@@ -343,4 +343,16 @@ Object.keys(_Toolbar).forEach(function (key) {
343
343
  return _Toolbar[key];
344
344
  }
345
345
  });
346
+ });
347
+ var _ChartsWrapper = require("./ChartsWrapper");
348
+ Object.keys(_ChartsWrapper).forEach(function (key) {
349
+ if (key === "default" || key === "__esModule") return;
350
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
351
+ if (key in exports && exports[key] === _ChartsWrapper[key]) return;
352
+ Object.defineProperty(exports, key, {
353
+ enumerable: true,
354
+ get: function () {
355
+ return _ChartsWrapper[key];
356
+ }
357
+ });
346
358
  });
@@ -0,0 +1 @@
1
+ export declare function findMinMax(data: readonly number[]): [number, number];
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findMinMax = findMinMax;
7
+ function findMinMax(data) {
8
+ let min = Infinity;
9
+ let max = -Infinity;
10
+ for (const value of data ?? []) {
11
+ if (value < min) {
12
+ min = value;
13
+ }
14
+ if (value > max) {
15
+ max = value;
16
+ }
17
+ }
18
+ return [min, max];
19
+ }
@@ -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;
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.getScale = getScale;
7
7
  var _d3Scale = require("@mui/x-charts-vendor/d3-scale");
8
+ var _symlogScale = require("./symlogScale");
8
9
  function getScale(scaleType, domain, range) {
9
10
  switch (scaleType) {
10
11
  case 'log':
@@ -17,6 +18,8 @@ function getScale(scaleType, domain, range) {
17
18
  return (0, _d3Scale.scaleTime)(domain, range);
18
19
  case 'utc':
19
20
  return (0, _d3Scale.scaleUtc)(domain, range);
21
+ case 'symlog':
22
+ return (0, _symlogScale.scaleSymlog)(domain, range);
20
23
  default:
21
24
  return (0, _d3Scale.scaleLinear)(domain, range);
22
25
  }
@@ -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";
@@ -122,18 +122,6 @@ Object.keys(_ChartsAxesGradients).forEach(function (key) {
122
122
  }
123
123
  });
124
124
  });
125
- var _ChartsWrapper = require("./components/ChartsWrapper");
126
- Object.keys(_ChartsWrapper).forEach(function (key) {
127
- if (key === "default" || key === "__esModule") return;
128
- if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
129
- if (key in exports && exports[key] === _ChartsWrapper[key]) return;
130
- Object.defineProperty(exports, key, {
131
- enumerable: true,
132
- get: function () {
133
- return _ChartsWrapper[key];
134
- }
135
- });
136
- });
137
125
  var _ChartsLabelMark = require("../ChartsLabel/ChartsLabelMark");
138
126
  Object.keys(_ChartsLabelMark).forEach(function (key) {
139
127
  if (key === "default" || key === "__esModule") return;
@@ -628,6 +616,18 @@ Object.keys(_isBandScale).forEach(function (key) {
628
616
  }
629
617
  });
630
618
  });
619
+ var _findMinMax = require("./findMinMax");
620
+ Object.keys(_findMinMax).forEach(function (key) {
621
+ if (key === "default" || key === "__esModule") return;
622
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
623
+ if (key in exports && exports[key] === _findMinMax[key]) return;
624
+ Object.defineProperty(exports, key, {
625
+ enumerable: true,
626
+ get: function () {
627
+ return _findMinMax[key];
628
+ }
629
+ });
630
+ });
631
631
  var _getAxisExtremum = require("./plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum");
632
632
  var _ChartProvider = require("../context/ChartProvider");
633
633
  Object.keys(_ChartProvider).forEach(function (key) {
@@ -121,6 +121,9 @@ function computeAxisValue({
121
121
  const tickNumber = (0, _ticks.scaleTickNumberByRange)(rawTickNumber, zoomRange);
122
122
  const zoomedRange = (0, _zoom.zoomScaleRange)(range, zoomRange);
123
123
  const scale = (0, _getScale.getScale)(scaleType, axisExtremums, zoomedRange);
124
+ if ((0, _axis.isSymlogScaleConfig)(axis) && axis.constant != null) {
125
+ scale.constant(axis.constant);
126
+ }
124
127
  const finalScale = domainLimit === 'nice' ? scale.nice(rawTickNumber) : scale;
125
128
  const [minDomain, maxDomain] = finalScale.domain();
126
129
  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;
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createAxisFilterMapper = createAxisFilterMapper;
7
+ exports.createContinuousScaleGetAxisFilter = createContinuousScaleGetAxisFilter;
8
+ exports.createDiscreteScaleGetAxisFilter = createDiscreteScaleGetAxisFilter;
7
9
  exports.createGetAxisFilters = void 0;
8
10
  var _isDefined = require("../../../isDefined");
9
11
  var _getAxisExtremum = require("./getAxisExtremum");
@@ -25,32 +27,41 @@ function createAxisFilterMapper({
25
27
  // No zoom, or zoom with all data visible
26
28
  return null;
27
29
  }
28
- let extremums = [];
29
30
  const scaleType = axis.scaleType;
30
31
  if (scaleType === 'point' || scaleType === 'band') {
31
- extremums = [0, (axis.data?.length ?? 1) - 1];
32
- } else {
33
- extremums = (0, _getAxisExtremum.getAxisExtremum)(axis, direction, seriesConfig, axisIndex, formattedSeries);
32
+ return createDiscreteScaleGetAxisFilter(axis.data, zoom.start, zoom.end, direction);
34
33
  }
35
- let min;
36
- let max;
37
- const continuousScaleType = !scaleType || scaleType === 'band' || scaleType === 'point' ? 'linear' : scaleType;
38
- [min, max] = (0, _getScale.getScale)(continuousScaleType, extremums, [0, 100]).nice().domain();
39
- min = min instanceof Date ? min.getTime() : min;
40
- max = max instanceof Date ? max.getTime() : max;
41
- const minVal = min + zoom.start * (max - min) / 100;
42
- const maxVal = min + zoom.end * (max - min) / 100;
43
- return (value, dataIndex) => {
44
- const val = value[direction] ?? axis.data?.[dataIndex];
45
- if (val == null) {
46
- // If the value does not exist because of missing data point, or out of range index, we just ignore.
47
- return true;
48
- }
49
- if (axis.scaleType === 'point' || axis.scaleType === 'band' || typeof val === 'string') {
50
- return dataIndex >= minVal && dataIndex <= maxVal;
51
- }
52
- return val >= minVal && val <= maxVal;
53
- };
34
+ return createContinuousScaleGetAxisFilter(scaleType, (0, _getAxisExtremum.getAxisExtremum)(axis, direction, seriesConfig, axisIndex, formattedSeries), zoom.start, zoom.end, direction, axis.data);
35
+ };
36
+ }
37
+ function createDiscreteScaleGetAxisFilter(axisData, zoomStart, zoomEnd, direction) {
38
+ const maxIndex = axisData?.length ?? 0;
39
+ const minVal = Math.floor(zoomStart * maxIndex / 100);
40
+ const maxVal = Math.ceil(zoomEnd * maxIndex / 100);
41
+ return function filterAxis(value, dataIndex) {
42
+ const val = value[direction] ?? axisData?.[dataIndex];
43
+ if (val == null) {
44
+ // If the value does not exist because of missing data point, or out of range index, we just ignore.
45
+ return true;
46
+ }
47
+ return dataIndex >= minVal && dataIndex < maxVal;
48
+ };
49
+ }
50
+ function createContinuousScaleGetAxisFilter(scaleType, extrema, zoomStart, zoomEnd, direction, axisData) {
51
+ let min;
52
+ let max;
53
+ [min, max] = (0, _getScale.getScale)(scaleType ?? 'linear', extrema, [0, 100]).nice().domain();
54
+ min = min instanceof Date ? min.getTime() : min;
55
+ max = max instanceof Date ? max.getTime() : max;
56
+ const minVal = min + zoomStart * (max - min) / 100;
57
+ const maxVal = min + zoomEnd * (max - min) / 100;
58
+ return function filterAxis(value, dataIndex) {
59
+ const val = value[direction] ?? axisData?.[dataIndex];
60
+ if (val == null) {
61
+ // If the value does not exist because of missing data point, or out of range index, we just ignore.
62
+ return true;
63
+ }
64
+ return val >= minVal && val <= maxVal;
54
65
  };
55
66
  }
56
67
  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];
@@ -74,22 +74,24 @@ const useChartVoronoi = ({
74
74
  const yScale = yAxis[yAxisId ?? defaultYAxisId].scale;
75
75
  const getXPosition = (0, _useScale.getValueToPositionMapper)(xScale);
76
76
  const getYPosition = (0, _useScale.getValueToPositionMapper)(yScale);
77
- const seriesPoints = data.flatMap(({
78
- x,
79
- y
80
- }) => {
77
+ const seriesPoints = [];
78
+ const seriesIndexes = [];
79
+ for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) {
80
+ const {
81
+ x,
82
+ y
83
+ } = data[dataIndex];
81
84
  const pointX = getXPosition(x);
82
85
  const pointY = getYPosition(y);
83
- if (!instance.isPointInside(pointX, pointY)) {
84
- // If the point is not displayed we move them to a trash coordinate.
85
- // This avoids managing index mapping before/after filtering.
86
- // The trash point is far enough such that any point in the drawing area will be closer to the mouse than the trash coordinate.
87
- return [-drawingArea.width, -drawingArea.height];
86
+ if (instance.isPointInside(pointX, pointY)) {
87
+ seriesPoints.push(pointX);
88
+ seriesPoints.push(pointY);
89
+ seriesIndexes.push(dataIndex);
88
90
  }
89
- return [pointX, pointY];
90
- });
91
+ }
91
92
  voronoiRef.current[seriesId] = {
92
93
  seriesId,
94
+ seriesIndexes,
93
95
  startIndex: points.length,
94
96
  endIndex: points.length + seriesPoints.length
95
97
  };
@@ -124,7 +126,10 @@ const useChartVoronoi = ({
124
126
  if (closestSeries === undefined) {
125
127
  return 'no-point-found';
126
128
  }
127
- const dataIndex = (2 * closestPointIndex - voronoiRef.current[closestSeries.seriesId].startIndex) / 2;
129
+
130
+ // The point index in the series with id=closestSeries.seriesId.
131
+ const seriesPointIndex = (2 * closestPointIndex - voronoiRef.current[closestSeries.seriesId].startIndex) / 2;
132
+ const dataIndex = voronoiRef.current[closestSeries.seriesId].seriesIndexes[seriesPointIndex];
128
133
  if (voronoiMaxRadius !== undefined) {
129
134
  const pointX = delauneyRef.current.points[2 * closestPointIndex];
130
135
  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>;