diff --git a/packages/x-charts/src/BarChart/BarPlot.tsx b/packages/x-charts/src/BarChart/BarPlot.tsx index 7ff1e8999a57..bab8699fe686 100644 --- a/packages/x-charts/src/BarChart/BarPlot.tsx +++ b/packages/x-charts/src/BarChart/BarPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useTransition } from '@react-spring/web'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { BarElement, BarElementSlotProps, BarElementSlots } from './BarElement'; import { AxisDefaultized } from '../models/axis'; import { FormatterResult } from '../models/seriesType/config'; @@ -89,7 +89,7 @@ const useAggregatedData = (): { const seriesData = useBarSeries() ?? ({ series: {}, stackingGroups: [], seriesOrder: [] } as FormatterResult<'bar'>); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const chartId = useChartId(); const { series, stackingGroups } = seriesData; diff --git a/packages/x-charts/src/BarChart/checkScaleErrors.ts b/packages/x-charts/src/BarChart/checkScaleErrors.ts index e3b7b0803e96..cbd3137b11d5 100644 --- a/packages/x-charts/src/BarChart/checkScaleErrors.ts +++ b/packages/x-charts/src/BarChart/checkScaleErrors.ts @@ -1,8 +1,8 @@ import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; -import { AxisDefaultized, isBandScaleConfig, isPointScaleConfig } from '../models/axis'; +import { AxisDefaultized, AxisId, isBandScaleConfig, isPointScaleConfig } from '../models/axis'; import { SeriesId } from '../models/seriesType/common'; -const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: string) => { +const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: AxisId) => { const axisName = `${axisDirection}-axis`; const axisKeyName = `${axisDirection}Axis`; const axisDefaultKey = axisDirection === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY; @@ -14,10 +14,10 @@ const getAxisMessage = (axisDirection: 'x' | 'y', axisKey: string) => { export function checkScaleErrors( verticalLayout: boolean, seriesId: SeriesId, - xAxisKey: string, - xAxis: { DEFAULT_X_AXIS_KEY: AxisDefaultized } & { [axisKey: string]: AxisDefaultized }, - yAxisKey: string, - yAxis: { DEFAULT_X_AXIS_KEY: AxisDefaultized } & { [axisKey: string]: AxisDefaultized }, + xAxisKey: AxisId, + xAxis: { [axisKey: AxisId]: AxisDefaultized }, + yAxisKey: AxisId, + yAxis: { [axisKey: AxisId]: AxisDefaultized }, ): void { const xAxisConfig = xAxis[xAxisKey]; const yAxisConfig = yAxis[yAxisKey]; diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 7ebdd67c0e32..c389f3b3d609 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -13,7 +13,7 @@ import { ChartsSurface, ChartsSurfaceProps } from '../ChartsSurface'; import { CartesianContextProvider, CartesianContextProviderProps, -} from '../context/CartesianContextProvider'; +} from '../context/CartesianProvider'; import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; import { HighlightedProvider, diff --git a/packages/x-charts/src/ChartContainer/usePluginsMerge.ts b/packages/x-charts/src/ChartContainer/usePluginsMerge.ts index ee1043e918f9..b269bf79adfb 100644 --- a/packages/x-charts/src/ChartContainer/usePluginsMerge.ts +++ b/packages/x-charts/src/ChartContainer/usePluginsMerge.ts @@ -1,7 +1,6 @@ import * as React from 'react'; -import { ChartsPluginType, ColorProcessorsConfig } from '../models'; +import { ChartsPluginType, ColorProcessorsConfig, ExtremumGettersConfig } from '../models'; import { ChartSeriesType } from '../models/seriesType/config'; -import { ExtremumGettersConfig } from '../context/CartesianContextProvider'; import { SeriesFormatterConfig } from '../context/SeriesContextProvider'; import { defaultPlugins } from './defaultPlugins'; diff --git a/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx b/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx index db42c36c7cb7..4212e2950954 100644 --- a/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx +++ b/packages/x-charts/src/ChartsAxis/ChartsAxis.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ChartsXAxis } from '../ChartsXAxis'; import { ChartsYAxis } from '../ChartsYAxis'; import { @@ -49,8 +49,8 @@ export interface ChartsAxisProps { } const getAxisId = ( - propsValue: undefined | null | string | ChartsXAxisProps | ChartsYAxisProps, - defaultAxisId?: string, + propsValue: undefined | null | AxisId | ChartsXAxisProps | ChartsYAxisProps, + defaultAxisId?: AxisId, ): AxisId | null => { if (propsValue == null) { return null; @@ -62,7 +62,7 @@ const getAxisId = ( }; const mergeProps = ( - axisConfig: undefined | null | string | ChartsXAxisProps | ChartsYAxisProps, + axisConfig: undefined | null | AxisId | ChartsXAxisProps | ChartsYAxisProps, slots?: Partial, slotProps?: Partial, ) => { @@ -86,7 +86,7 @@ const mergeProps = ( */ function ChartsAxis(props: ChartsAxisProps) { const { topAxis, leftAxis, rightAxis, bottomAxis, slots, slotProps } = props; - const { xAxis, xAxisIds, yAxis, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds, yAxis, yAxisIds } = useCartesianContext(); // TODO: use for plotting line without ticks or any thing // const drawingArea = React.useContext(DrawingContext); diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx index d72082da7b8d..6485c9c3f4d6 100644 --- a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx @@ -5,7 +5,7 @@ import generateUtilityClass from '@mui/utils/generateUtilityClass'; import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; import { styled } from '@mui/material/styles'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; import { isBandScale } from '../internals/isBandScale'; @@ -67,7 +67,7 @@ export type ChartsAxisHighlightProps = { */ function ChartsAxisHighlight(props: ChartsAxisHighlightProps) { const { x: xAxisHighlight, y: yAxisHighlight } = props; - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); const classes = useUtilityClasses(); const USED_X_AXIS_ID = xAxisIds[0]; diff --git a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx index 01b2539a4ce9..c150244b2d39 100644 --- a/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx +++ b/packages/x-charts/src/ChartsGrid/ChartsGrid.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import { styled, useThemeProps } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks } from '../hooks/useTicks'; import { ChartsGridClasses, @@ -69,7 +69,7 @@ function ChartsGrid(props: ChartsGridProps) { const themeProps = useThemeProps({ props, name: 'MuiChartsGrid' }); const { vertical, horizontal, ...other } = themeProps; - const { xAxis, xAxisIds, yAxis, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds, yAxis, yAxisIds } = useCartesianContext(); const classes = useUtilityClasses(themeProps); diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx index f134b0b2f599..8710c72762a0 100644 --- a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; import { useSeries } from '../hooks/useSeries'; import { useSvgRef } from '../hooks'; +import { useCartesianContext } from '../context/CartesianProvider'; type AxisData = { dataIndex: number; @@ -27,7 +27,7 @@ function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { const svgRef = useSvgRef(); const series = useSeries(); const { axis } = React.useContext(InteractionContext); - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); React.useEffect(() => { const element = svgRef.current; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 262bb3688029..e4e9487f7ab7 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { SxProps, Theme } from '@mui/material/styles'; import { useSlotProps } from '@mui/base/utils'; import { AxisInteractionData } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { AxisDefaultized } from '../models/axis'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; @@ -59,7 +59,7 @@ function ChartsAxisTooltipContent(props: { const dataIndex = isXaxis ? axisData.x && axisData.x.index : axisData.y && axisData.y.index; const axisValue = isXaxis ? axisData.x && axisData.x.value : axisData.y && axisData.y.value; - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); const { zAxisIds, zAxis } = React.useContext(ZAxisContext); const series = useSeries(); diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index ea0951a2d1a4..f4356bbcfc1a 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -6,7 +6,7 @@ import { ItemInteractionData } from '../context/InteractionProvider'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useColorProcessor } from '../hooks/useColor'; import { useSeries } from '../hooks/useSeries'; @@ -44,7 +44,7 @@ function ChartsItemTooltipContent(props: { const series = useSeries()[itemData.type]!.series[itemData.seriesId] as ChartSeriesDefaultized; - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { zAxis, zAxisIds } = React.useContext(ZAxisContext); const colorProcessors = useColorProcessor(); diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index 170c4a71e112..d9812c0b3baa 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Delaunay } from 'd3-delaunay'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; import { getSVGPoint } from '../internals/utils'; import { ScatterItemIdentifier } from '../models'; @@ -32,7 +32,7 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const { voronoiMaxRadius, onItemClick } = props; const svgRef = useSvgRef(); const { left, top, width, height } = useDrawingArea(); - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { dispatch } = React.useContext(InteractionContext); const { series, seriesOrder } = useScatterSeries() ?? {}; diff --git a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx index 98146ac637d4..ea796b2e333e 100644 --- a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx +++ b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks, TickItemType } from '../hooks/useTicks'; import { AxisDefaultized, ChartsXAxisProps } from '../models/axis'; import { getAxisUtilityClass } from '../ChartsAxis/axisClasses'; @@ -98,7 +98,7 @@ const defaultProps = { * - [ChartsXAxis API](https://mui.com/x/api/charts/charts-x-axis/) */ function ChartsXAxis(inProps: ChartsXAxisProps) { - const { xAxisIds, xAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis } = useCartesianContext(); const { scale: xScale, tickNumber, reverse, ...settings } = xAxis[inProps.axisId ?? xAxisIds[0]]; const isMounted = useMounted(); diff --git a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx index 784ed2640ca0..44475ad90f1f 100644 --- a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx +++ b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { useTicks } from '../hooks/useTicks'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { ChartsYAxisProps } from '../models/axis'; @@ -44,7 +44,7 @@ const defaultProps = { * - [ChartsYAxis API](https://mui.com/x/api/charts/charts-y-axis/) */ function ChartsYAxis(inProps: ChartsYAxisProps) { - const { yAxisIds, yAxis } = React.useContext(CartesianContext); + const { yAxisIds, yAxis } = useCartesianContext(); const { scale: yScale, tickNumber, ...settings } = yAxis[inProps.axisId ?? yAxisIds[0]]; const themedProps = useThemeProps({ props: { ...settings, ...inProps }, name: 'MuiChartsYAxis' }); diff --git a/packages/x-charts/src/LineChart/AreaPlot.tsx b/packages/x-charts/src/LineChart/AreaPlot.tsx index 51a62066c83a..daa51ea9d69a 100644 --- a/packages/x-charts/src/LineChart/AreaPlot.tsx +++ b/packages/x-charts/src/LineChart/AreaPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { area as d3Area } from 'd3-shape'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { AreaElement, AreaElementProps, @@ -14,6 +14,7 @@ import { DEFAULT_X_AXIS_KEY } from '../constants'; import { LineItemIdentifier } from '../models/seriesType/line'; import { useChartGradient } from '../internals/components/ChartsAxesGradients'; import { useLineSeries } from '../hooks/useSeries'; +import { AxisId } from '../models/axis'; export interface AreaPlotSlots extends AreaElementSlots {} @@ -35,7 +36,7 @@ export interface AreaPlotProps const useAggregatedData = () => { const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); if (seriesData === undefined) { return []; @@ -62,7 +63,7 @@ const useAggregatedData = () => { const yScale = yAxis[yAxisKey].scale; const xData = xAxis[xAxisKey].data; - const gradientUsed: [string, 'x' | 'y'] | undefined = + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = (yAxis[yAxisKey].colorScale && [yAxisKey, 'y']) || (xAxis[xAxisKey].colorScale && [xAxisKey, 'x']) || undefined; diff --git a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx index 25343dd4c129..d183bd73042d 100644 --- a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { LineHighlightElement, LineHighlightElementProps } from './LineHighlightElement'; import { getValueToPositionMapper } from '../hooks/useScale'; import { InteractionContext } from '../context/InteractionProvider'; @@ -43,7 +43,7 @@ function LineHighlightPlot(props: LineHighlightPlotProps) { const { slots, slotProps, ...other } = props; const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const { axis } = React.useContext(InteractionContext); const highlightedIndex = axis.x?.index; diff --git a/packages/x-charts/src/LineChart/LinePlot.tsx b/packages/x-charts/src/LineChart/LinePlot.tsx index 7e09416d2f96..6ee5d39eabf1 100644 --- a/packages/x-charts/src/LineChart/LinePlot.tsx +++ b/packages/x-charts/src/LineChart/LinePlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { line as d3Line } from 'd3-shape'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { LineElement, LineElementProps, @@ -14,6 +14,7 @@ import { DEFAULT_X_AXIS_KEY } from '../constants'; import { LineItemIdentifier } from '../models/seriesType/line'; import { useChartGradient } from '../internals/components/ChartsAxesGradients'; import { useLineSeries } from '../hooks/useSeries'; +import { AxisId } from '../models/axis'; export interface LinePlotSlots extends LineElementSlots {} @@ -35,7 +36,7 @@ export interface LinePlotProps const useAggregatedData = () => { const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); if (seriesData === undefined) { return []; @@ -60,7 +61,7 @@ const useAggregatedData = () => { const yScale = yAxis[yAxisKey].scale; const xData = xAxis[xAxisKey].data; - const gradientUsed: [string, 'x' | 'y'] | undefined = + const gradientUsed: [AxisId, 'x' | 'y'] | undefined = (yAxis[yAxisKey].colorScale && [yAxisKey, 'y']) || (xAxis[xAxisKey].colorScale && [xAxisKey, 'x']) || undefined; diff --git a/packages/x-charts/src/LineChart/MarkPlot.tsx b/packages/x-charts/src/LineChart/MarkPlot.tsx index 23c7695f443e..ceecfbb0b6f7 100644 --- a/packages/x-charts/src/LineChart/MarkPlot.tsx +++ b/packages/x-charts/src/LineChart/MarkPlot.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { MarkElement, MarkElementProps } from './MarkElement'; import { getValueToPositionMapper } from '../hooks/useScale'; import { useChartId } from '../hooks/useChartId'; @@ -56,7 +56,7 @@ function MarkPlot(props: MarkPlotProps) { const { slots, slotProps, skipAnimation, onItemClick, ...other } = props; const seriesData = useLineSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const chartId = useChartId(); const Mark = slots?.mark ?? MarkElement; diff --git a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx index 9b4129a1fa0c..0bdc7c1060a2 100644 --- a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { Scatter, ScatterProps } from './Scatter'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import getColor from './getColor'; import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useScatterSeries } from '../hooks/useSeries'; @@ -40,7 +40,7 @@ export interface ScatterPlotProps extends Pick { function ScatterPlot(props: ScatterPlotProps) { const { slots, slotProps, onItemClick } = props; const seriesData = useScatterSeries(); - const axisData = React.useContext(CartesianContext); + const axisData = useCartesianContext(); const { zAxis, zAxisIds } = React.useContext(ZAxisContext); if (seriesData === undefined) { diff --git a/packages/x-charts/src/context/CartesianContextProvider.tsx b/packages/x-charts/src/context/CartesianContextProvider.tsx deleted file mode 100644 index 9a97fbd6e807..000000000000 --- a/packages/x-charts/src/context/CartesianContextProvider.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import * as React from 'react'; -import { scaleBand, scalePoint } from 'd3-scale'; -import { - AxisConfig, - AxisDefaultized, - ChartsXAxisProps, - ChartsYAxisProps, - ScaleName, - isBandScaleConfig, - isPointScaleConfig, -} from '../models/axis'; -import { getScale } from '../internals/getScale'; -import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../constants'; -import { - CartesianChartSeriesType, - ChartSeriesType, - ChartSeries, - DatasetType, - ExtremumGetter, - ExtremumGetterResult, -} from '../models/seriesType/config'; -import { MakeOptional } from '../models/helpers'; -import { getTickNumber } from '../hooks/useTicks'; -import { useDrawingArea } from '../hooks/useDrawingArea'; -import { SeriesId } from '../models/seriesType/common'; -import { getColorScale, getOrdinalColorScale } from '../internals/colorScale'; -import { useSeries } from '../hooks/useSeries'; - -export type ExtremumGettersConfig = { - [K in T]?: ExtremumGetter; -}; - -export type CartesianContextProviderProps = { - /** - * The configuration of the x-axes. - * If not provided, a default axis config is used. - * An array of [[AxisConfig]] objects. - */ - xAxis?: MakeOptional, 'id'>[]; - /** - * The configuration of the y-axes. - * If not provided, a default axis config is used. - * An array of [[AxisConfig]] objects. - */ - yAxis?: MakeOptional, 'id'>[]; - /** - * An array of objects that can be used to populate series and axes data using their `dataKey` property. - */ - dataset?: DatasetType; - /** - * An object with x-axis extremum getters per series type. - */ - xExtremumGetters: ExtremumGettersConfig; - /** - * An object with y-axis extremum getters per series type. - */ - yExtremumGetters: ExtremumGettersConfig; - children: React.ReactNode; -}; - -const DEFAULT_CATEGORY_GAP_RATIO = 0.2; -const DEFAULT_BAR_GAP_RATIO = 0.1; - -type DefaultizedAxisConfig = { - [axisKey: string]: AxisDefaultized; -}; - -export const CartesianContext = React.createContext<{ - /** - * Mapping from x-axis key to scaling configuration. - */ - xAxis: { - DEFAULT_X_AXIS_KEY: AxisDefaultized; - } & DefaultizedAxisConfig; - /** - * Mapping from y-axis key to scaling configuration. - */ - yAxis: { - DEFAULT_X_AXIS_KEY: AxisDefaultized; - } & DefaultizedAxisConfig; - /** - * The x-axes IDs sorted by order they got provided. - */ - xAxisIds: string[]; - /** - * The y-axes IDs sorted by order they got provided. - */ - yAxisIds: string[]; - // @ts-ignore -}>({ xAxis: {}, yAxis: {}, xAxisIds: [], yAxisIds: [] }); - -if (process.env.NODE_ENV !== 'production') { - CartesianContext.displayName = 'CartesianContext'; -} - -function CartesianContextProvider(props: CartesianContextProviderProps) { - const { - xAxis: inXAxis, - yAxis: inYAxis, - dataset, - xExtremumGetters, - yExtremumGetters, - children, - } = props; - const formattedSeries = useSeries(); - const drawingArea = useDrawingArea(); - - const xAxis = React.useMemo( - () => - inXAxis?.map((axisConfig) => { - const dataKey = axisConfig.dataKey; - if (dataKey === undefined || axisConfig.data !== undefined) { - return axisConfig; - } - if (dataset === undefined) { - throw Error('MUI X Charts: x-axis uses `dataKey` but no `dataset` is provided.'); - } - return { - ...axisConfig, - data: dataset.map((d) => d[dataKey]), - }; - }), - [inXAxis, dataset], - ); - - const yAxis = React.useMemo( - () => - inYAxis?.map((axisConfig) => { - const dataKey = axisConfig.dataKey; - if (dataKey === undefined || axisConfig.data !== undefined) { - return axisConfig; - } - if (dataset === undefined) { - throw Error('MUI X Charts: y-axis uses `dataKey` but no `dataset` is provided.'); - } - return { - ...axisConfig, - data: dataset.map((d) => d[dataKey]), - }; - }), - [inYAxis, dataset], - ); - - const value = React.useMemo(() => { - const axisExtremumCallback = ( - acc: ExtremumGetterResult, - chartType: T, - axis: AxisConfig, - getters: { [T2 in CartesianChartSeriesType]?: ExtremumGetter }, - isDefaultAxis: boolean, - ): ExtremumGetterResult => { - const getter = getters[chartType]; - const series = (formattedSeries[chartType]?.series as Record>) ?? {}; - - const [minChartTypeData, maxChartTypeData] = getter?.({ - series, - axis, - isDefaultAxis, - }) ?? [null, null]; - - const [minData, maxData] = acc; - - if (minData === null || maxData === null) { - return [minChartTypeData!, maxChartTypeData!]; - } - - if (minChartTypeData === null || maxChartTypeData === null) { - return [minData, maxData]; - } - - return [Math.min(minChartTypeData, minData), Math.max(maxChartTypeData, maxData)]; - }; - - const getAxisExtremum = ( - axis: AxisConfig, - getters: { [T in CartesianChartSeriesType]?: ExtremumGetter }, - isDefaultAxis: boolean, - ) => { - const charTypes = Object.keys(getters) as CartesianChartSeriesType[]; - - return charTypes.reduce( - (acc, charType) => axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis), - [null, null] as ExtremumGetterResult, - ); - }; - - const allXAxis = [ - ...(xAxis?.map((axis, index) => ({ id: `defaultized-x-axis-${index}`, ...axis })) ?? []), - // Allows to specify an axis with id=DEFAULT_X_AXIS_KEY - ...(xAxis === undefined || xAxis.findIndex(({ id }) => id === DEFAULT_X_AXIS_KEY) === -1 - ? [ - { id: DEFAULT_X_AXIS_KEY, scaleType: 'linear' } as AxisConfig< - ScaleName, - any, - ChartsXAxisProps - >, - ] - : []), - ]; - - const completedXAxis: DefaultizedAxisConfig = {}; - allXAxis.forEach((axis, axisIndex) => { - const isDefaultAxis = axisIndex === 0; - const [minData, maxData] = getAxisExtremum(axis, xExtremumGetters, isDefaultAxis); - - const range = axis.reverse - ? [drawingArea.left + drawingArea.width, drawingArea.left] - : [drawingArea.left, drawingArea.left + drawingArea.width]; - - if (isBandScaleConfig(axis)) { - const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; - const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO; - completedXAxis[axis.id] = { - categoryGapRatio, - barGapRatio, - ...axis, - scale: scaleBand(axis.data!, range) - .paddingInner(categoryGapRatio) - .paddingOuter(categoryGapRatio / 2), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (isPointScaleConfig(axis)) { - completedXAxis[axis.id] = { - ...axis, - scale: scalePoint(axis.data!, range), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (axis.scaleType === 'band' || axis.scaleType === 'point') { - // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. - return; - } - - const scaleType = axis.scaleType ?? 'linear'; - - const extremums = [axis.min ?? minData, axis.max ?? maxData]; - const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); - - const niceScale = getScale(scaleType, extremums, range).nice(tickNumber); - const niceDomain = niceScale.domain(); - const domain = [axis.min ?? niceDomain[0], axis.max ?? niceDomain[1]]; - - completedXAxis[axis.id] = { - ...axis, - scaleType, - scale: niceScale.domain(domain), - tickNumber, - colorScale: axis.colorMap && getColorScale(axis.colorMap), - } as AxisDefaultized; - }); - - const allYAxis = [ - ...(yAxis?.map((axis, index) => ({ id: `defaultized-y-axis-${index}`, ...axis })) ?? []), - ...(yAxis === undefined || yAxis.findIndex(({ id }) => id === DEFAULT_Y_AXIS_KEY) === -1 - ? [ - { id: DEFAULT_Y_AXIS_KEY, scaleType: 'linear' } as AxisConfig< - ScaleName, - any, - ChartsYAxisProps - >, - ] - : []), - ]; - - const completedYAxis: DefaultizedAxisConfig = {}; - allYAxis.forEach((axis, axisIndex) => { - const isDefaultAxis = axisIndex === 0; - const [minData, maxData] = getAxisExtremum(axis, yExtremumGetters, isDefaultAxis); - const range = axis.reverse - ? [drawingArea.top, drawingArea.top + drawingArea.height] - : [drawingArea.top + drawingArea.height, drawingArea.top]; - - if (isBandScaleConfig(axis)) { - const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; - completedYAxis[axis.id] = { - categoryGapRatio, - barGapRatio: 0, - ...axis, - scale: scaleBand(axis.data!, [range[1], range[0]]) - .paddingInner(categoryGapRatio) - .paddingOuter(categoryGapRatio / 2), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (isPointScaleConfig(axis)) { - completedYAxis[axis.id] = { - ...axis, - scale: scalePoint(axis.data!, [range[1], range[0]]), - tickNumber: axis.data!.length, - colorScale: - axis.colorMap && - (axis.colorMap.type === 'ordinal' - ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) - : getColorScale(axis.colorMap)), - }; - } - if (axis.scaleType === 'band' || axis.scaleType === 'point') { - // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. - return; - } - - const scaleType = axis.scaleType ?? 'linear'; - - const extremums = [axis.min ?? minData, axis.max ?? maxData]; - const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); - - const niceScale = getScale(scaleType, extremums, range).nice(tickNumber); - const niceDomain = niceScale.domain(); - const domain = [axis.min ?? niceDomain[0], axis.max ?? niceDomain[1]]; - - completedYAxis[axis.id] = { - ...axis, - scaleType, - scale: niceScale.domain(domain), - tickNumber, - colorScale: axis.colorMap && getColorScale(axis.colorMap), - } as AxisDefaultized; - }); - - return { - xAxis: completedXAxis, - yAxis: completedYAxis, - xAxisIds: allXAxis.map(({ id }) => id), - yAxisIds: allYAxis.map(({ id }) => id), - }; - }, [ - drawingArea.height, - drawingArea.left, - drawingArea.top, - drawingArea.width, - formattedSeries, - xAxis, - xExtremumGetters, - yAxis, - yExtremumGetters, - ]); - - // @ts-ignore - return {children}; -} - -export { CartesianContextProvider }; diff --git a/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts b/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts new file mode 100644 index 000000000000..6406b1e42dcc --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/CartesianContext.ts @@ -0,0 +1,47 @@ +import * as React from 'react'; + +import { Initializable } from '../context.types'; +import { + AxisDefaultized, + ScaleName, + ChartsXAxisProps, + ChartsYAxisProps, + AxisId, +} from '../../models/axis'; + +export type DefaultizedAxisConfig = { + [axisKey: AxisId]: AxisDefaultized; +}; + +export type CartesianContextState = { + /** + * Mapping from x-axis key to scaling configuration. + */ + xAxis: DefaultizedAxisConfig; + /** + * Mapping from y-axis key to scaling configuration. + */ + yAxis: DefaultizedAxisConfig; + /** + * The x-axes IDs sorted by order they got provided. + */ + xAxisIds: AxisId[]; + /** + * The y-axes IDs sorted by order they got provided. + */ + yAxisIds: AxisId[]; +}; + +export const CartesianContext = React.createContext>({ + isInitialized: false, + data: { + xAxis: {}, + yAxis: {}, + xAxisIds: [], + yAxisIds: [], + }, +}); + +if (process.env.NODE_ENV !== 'production') { + CartesianContext.displayName = 'CartesianContext'; +} diff --git a/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx b/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx new file mode 100644 index 000000000000..847f9e553afd --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/CartesianProvider.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import { AxisConfig, ChartsXAxisProps, ChartsYAxisProps, ScaleName } from '../../models/axis'; +import { DatasetType } from '../../models/seriesType/config'; +import { MakeOptional } from '../../models/helpers'; +import { useDrawingArea } from '../../hooks/useDrawingArea'; +import { useSeries } from '../../hooks/useSeries'; +import { CartesianContext } from './CartesianContext'; +import { normalizeAxis } from './normalizeAxis'; +import { computeValue } from './computeValue'; +import { ExtremumGettersConfig } from '../../models'; + +export type CartesianContextProviderProps = { + /** + * The configuration of the x-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + xAxis?: MakeOptional, 'id'>[]; + /** + * The configuration of the y-axes. + * If not provided, a default axis config is used. + * An array of [[AxisConfig]] objects. + */ + yAxis?: MakeOptional, 'id'>[]; + /** + * An array of objects that can be used to populate series and axes data using their `dataKey` property. + */ + dataset?: DatasetType; + /** + * An object with x-axis extremum getters per series type. + */ + xExtremumGetters: ExtremumGettersConfig; + /** + * An object with y-axis extremum getters per series type. + */ + yExtremumGetters: ExtremumGettersConfig; + children: React.ReactNode; +}; + +function CartesianContextProvider(props: CartesianContextProviderProps) { + const { + xAxis: inXAxis, + yAxis: inYAxis, + dataset, + xExtremumGetters, + yExtremumGetters, + children, + } = props; + + const formattedSeries = useSeries(); + const drawingArea = useDrawingArea(); + + const xAxis = React.useMemo(() => normalizeAxis(inXAxis, dataset, 'x'), [inXAxis, dataset]); + + const yAxis = React.useMemo(() => normalizeAxis(inYAxis, dataset, 'y'), [inYAxis, dataset]); + + const xValues = React.useMemo( + () => computeValue(drawingArea, formattedSeries, xAxis, xExtremumGetters, 'x'), + [drawingArea, formattedSeries, xAxis, xExtremumGetters], + ); + + const yValues = React.useMemo( + () => computeValue(drawingArea, formattedSeries, yAxis, yExtremumGetters, 'y'), + [drawingArea, formattedSeries, yAxis, yExtremumGetters], + ); + + const value = React.useMemo( + () => ({ + isInitialized: true, + data: { + xAxis: xValues.axis, + yAxis: yValues.axis, + xAxisIds: xValues.axisIds, + yAxisIds: yValues.axisIds, + }, + }), + [xValues, yValues], + ); + + return {children}; +} + +export { CartesianContextProvider }; diff --git a/packages/x-charts/src/context/CartesianProvider/computeValue.ts b/packages/x-charts/src/context/CartesianProvider/computeValue.ts new file mode 100644 index 000000000000..053b51cf1afd --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/computeValue.ts @@ -0,0 +1,144 @@ +import { scaleBand, scalePoint } from 'd3-scale'; +import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../../constants'; +import { AxisConfig, ScaleName } from '../../models'; +import { + ChartsXAxisProps, + ChartsAxisProps, + ChartsYAxisProps, + isBandScaleConfig, + isPointScaleConfig, +} from '../../models/axis'; +import { CartesianChartSeriesType, ExtremumGetter } from '../../models/seriesType/config'; +import { DefaultizedAxisConfig } from './CartesianContext'; +import { getColorScale, getOrdinalColorScale } from '../../internals/colorScale'; +import { getTickNumber } from '../../hooks/useTicks'; +import { getScale } from '../../internals/getScale'; +import { DrawingArea } from '../DrawingProvider'; +import { FormattedSeries } from '../SeriesContextProvider'; +import { MakeOptional } from '../../models/helpers'; +import { getAxisExtremum } from './getAxisExtremum'; + +const getRange = (drawingArea: DrawingArea, axisName: 'x' | 'y', isReverse?: boolean) => { + const range = + axisName === 'x' + ? [drawingArea.left, drawingArea.left + drawingArea.width] + : [drawingArea.top + drawingArea.height, drawingArea.top]; + + return isReverse ? range.reverse() : range; +}; + +const DEFAULT_CATEGORY_GAP_RATIO = 0.2; +const DEFAULT_BAR_GAP_RATIO = 0.1; + +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + axis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'y', +): { + axis: DefaultizedAxisConfig; + axisIds: string[]; +}; +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + inAxis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'x', +): { + axis: DefaultizedAxisConfig; + axisIds: string[]; +}; +export function computeValue( + drawingArea: DrawingArea, + formattedSeries: FormattedSeries, + inAxis: MakeOptional, 'id'>[] | undefined, + extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter }, + axisName: 'x' | 'y', +) { + const DEFAULT_AXIS_KEY = axisName === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY; + + const allAxis: AxisConfig[] = [ + ...(inAxis?.map((axis, index) => ({ id: `defaultized-${axisName}-axis-${index}`, ...axis })) ?? + []), + ...(inAxis === undefined || inAxis.findIndex(({ id }) => id === DEFAULT_AXIS_KEY) === -1 + ? [{ id: DEFAULT_AXIS_KEY, scaleType: 'linear' as const }] + : []), + ]; + + const completeAxis: DefaultizedAxisConfig = {}; + allAxis.forEach((axis, axisIndex) => { + const isDefaultAxis = axisIndex === 0; + const [minData, maxData] = getAxisExtremum( + axis, + extremumGetters, + isDefaultAxis, + formattedSeries, + ); + + const range = getRange(drawingArea, axisName, axis.reverse); + + if (isBandScaleConfig(axis)) { + const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; + const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO; + // Reverse range because ordinal scales are presented from top to bottom on y-axis + const scaleRange = axisName === 'x' ? range : [range[1], range[0]]; + + completeAxis[axis.id] = { + categoryGapRatio, + barGapRatio, + ...axis, + scale: scaleBand(axis.data!, scaleRange) + .paddingInner(categoryGapRatio) + .paddingOuter(categoryGapRatio / 2), + tickNumber: axis.data!.length, + colorScale: + axis.colorMap && + (axis.colorMap.type === 'ordinal' + ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) + : getColorScale(axis.colorMap)), + }; + } + if (isPointScaleConfig(axis)) { + const scaleRange = axisName === 'x' ? range : [...range].reverse(); + + completeAxis[axis.id] = { + ...axis, + scale: scalePoint(axis.data!, scaleRange), + tickNumber: axis.data!.length, + colorScale: + axis.colorMap && + (axis.colorMap.type === 'ordinal' + ? getOrdinalColorScale({ values: axis.data, ...axis.colorMap }) + : getColorScale(axis.colorMap)), + }; + } + if (axis.scaleType === 'band' || axis.scaleType === 'point') { + // Could be merged with the two previous "if conditions" but then TS does not get that `axis.scaleType` can't be `band` or `point`. + return; + } + + const scaleType = axis.scaleType ?? ('linear' as const); + + const extremums = [axis.min ?? minData, axis.max ?? maxData]; + const tickNumber = getTickNumber({ ...axis, range, domain: extremums }); + + const scale = getScale(scaleType, extremums, range).nice(tickNumber); + const [minDomain, maxDomain] = scale.domain(); + const domain = [axis.min ?? minDomain, axis.max ?? maxDomain]; + + completeAxis[axis.id] = { + ...axis, + scaleType: scaleType as any, + scale: scale.domain(domain) as any, + tickNumber, + colorScale: axis.colorMap && getColorScale(axis.colorMap), + }; + }); + + return { + axis: completeAxis, + axisIds: allAxis.map(({ id }) => id), + }; +} diff --git a/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts b/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts new file mode 100644 index 000000000000..43a16a657cd4 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/getAxisExtremum.ts @@ -0,0 +1,48 @@ +import { AxisConfig, ExtremumGettersConfig } from '../../models'; +import { CartesianChartSeriesType, ExtremumGetterResult } from '../../models/seriesType/config'; +import { FormattedSeries } from '../SeriesContextProvider'; + +const axisExtremumCallback = ( + acc: ExtremumGetterResult, + chartType: T, + axis: AxisConfig, + getters: ExtremumGettersConfig, + isDefaultAxis: boolean, + formattedSeries: FormattedSeries, +): ExtremumGetterResult => { + const getter = getters[chartType]; + const series = formattedSeries[chartType]?.series ?? {}; + + const [minChartTypeData, maxChartTypeData] = getter?.({ + series, + axis, + isDefaultAxis, + }) ?? [null, null]; + + const [minData, maxData] = acc; + + if (minData === null || maxData === null) { + return [minChartTypeData!, maxChartTypeData!]; + } + + if (minChartTypeData === null || maxChartTypeData === null) { + return [minData, maxData]; + } + + return [Math.min(minChartTypeData, minData), Math.max(maxChartTypeData, maxData)]; +}; + +export const getAxisExtremum = ( + axis: AxisConfig, + getters: ExtremumGettersConfig, + isDefaultAxis: boolean, + formattedSeries: FormattedSeries, +) => { + const charTypes = Object.keys(getters) as CartesianChartSeriesType[]; + + return charTypes.reduce( + (acc, charType) => + axisExtremumCallback(acc, charType, axis, getters, isDefaultAxis, formattedSeries), + [null, null], + ); +}; diff --git a/packages/x-charts/src/context/CartesianProvider/index.ts b/packages/x-charts/src/context/CartesianProvider/index.ts new file mode 100644 index 000000000000..b9f4f07059dc --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/index.ts @@ -0,0 +1,13 @@ +import { computeValue } from './computeValue'; +import { normalizeAxis } from './normalizeAxis'; + +export * from './CartesianProvider'; +export * from './CartesianContext'; +export * from './useCartesianContext'; + +const cartesianProviderUtils = { + computeValue, + normalizeAxis, +}; + +export { cartesianProviderUtils }; diff --git a/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts b/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts new file mode 100644 index 000000000000..619eccdf40a6 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/normalizeAxis.ts @@ -0,0 +1,29 @@ +import type { AxisConfig, ScaleName } from '../../models'; +import { ChartsAxisProps } from '../../models/axis'; +import { MakeOptional } from '../../models/helpers'; +import { DatasetType } from '../../models/seriesType/config'; + +export const normalizeAxis = < + T extends ChartsAxisProps, + R extends MakeOptional, 'id'>, +>( + axis: R[] | undefined, + dataset: DatasetType | undefined, + axisName: 'x' | 'y', +): R[] | undefined => { + return axis?.map((axisConfig) => { + const dataKey = axisConfig.dataKey; + if (dataKey === undefined || axisConfig.data !== undefined) { + return axisConfig; + } + if (dataset === undefined) { + throw Error( + `MUI X Charts: ${axisName}-axis uses \`dataKey\` but no \`dataset\` is provided.`, + ); + } + return { + ...axisConfig, + data: dataset.map((d) => d[dataKey]), + }; + }); +}; diff --git a/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts b/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts new file mode 100644 index 000000000000..ee5376958745 --- /dev/null +++ b/packages/x-charts/src/context/CartesianProvider/useCartesianContext.ts @@ -0,0 +1,7 @@ +import * as React from 'react'; +import { CartesianContext, CartesianContextState } from './CartesianContext'; + +export const useCartesianContext = (): CartesianContextState => { + const { data } = React.useContext(CartesianContext); + return data; +}; diff --git a/packages/x-charts/src/hooks/useAxisEvents.ts b/packages/x-charts/src/hooks/useAxisEvents.ts index 0663d1655ae2..855ec5985c1a 100644 --- a/packages/x-charts/src/hooks/useAxisEvents.ts +++ b/packages/x-charts/src/hooks/useAxisEvents.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import { InteractionContext } from '../context/InteractionProvider'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { isBandScale } from '../internals/isBandScale'; import { AxisDefaultized } from '../models/axis'; import { getSVGPoint } from '../internals/utils'; @@ -13,7 +13,7 @@ function getAsANumber(value: number | Date) { export const useAxisEvents = (disableAxisListener: boolean) => { const svgRef = useSvgRef(); const { left, top, width, height } = useDrawingArea(); - const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext); + const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); const { dispatch } = React.useContext(InteractionContext); const usedXAxis = xAxisIds[0]; diff --git a/packages/x-charts/src/hooks/useColorScale.ts b/packages/x-charts/src/hooks/useColorScale.ts index 947d2acbd6de..1443bfc727bd 100644 --- a/packages/x-charts/src/hooks/useColorScale.ts +++ b/packages/x-charts/src/hooks/useColorScale.ts @@ -1,12 +1,12 @@ import * as React from 'react'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { AxisScaleComputedConfig, ScaleName } from '../models/axis'; import { ZAxisContext } from '../context/ZAxisContextProvider'; export function useXColorScale( identifier?: number | string, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { xAxis, xAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; @@ -16,7 +16,7 @@ export function useXColorScale( export function useYColorScale( identifier?: number | string, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { yAxis, yAxisIds } = React.useContext(CartesianContext); + const { yAxis, yAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; diff --git a/packages/x-charts/src/hooks/useDrawingArea.ts b/packages/x-charts/src/hooks/useDrawingArea.ts index e08c3e3a56b7..7b957071e1cd 100644 --- a/packages/x-charts/src/hooks/useDrawingArea.ts +++ b/packages/x-charts/src/hooks/useDrawingArea.ts @@ -1,7 +1,7 @@ import * as React from 'react'; -import { DrawingContext } from '../context/DrawingProvider'; +import { DrawingArea, DrawingContext } from '../context/DrawingProvider'; -export function useDrawingArea() { +export function useDrawingArea(): DrawingArea { const { left, top, width, height, bottom, right } = React.useContext(DrawingContext); return React.useMemo( () => ({ left, top, width, height, bottom, right }), diff --git a/packages/x-charts/src/hooks/useScale.ts b/packages/x-charts/src/hooks/useScale.ts index 648249f21c75..3af08f437bbf 100644 --- a/packages/x-charts/src/hooks/useScale.ts +++ b/packages/x-charts/src/hooks/useScale.ts @@ -1,5 +1,4 @@ -import * as React from 'react'; -import { CartesianContext } from '../context/CartesianContextProvider'; +import { useCartesianContext } from '../context/CartesianProvider'; import { isBandScale } from '../internals/isBandScale'; import { AxisScaleConfig, D3Scale, ScaleName } from '../models/axis'; @@ -19,7 +18,7 @@ export function getValueToPositionMapper(scale: D3Scale) { export function useXScale( identifier?: number | string, ): AxisScaleConfig[S]['scale'] { - const { xAxis, xAxisIds } = React.useContext(CartesianContext); + const { xAxis, xAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; @@ -29,7 +28,7 @@ export function useXScale( export function useYScale( identifier?: number | string, ): AxisScaleConfig[S]['scale'] { - const { yAxis, yAxisIds } = React.useContext(CartesianContext); + const { yAxis, yAxisIds } = useCartesianContext(); const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; diff --git a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx index 2e388f111c11..b5e0e40e86cb 100644 --- a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx +++ b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; -import { CartesianContext } from '../../../context/CartesianContextProvider'; +import { useCartesianContext } from '../../../context/CartesianProvider'; import { DrawingContext } from '../../../context/DrawingProvider'; import { useDrawingArea } from '../../../hooks'; import ChartsPiecewiseGradient from './ChartsPiecewiseGradient'; import ChartsContinuousGradient from './ChartsContinuousGradient'; +import { AxisId } from '../../../models/axis'; export function useChartGradient() { const { chartId } = React.useContext(DrawingContext); return React.useCallback( - (axisId: string, direction: 'x' | 'y') => `${chartId}-gradient-${direction}-${axisId}`, + (axisId: AxisId, direction: 'x' | 'y') => `${chartId}-gradient-${direction}-${axisId}`, [chartId], ); } @@ -19,7 +20,7 @@ export function ChartsAxesGradients() { const svgHeight = top + height + bottom; const svgWidth = left + width + right; const getGradientId = useChartGradient(); - const { xAxisIds, xAxis, yAxisIds, yAxis } = React.useContext(CartesianContext); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); return ( diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 6e6bafd231d4..fb23fa7f025f 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -14,7 +14,7 @@ export * from './configInit'; // contexts -export * from '../context/CartesianContextProvider'; +export * from '../context/CartesianProvider'; export * from '../context/DrawingProvider'; export * from '../context/InteractionProvider'; export * from '../context/SeriesContextProvider'; diff --git a/packages/x-charts/src/models/plugin.ts b/packages/x-charts/src/models/plugin.ts index a8b4dd5287e5..49e04baa8a4f 100644 --- a/packages/x-charts/src/models/plugin.ts +++ b/packages/x-charts/src/models/plugin.ts @@ -1,4 +1,9 @@ -import { ChartSeriesType, ExtremumGetter, Formatter } from './seriesType/config'; +import { + CartesianChartSeriesType, + ChartSeriesType, + ExtremumGetter, + Formatter, +} from './seriesType/config'; import { AxisDefaultized } from './axis'; import { DefaultizedSeriesType } from './seriesType'; import { ZAxisDefaultized } from './z-axis'; @@ -23,3 +28,7 @@ export type ChartsPluginType = T extends ChartSeriesType yExtremumGetter?: ExtremumGetter; } : never; + +export type ExtremumGettersConfig = { + [K in T]?: ExtremumGetter; +}; diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 4863552e605e..a38d3220182e 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -135,6 +135,7 @@ { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, { "name": "Direction", "kind": "TypeAlias" }, + { "name": "ExtremumGettersConfig", "kind": "TypeAlias" }, { "name": "FadeOptions", "kind": "TypeAlias" }, { "name": "Gauge", "kind": "Function" }, { "name": "gaugeClasses", "kind": "Variable" },