@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.
- package/BarChart/BarChart.js +16 -0
- package/CHANGELOG.md +121 -6
- package/ChartContainer/ChartContainer.js +24 -0
- package/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
- package/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
- package/ChartsTooltip/ChartsTooltip.d.ts +2 -1
- package/ChartsTooltip/ChartsTooltip.js +3 -3
- package/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
- package/ChartsTooltip/ChartsTooltipContainer.js +3 -3
- package/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
- package/ChartsXAxis/ChartsGroupedXAxis.js +142 -0
- package/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
- package/ChartsXAxis/ChartsSingleXAxis.js +144 -0
- package/ChartsXAxis/ChartsXAxis.d.ts +1 -1
- package/ChartsXAxis/ChartsXAxis.js +8 -210
- package/ChartsXAxis/getVisibleLabels.d.ts +2 -2
- package/ChartsXAxis/useAxisProps.d.ts +4526 -0
- package/ChartsXAxis/useAxisProps.js +105 -0
- package/ChartsXAxis/utilities.d.ts +11 -0
- package/ChartsXAxis/utilities.js +43 -0
- package/LineChart/LineChart.js +16 -0
- package/RadarChart/index.d.ts +9 -2
- package/RadarChart/index.js +13 -14
- package/ScatterChart/ScatterChart.d.ts +8 -1
- package/ScatterChart/ScatterChart.js +16 -0
- package/SparkLineChart/SparkLineChart.js +16 -0
- package/esm/BarChart/BarChart.js +16 -0
- package/esm/ChartContainer/ChartContainer.js +24 -0
- package/esm/ChartsAxisHighlight/ChartsXAxisHighlight.js +1 -3
- package/esm/ChartsAxisHighlight/ChartsYAxisHighlight.js +1 -3
- package/esm/ChartsTooltip/ChartsTooltip.d.ts +2 -1
- package/esm/ChartsTooltip/ChartsTooltip.js +3 -3
- package/esm/ChartsTooltip/ChartsTooltipContainer.d.ts +5 -5
- package/esm/ChartsTooltip/ChartsTooltipContainer.js +3 -3
- package/esm/ChartsXAxis/ChartsGroupedXAxis.d.ts +7 -0
- package/esm/ChartsXAxis/ChartsGroupedXAxis.js +136 -0
- package/esm/ChartsXAxis/ChartsSingleXAxis.d.ts +7 -0
- package/esm/ChartsXAxis/ChartsSingleXAxis.js +140 -0
- package/esm/ChartsXAxis/ChartsXAxis.d.ts +1 -1
- package/esm/ChartsXAxis/ChartsXAxis.js +7 -207
- package/esm/ChartsXAxis/getVisibleLabels.d.ts +2 -2
- package/esm/ChartsXAxis/useAxisProps.d.ts +4526 -0
- package/esm/ChartsXAxis/useAxisProps.js +98 -0
- package/esm/ChartsXAxis/utilities.d.ts +11 -0
- package/esm/ChartsXAxis/utilities.js +35 -0
- package/esm/LineChart/LineChart.js +16 -0
- package/esm/RadarChart/index.d.ts +9 -2
- package/esm/RadarChart/index.js +12 -2
- package/esm/ScatterChart/ScatterChart.d.ts +8 -1
- package/esm/ScatterChart/ScatterChart.js +16 -0
- package/esm/SparkLineChart/SparkLineChart.js +16 -0
- package/esm/hooks/useTicksGrouped.d.ts +28 -0
- package/esm/hooks/useTicksGrouped.js +98 -0
- package/esm/index.js +1 -1
- package/esm/internals/getScale.d.ts +1 -1
- package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
- package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +32 -23
- package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
- package/esm/models/axis.d.ts +61 -0
- package/hooks/useTicksGrouped.d.ts +28 -0
- package/hooks/useTicksGrouped.js +104 -0
- package/index.js +1 -1
- package/internals/getScale.d.ts +1 -1
- package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts +3 -1
- package/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js +34 -23
- package/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtremum.d.ts +1 -1
- package/models/axis.d.ts +61 -0
- package/package.json +3 -4
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
4
|
+
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
5
|
+
const _excluded = ["scale", "tickNumber", "reverse"];
|
|
6
|
+
import useSlotProps from '@mui/utils/useSlotProps';
|
|
7
|
+
import { useThemeProps, useTheme } from '@mui/material/styles';
|
|
8
|
+
import { useRtl } from '@mui/system/RtlProvider';
|
|
9
|
+
import { ChartsText } from "../ChartsText/index.js";
|
|
10
|
+
import { useXAxes } from "../hooks/useAxis.js";
|
|
11
|
+
import { getDefaultBaseline, getDefaultTextAnchor } from "../ChartsText/defaultTextPlacement.js";
|
|
12
|
+
import { invertTextAnchor } from "../internals/invertTextAnchor.js";
|
|
13
|
+
import { defaultProps, useUtilityClasses } from "./utilities.js";
|
|
14
|
+
import { isBandScale } from "../internals/isBandScale.js";
|
|
15
|
+
import { isInfinity } from "../internals/isInfinity.js";
|
|
16
|
+
export const useAxisProps = inProps => {
|
|
17
|
+
const {
|
|
18
|
+
xAxis,
|
|
19
|
+
xAxisIds
|
|
20
|
+
} = useXAxes();
|
|
21
|
+
const _xAxis = xAxis[inProps.axisId ?? xAxisIds[0]],
|
|
22
|
+
{
|
|
23
|
+
scale: xScale,
|
|
24
|
+
tickNumber,
|
|
25
|
+
reverse
|
|
26
|
+
} = _xAxis,
|
|
27
|
+
settings = _objectWithoutPropertiesLoose(_xAxis, _excluded);
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line material-ui/mui-name-matches-component-name
|
|
30
|
+
const themedProps = useThemeProps({
|
|
31
|
+
props: _extends({}, settings, inProps),
|
|
32
|
+
name: 'MuiChartsXAxis'
|
|
33
|
+
});
|
|
34
|
+
const defaultizedProps = _extends({}, defaultProps, themedProps);
|
|
35
|
+
const {
|
|
36
|
+
position,
|
|
37
|
+
tickLabelStyle,
|
|
38
|
+
labelStyle,
|
|
39
|
+
slots,
|
|
40
|
+
slotProps
|
|
41
|
+
} = defaultizedProps;
|
|
42
|
+
const theme = useTheme();
|
|
43
|
+
const isRtl = useRtl();
|
|
44
|
+
const classes = useUtilityClasses(defaultizedProps);
|
|
45
|
+
const positionSign = position === 'bottom' ? 1 : -1;
|
|
46
|
+
const Line = slots?.axisLine ?? 'line';
|
|
47
|
+
const Tick = slots?.axisTick ?? 'line';
|
|
48
|
+
const TickLabel = slots?.axisTickLabel ?? ChartsText;
|
|
49
|
+
const Label = slots?.axisLabel ?? ChartsText;
|
|
50
|
+
const defaultTextAnchor = getDefaultTextAnchor((position === 'bottom' ? 0 : 180) - (tickLabelStyle?.angle ?? 0));
|
|
51
|
+
const defaultDominantBaseline = getDefaultBaseline((position === 'bottom' ? 0 : 180) - (tickLabelStyle?.angle ?? 0));
|
|
52
|
+
const axisTickLabelProps = useSlotProps({
|
|
53
|
+
elementType: TickLabel,
|
|
54
|
+
externalSlotProps: slotProps?.axisTickLabel,
|
|
55
|
+
additionalProps: {
|
|
56
|
+
style: _extends({}, theme.typography.caption, {
|
|
57
|
+
fontSize: 12,
|
|
58
|
+
lineHeight: 1.25,
|
|
59
|
+
textAnchor: isRtl ? invertTextAnchor(defaultTextAnchor) : defaultTextAnchor,
|
|
60
|
+
dominantBaseline: defaultDominantBaseline
|
|
61
|
+
}, tickLabelStyle)
|
|
62
|
+
},
|
|
63
|
+
className: classes.tickLabel,
|
|
64
|
+
ownerState: {}
|
|
65
|
+
});
|
|
66
|
+
const axisLabelProps = useSlotProps({
|
|
67
|
+
elementType: Label,
|
|
68
|
+
externalSlotProps: slotProps?.axisLabel,
|
|
69
|
+
additionalProps: {
|
|
70
|
+
style: _extends({}, theme.typography.body1, {
|
|
71
|
+
lineHeight: 1,
|
|
72
|
+
fontSize: 14,
|
|
73
|
+
textAnchor: 'middle',
|
|
74
|
+
dominantBaseline: position === 'bottom' ? 'text-after-edge' : 'text-before-edge'
|
|
75
|
+
}, labelStyle)
|
|
76
|
+
},
|
|
77
|
+
ownerState: {}
|
|
78
|
+
});
|
|
79
|
+
const domain = xScale.domain();
|
|
80
|
+
const isScaleBand = isBandScale(xScale);
|
|
81
|
+
const skipAxisRendering = isScaleBand && domain.length === 0 || !isScaleBand && domain.some(isInfinity) || position === 'none';
|
|
82
|
+
return {
|
|
83
|
+
xScale,
|
|
84
|
+
defaultizedProps,
|
|
85
|
+
tickNumber,
|
|
86
|
+
positionSign,
|
|
87
|
+
skipAxisRendering,
|
|
88
|
+
classes,
|
|
89
|
+
Line,
|
|
90
|
+
Tick,
|
|
91
|
+
TickLabel,
|
|
92
|
+
Label,
|
|
93
|
+
axisTickLabelProps,
|
|
94
|
+
axisLabelProps,
|
|
95
|
+
reverse,
|
|
96
|
+
isRtl
|
|
97
|
+
};
|
|
98
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AxisConfig, ChartsXAxisProps } from "../models/axis.js";
|
|
2
|
+
export declare const useUtilityClasses: (ownerState: AxisConfig<any, any, ChartsXAxisProps>) => Record<"root" | "line" | "label" | "tickContainer" | "tick" | "tickLabel", string>;
|
|
3
|
+
export declare const TICK_LABEL_GAP = 3;
|
|
4
|
+
export declare const AXIS_LABEL_TICK_LABEL_GAP = 4;
|
|
5
|
+
export declare const XAxisRoot: import("@emotion/styled").StyledComponent<Pick<import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & Pick<import("react").SVGProps<SVGGElement>, keyof import("react").SVGProps<SVGGElement>>, keyof import("react").SVGProps<SVGGElement> | keyof import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme>> & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme>, {}, {}>;
|
|
6
|
+
export declare const defaultProps: {
|
|
7
|
+
readonly disableLine: false;
|
|
8
|
+
readonly disableTicks: false;
|
|
9
|
+
readonly tickSize: 6;
|
|
10
|
+
readonly tickLabelMinGap: 4;
|
|
11
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import composeClasses from '@mui/utils/composeClasses';
|
|
2
|
+
import { styled } from '@mui/material/styles';
|
|
3
|
+
import { getAxisUtilityClass } from "../ChartsAxis/axisClasses.js";
|
|
4
|
+
import { AxisRoot } from "../internals/components/AxisSharedComponents.js";
|
|
5
|
+
export const useUtilityClasses = ownerState => {
|
|
6
|
+
const {
|
|
7
|
+
classes,
|
|
8
|
+
position,
|
|
9
|
+
id
|
|
10
|
+
} = ownerState;
|
|
11
|
+
const slots = {
|
|
12
|
+
root: ['root', 'directionX', position, `id-${id}`],
|
|
13
|
+
line: ['line'],
|
|
14
|
+
tickContainer: ['tickContainer'],
|
|
15
|
+
tick: ['tick'],
|
|
16
|
+
tickLabel: ['tickLabel'],
|
|
17
|
+
label: ['label']
|
|
18
|
+
};
|
|
19
|
+
return composeClasses(slots, getAxisUtilityClass, classes);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/* Gap between a tick and its label. */
|
|
23
|
+
export const TICK_LABEL_GAP = 3;
|
|
24
|
+
/* Gap between the axis label and tick labels. */
|
|
25
|
+
export const AXIS_LABEL_TICK_LABEL_GAP = 4;
|
|
26
|
+
export const XAxisRoot = styled(AxisRoot, {
|
|
27
|
+
name: 'MuiChartsXAxis',
|
|
28
|
+
slot: 'Root'
|
|
29
|
+
})({});
|
|
30
|
+
export const defaultProps = {
|
|
31
|
+
disableLine: false,
|
|
32
|
+
disableTicks: false,
|
|
33
|
+
tickSize: 6,
|
|
34
|
+
tickLabelMinGap: 4
|
|
35
|
+
};
|
|
@@ -270,6 +270,10 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes = {
|
|
|
270
270
|
disableTicks: PropTypes.bool,
|
|
271
271
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
272
272
|
fill: PropTypes.string,
|
|
273
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
274
|
+
getValue: PropTypes.func.isRequired,
|
|
275
|
+
tickSize: PropTypes.number
|
|
276
|
+
})),
|
|
273
277
|
height: PropTypes.number,
|
|
274
278
|
hideTooltip: PropTypes.bool,
|
|
275
279
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
@@ -321,6 +325,10 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes = {
|
|
|
321
325
|
disableTicks: PropTypes.bool,
|
|
322
326
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
323
327
|
fill: PropTypes.string,
|
|
328
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
329
|
+
getValue: PropTypes.func.isRequired,
|
|
330
|
+
tickSize: PropTypes.number
|
|
331
|
+
})),
|
|
324
332
|
height: PropTypes.number,
|
|
325
333
|
hideTooltip: PropTypes.bool,
|
|
326
334
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
@@ -703,6 +711,10 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes = {
|
|
|
703
711
|
disableTicks: PropTypes.bool,
|
|
704
712
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
705
713
|
fill: PropTypes.string,
|
|
714
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
715
|
+
getValue: PropTypes.func.isRequired,
|
|
716
|
+
tickSize: PropTypes.number
|
|
717
|
+
})),
|
|
706
718
|
hideTooltip: PropTypes.bool,
|
|
707
719
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
708
720
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -753,6 +765,10 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes = {
|
|
|
753
765
|
disableTicks: PropTypes.bool,
|
|
754
766
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
755
767
|
fill: PropTypes.string,
|
|
768
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
769
|
+
getValue: PropTypes.func.isRequired,
|
|
770
|
+
tickSize: PropTypes.number
|
|
771
|
+
})),
|
|
756
772
|
hideTooltip: PropTypes.bool,
|
|
757
773
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
758
774
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { RadarDataProvider } from "./RadarDataProvider/index.js";
|
|
2
2
|
export { RadarChart } from "./RadarChart.js";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated radar chart is now stable, import `RadarChart` instead
|
|
5
|
+
*/
|
|
6
|
+
export declare const Unstable_RadarChart: import("react").ForwardRefExoticComponent<import("./RadarChart.js").RadarChartProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
4
7
|
export { RadarDataProvider } from "./RadarDataProvider/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated radar data provider is now stable, import `RadarDataProvider` instead
|
|
10
|
+
*/
|
|
11
|
+
export declare const Unstable_RadarDataProvider: typeof RadarDataProvider;
|
|
5
12
|
export type { RadarChartProps, RadarChartSlots, RadarChartSlotProps } from "./RadarChart.js";
|
|
6
13
|
export type { RadarDataProviderProps, RadarSeries } from "./RadarDataProvider/index.js";
|
|
7
14
|
export * from "./RadarGrid/index.js";
|
package/esm/RadarChart/index.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { RadarChart } from "./RadarChart.js";
|
|
2
|
+
import { RadarDataProvider } from "./RadarDataProvider/index.js";
|
|
2
3
|
export { RadarChart } from "./RadarChart.js";
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated radar chart is now stable, import `RadarChart` instead
|
|
6
|
+
*/
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
|
+
export const Unstable_RadarChart = RadarChart;
|
|
4
9
|
export { RadarDataProvider } from "./RadarDataProvider/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated radar data provider is now stable, import `RadarDataProvider` instead
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
+
export const Unstable_RadarDataProvider = RadarDataProvider;
|
|
5
15
|
export * from "./RadarGrid/index.js";
|
|
6
16
|
export * from "./RadarAxisHighlight/index.js";
|
|
7
17
|
export * from "./RadarMetricLabels/index.js";
|
|
@@ -6,6 +6,7 @@ import { ScatterPlotProps, ScatterPlotSlotProps, ScatterPlotSlots } from "./Scat
|
|
|
6
6
|
import { ChartContainerProps } from "../ChartContainer/index.js";
|
|
7
7
|
import { ChartsAxisProps } from "../ChartsAxis/index.js";
|
|
8
8
|
import { ScatterSeriesType } from "../models/seriesType/scatter.js";
|
|
9
|
+
import { ChartsTooltipProps } from "../ChartsTooltip/index.js";
|
|
9
10
|
import { ChartsTooltipSlots, ChartsTooltipSlotProps } from "../ChartsTooltip/ChartTooltip.types.js";
|
|
10
11
|
import { ChartsLegendSlotProps, ChartsLegendSlots } from "../ChartsLegend/index.js";
|
|
11
12
|
import { ChartsOverlayProps, ChartsOverlaySlotProps, ChartsOverlaySlots } from "../ChartsOverlay/index.js";
|
|
@@ -15,7 +16,13 @@ import { ChartsGridProps } from "../ChartsGrid/index.js";
|
|
|
15
16
|
import { UseChartVoronoiSignature } from "../internals/plugins/featurePlugins/useChartVoronoi/index.js";
|
|
16
17
|
import { ScatterChartPluginsSignatures } from "./ScatterChart.plugins.js";
|
|
17
18
|
export interface ScatterChartSlots extends ChartsAxisSlots, ScatterPlotSlots, ChartsLegendSlots, ChartsOverlaySlots, ChartsTooltipSlots, ChartsToolbarSlots, Partial<ChartsSlots> {}
|
|
18
|
-
export interface ScatterChartSlotProps extends ChartsAxisSlotProps, ScatterPlotSlotProps, ChartsLegendSlotProps, ChartsOverlaySlotProps, ChartsTooltipSlotProps, ChartsToolbarSlotProps, Partial<ChartsSlotProps> {
|
|
19
|
+
export interface ScatterChartSlotProps extends ChartsAxisSlotProps, ScatterPlotSlotProps, ChartsLegendSlotProps, ChartsOverlaySlotProps, Omit<ChartsTooltipSlotProps, 'tooltip'>, ChartsToolbarSlotProps, Partial<ChartsSlotProps> {
|
|
20
|
+
/**
|
|
21
|
+
* Slot props for the tooltip component.
|
|
22
|
+
* @default {}
|
|
23
|
+
*/
|
|
24
|
+
tooltip?: Partial<ChartsTooltipProps<'item' | 'none'>>;
|
|
25
|
+
}
|
|
19
26
|
export type ScatterSeries = MakeOptional<ScatterSeriesType, 'type'>;
|
|
20
27
|
export interface ScatterChartProps extends Omit<ChartContainerProps<'scatter', ScatterChartPluginsSignatures>, 'series' | 'plugins' | 'onItemClick' | 'experimentalFeatures' | 'highlightedAxis' | 'onHighlightedAxisChange'>, Omit<ChartsAxisProps, 'slots' | 'slotProps'>, Omit<ChartsOverlayProps, 'slots' | 'slotProps'> {
|
|
21
28
|
/**
|
|
@@ -239,6 +239,10 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes = {
|
|
|
239
239
|
disableTicks: PropTypes.bool,
|
|
240
240
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
241
241
|
fill: PropTypes.string,
|
|
242
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
243
|
+
getValue: PropTypes.func.isRequired,
|
|
244
|
+
tickSize: PropTypes.number
|
|
245
|
+
})),
|
|
242
246
|
height: PropTypes.number,
|
|
243
247
|
hideTooltip: PropTypes.bool,
|
|
244
248
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
@@ -290,6 +294,10 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes = {
|
|
|
290
294
|
disableTicks: PropTypes.bool,
|
|
291
295
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
292
296
|
fill: PropTypes.string,
|
|
297
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
298
|
+
getValue: PropTypes.func.isRequired,
|
|
299
|
+
tickSize: PropTypes.number
|
|
300
|
+
})),
|
|
293
301
|
height: PropTypes.number,
|
|
294
302
|
hideTooltip: PropTypes.bool,
|
|
295
303
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
@@ -672,6 +680,10 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes = {
|
|
|
672
680
|
disableTicks: PropTypes.bool,
|
|
673
681
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
674
682
|
fill: PropTypes.string,
|
|
683
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
684
|
+
getValue: PropTypes.func.isRequired,
|
|
685
|
+
tickSize: PropTypes.number
|
|
686
|
+
})),
|
|
675
687
|
hideTooltip: PropTypes.bool,
|
|
676
688
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
677
689
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -722,6 +734,10 @@ process.env.NODE_ENV !== "production" ? ScatterChart.propTypes = {
|
|
|
722
734
|
disableTicks: PropTypes.bool,
|
|
723
735
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
724
736
|
fill: PropTypes.string,
|
|
737
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
738
|
+
getValue: PropTypes.func.isRequired,
|
|
739
|
+
tickSize: PropTypes.number
|
|
740
|
+
})),
|
|
725
741
|
hideTooltip: PropTypes.bool,
|
|
726
742
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
727
743
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -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]),
|
|
@@ -785,6 +793,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
|
|
|
785
793
|
disableTicks: PropTypes.bool,
|
|
786
794
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
787
795
|
fill: PropTypes.string,
|
|
796
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
797
|
+
getValue: PropTypes.func.isRequired,
|
|
798
|
+
tickSize: PropTypes.number
|
|
799
|
+
})),
|
|
788
800
|
hideTooltip: PropTypes.bool,
|
|
789
801
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
790
802
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -835,6 +847,10 @@ process.env.NODE_ENV !== "production" ? SparkLineChart.propTypes = {
|
|
|
835
847
|
disableTicks: PropTypes.bool,
|
|
836
848
|
domainLimit: PropTypes.oneOfType([PropTypes.oneOf(['nice', 'strict']), PropTypes.func]),
|
|
837
849
|
fill: PropTypes.string,
|
|
850
|
+
groups: PropTypes.arrayOf(PropTypes.shape({
|
|
851
|
+
getValue: PropTypes.func.isRequired,
|
|
852
|
+
tickSize: PropTypes.number
|
|
853
|
+
})),
|
|
838
854
|
hideTooltip: PropTypes.bool,
|
|
839
855
|
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
840
856
|
ignoreTooltip: PropTypes.bool,
|
|
@@ -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.js
CHANGED
|
@@ -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;
|
package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.d.ts
CHANGED
|
@@ -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;
|
package/esm/internals/plugins/featurePlugins/useChartCartesianAxis/createAxisFilterMapper.js
CHANGED
|
@@ -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
|
-
|
|
25
|
-
} else {
|
|
26
|
-
extremums = getAxisExtremum(axis, direction, seriesConfig, axisIndex, formattedSeries);
|
|
23
|
+
return createDiscreteScaleGetAxisFilter(axis.data, zoom.start, zoom.end, direction);
|
|
27
24
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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];
|
package/esm/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';
|