@mui/x-charts 8.9.2 → 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 (68) hide show
  1. package/BarChart/BarChart.js +16 -0
  2. package/CHANGELOG.md +121 -6
  3. package/ChartContainer/ChartContainer.js +24 -0
  4. package/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
  5. package/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
  6. package/ChartsTooltip/ChartsTooltip.d.ts +2 -1
  7. package/ChartsTooltip/ChartsTooltip.js +3 -3
  8. package/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
  9. package/ChartsTooltip/ChartsTooltipContainer.js +3 -3
  10. package/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
  11. package/ChartsXAxis/ChartsGroupedXAxis.js +142 -0
  12. package/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
  13. package/ChartsXAxis/ChartsSingleXAxis.js +144 -0
  14. package/ChartsXAxis/ChartsXAxis.d.ts +1 -1
  15. package/ChartsXAxis/ChartsXAxis.js +8 -210
  16. package/ChartsXAxis/getVisibleLabels.d.ts +2 -2
  17. package/ChartsXAxis/useAxisProps.d.ts +4526 -0
  18. package/ChartsXAxis/useAxisProps.js +105 -0
  19. package/ChartsXAxis/utilities.d.ts +11 -0
  20. package/ChartsXAxis/utilities.js +43 -0
  21. package/LineChart/LineChart.js +16 -0
  22. package/RadarChart/index.d.ts +9 -2
  23. package/RadarChart/index.js +13 -14
  24. package/ScatterChart/ScatterChart.d.ts +8 -1
  25. package/ScatterChart/ScatterChart.js +16 -0
  26. package/SparkLineChart/SparkLineChart.js +16 -0
  27. package/esm/BarChart/BarChart.js +16 -0
  28. package/esm/ChartContainer/ChartContainer.js +24 -0
  29. package/esm/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
  30. package/esm/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
  31. package/esm/ChartsTooltip/ChartsTooltip.d.ts +2 -1
  32. package/esm/ChartsTooltip/ChartsTooltip.js +3 -3
  33. package/esm/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
  34. package/esm/ChartsTooltip/ChartsTooltipContainer.js +3 -3
  35. package/esm/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
  36. package/esm/ChartsXAxis/ChartsGroupedXAxis.js +136 -0
  37. package/esm/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
  38. package/esm/ChartsXAxis/ChartsSingleXAxis.js +140 -0
  39. package/esm/ChartsXAxis/ChartsXAxis.d.ts +1 -1
  40. package/esm/ChartsXAxis/ChartsXAxis.js +7 -207
  41. package/esm/ChartsXAxis/getVisibleLabels.d.ts +2 -2
  42. package/esm/ChartsXAxis/useAxisProps.d.ts +4526 -0
  43. package/esm/ChartsXAxis/useAxisProps.js +98 -0
  44. package/esm/ChartsXAxis/utilities.d.ts +11 -0
  45. package/esm/ChartsXAxis/utilities.js +35 -0
  46. package/esm/LineChart/LineChart.js +16 -0
  47. package/esm/RadarChart/index.d.ts +9 -2
  48. package/esm/RadarChart/index.js +12 -2
  49. package/esm/ScatterChart/ScatterChart.d.ts +8 -1
  50. package/esm/ScatterChart/ScatterChart.js +16 -0
  51. package/esm/SparkLineChart/SparkLineChart.js +16 -0
  52. package/esm/hooks/useTicksGrouped.d.ts +28 -0
  53. package/esm/hooks/useTicksGrouped.js +98 -0
  54. package/esm/index.js +1 -1
  55. package/esm/internals/getScale.d.ts +1 -1
  56. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
  57. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +32 -23
  58. package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
  59. package/esm/models/axis.d.ts +61 -0
  60. package/hooks/useTicksGrouped.d.ts +28 -0
  61. package/hooks/useTicksGrouped.js +104 -0
  62. package/index.js +1 -1
  63. package/internals/getScale.d.ts +1 -1
  64. package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
  65. package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +34 -23
  66. package/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
  67. package/models/axis.d.ts +61 -0
  68. package/package.json +3 -4
@@ -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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts v8.9.2
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
@@ -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,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];
package/models/axis.d.ts CHANGED
@@ -180,6 +180,21 @@ export interface ChartsRadiusAxisProps extends ChartsAxisProps {
180
180
  }
181
181
  export type ScaleName = keyof AxisScaleConfig;
182
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,11 +212,57 @@ 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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-charts",
3
- "version": "8.9.2",
3
+ "version": "8.10.0",
4
4
  "author": "MUI Team",
5
5
  "description": "The community edition of MUI X Charts components.",
6
6
  "main": "./index.js",
@@ -36,8 +36,8 @@
36
36
  "reselect": "^5.1.1",
37
37
  "use-sync-external-store": "^1.5.0",
38
38
  "@mui/x-charts-vendor": "8.6.0",
39
- "@mui/x-internal-gestures": "0.2.2",
40
- "@mui/x-internals": "8.9.2"
39
+ "@mui/x-internal-gestures": "0.2.3",
40
+ "@mui/x-internals": "8.10.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@emotion/react": "^11.9.0",
@@ -59,7 +59,6 @@
59
59
  "node": ">=14.0.0"
60
60
  },
61
61
  "private": false,
62
- "module": "./esm/index.js",
63
62
  "exports": {
64
63
  "./package.json": "./package.json",
65
64
  ".": {