diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx index 8f191ad95be7a..7e0c4147cdbff 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx @@ -37,7 +37,7 @@ const selectorReturnNull = () => null; function getIsOpenSelector( trigger: TriggerOptions, - axisSystem: 'none' | 'polar' | 'cartesian', + axisSystem: 'none' | 'radial' | 'cartesian', shouldPreventBecauseOfBrush?: boolean, ) { if (shouldPreventBecauseOfBrush) { @@ -46,7 +46,7 @@ function getIsOpenSelector( if (trigger === 'item') { return selectorChartsTooltipItemIsDefined; } - if (axisSystem === 'polar') { + if (axisSystem === 'radial') { return selectorChartsInteractionPolarAxisTooltip; } if (axisSystem === 'cartesian') { diff --git a/packages/x-charts/src/ChartsTooltip/useAxesTooltip.tsx b/packages/x-charts/src/ChartsTooltip/useAxesTooltip.tsx index 747d5a1b87d4b..0fc6f2d90ce6e 100644 --- a/packages/x-charts/src/ChartsTooltip/useAxesTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/useAxesTooltip.tsx @@ -3,6 +3,7 @@ import { useSeries } from '../hooks/useSeries'; import { useColorProcessor } from '../internals/plugins/corePlugins/useChartSeries/useColorProcessor'; import { type SeriesId } from '../models/seriesType/common'; import { + type ChartSeriesDefaultized, type CartesianChartSeriesType, type ChartsSeriesConfig, type PolarChartSeriesType, @@ -33,6 +34,7 @@ import { type ComposableCartesianChartSeriesType, composableCartesianSeriesTypes, } from '../models/seriesType/composition'; +import type { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; export interface UseAxesTooltipReturnValue< SeriesType extends CartesianChartSeriesType | PolarChartSeriesType = @@ -156,82 +158,92 @@ export function useAxesTooltip< }); } - Object.keys(series) - .filter((seriesType): seriesType is ComposableCartesianChartSeriesType => - composableCartesianSeriesTypes.has(seriesType as ComposableCartesianChartSeriesType), - ) - .forEach((seriesType: Type) => { - const seriesOfType = series[seriesType]; - if (!seriesOfType) { - return []; - } - return seriesOfType.seriesOrder.forEach((seriesId) => { - const seriesToAdd = seriesOfType.series[seriesId]!; - - // Skip hidden series (only if visibility manager is available) - if (isItemVisible && !isItemVisible({ type: seriesType, seriesId })) { - return; + const isCartesianContext = xAxis !== undefined || yAxis !== undefined; + + if (isCartesianContext) { + Object.keys(series) + .filter((seriesType): seriesType is ComposableCartesianChartSeriesType => + composableCartesianSeriesTypes.has(seriesType as ComposableCartesianChartSeriesType), + ) + .forEach((seriesType: Type) => { + const seriesOfType = series[seriesType] as ProcessedSeries[Type]; + if (!seriesOfType) { + return []; } + return seriesOfType.seriesOrder.forEach((seriesId) => { + const seriesToAdd = seriesOfType.series[seriesId] as ChartSeriesDefaultized< + Type, + 'cartesian' + >; + + // Skip hidden series (only if visibility manager is available) + if (isItemVisible && !isItemVisible({ type: seriesType, seriesId })) { + return; + } - const providedXAxisId = seriesToAdd.xAxisId ?? defaultXAxis.id; - const providedYAxisId = seriesToAdd.yAxisId ?? defaultYAxis.id; - - const tooltipItemIndex = tooltipAxes.findIndex( - ({ axisDirection, axisId }) => - (axisDirection === 'x' && axisId === providedXAxisId) || - (axisDirection === 'y' && axisId === providedYAxisId), - ); - // Test if the series uses the default axis - if (tooltipItemIndex >= 0) { - const zAxisId = 'zAxisId' in seriesToAdd ? seriesToAdd.zAxisId : zAxisIds[0]; - const { dataIndex } = tooltipAxes[tooltipItemIndex]; - const color = - colorProcessors[seriesType]?.( - seriesToAdd, - xAxis[providedXAxisId], - yAxis[providedYAxisId], - zAxisId ? zAxis[zAxisId] : undefined, - )(dataIndex) ?? ''; - - const rawValue = seriesToAdd.data[dataIndex] ?? null; - const formattedLabel = getLabel(seriesToAdd.label, 'tooltip') ?? null; - - let value: any; - let formattedValue: any; - - if (seriesType === 'ohlc' && Array.isArray(rawValue)) { - const [open, high, low, close] = rawValue as [number, number, number, number]; - const formatter = seriesToAdd.valueFormatter as any; - value = { open, high, low, close }; - formattedValue = { - open: formatter(open, { dataIndex, field: 'open' }), - high: formatter(high, { dataIndex, field: 'high' }), - low: formatter(low, { dataIndex, field: 'low' }), - close: formatter(close, { dataIndex, field: 'close' }), - }; - } else { - value = rawValue; - formattedValue = (seriesToAdd.valueFormatter as any)(rawValue, { - dataIndex, + const providedXAxisId = seriesToAdd.xAxisId ?? defaultXAxis.id; + const providedYAxisId = seriesToAdd.yAxisId ?? defaultYAxis.id; + + const tooltipItemIndex = tooltipAxes.findIndex( + ({ axisDirection, axisId }) => + (axisDirection === 'x' && axisId === providedXAxisId) || + (axisDirection === 'y' && axisId === providedYAxisId), + ); + // Test if the series uses the default axis + if (tooltipItemIndex >= 0) { + const zAxisId = 'zAxisId' in seriesToAdd ? seriesToAdd.zAxisId : zAxisIds[0]; + const { dataIndex } = tooltipAxes[tooltipItemIndex]; + const color = + colorProcessors[seriesType]?.( + seriesToAdd, + xAxis[providedXAxisId], + yAxis[providedYAxisId], + zAxisId ? zAxis[zAxisId] : undefined, + )(dataIndex) ?? ''; + + const rawValue = seriesToAdd.data[dataIndex] ?? null; + const formattedLabel = getLabel(seriesToAdd.label, 'tooltip') ?? null; + + let value: any; + let formattedValue: any; + + if (seriesType === 'ohlc' && Array.isArray(rawValue)) { + const [open, high, low, close] = rawValue as [number, number, number, number]; + const formatter = seriesToAdd.valueFormatter as any; + value = { open, high, low, close }; + formattedValue = { + open: formatter(open, { dataIndex, field: 'open' }), + high: formatter(high, { dataIndex, field: 'high' }), + low: formatter(low, { dataIndex, field: 'low' }), + close: formatter(close, { dataIndex, field: 'close' }), + }; + } else { + value = rawValue; + formattedValue = (seriesToAdd.valueFormatter as any)(rawValue, { + dataIndex, + }); + } + + tooltipAxes[tooltipItemIndex].seriesItems.push({ + seriesId, + color, + value, + formattedValue, + formattedLabel, + markType: seriesToAdd.labelMarkType, + markShape: + 'showMark' in seriesToAdd && seriesToAdd.showMark + ? (seriesToAdd.shape ?? 'circle') + : undefined, }); } - - tooltipAxes[tooltipItemIndex].seriesItems.push({ - seriesId, - color, - value, - formattedValue, - formattedLabel, - markType: seriesToAdd.labelMarkType, - markShape: - 'showMark' in seriesToAdd && seriesToAdd.showMark - ? (seriesToAdd.shape ?? 'circle') - : undefined, - }); - } + }); }); - }); + return tooltipAxes as UseAxesTooltipReturnValue[]; + } + + // For polar charts Object.keys(series) .filter(isPolarSeriesType) .forEach((seriesType: Type) => { @@ -278,6 +290,5 @@ export function useAxesTooltip< } }); }); - return tooltipAxes as UseAxesTooltipReturnValue[]; } diff --git a/packages/x-charts/src/LineChart/seriesConfig/getItemAtPosition.ts b/packages/x-charts/src/LineChart/seriesConfig/getItemAtPosition.ts index 85384fcb1de95..63b1359408577 100644 --- a/packages/x-charts/src/LineChart/seriesConfig/getItemAtPosition.ts +++ b/packages/x-charts/src/LineChart/seriesConfig/getItemAtPosition.ts @@ -154,7 +154,10 @@ export default function getItemAtPosition( const { axis: xAxes, axisIds: xAxisIds } = selectorChartXAxis(state); const { axis: yAxes, axisIds: yAxisIds } = selectorChartYAxis(state); - const series = selectorAllSeriesOfType(state, 'line') as ProcessedSeries['line']; + const series = selectorAllSeriesOfType(state, 'line') as ProcessedSeries< + 'line', + 'cartesian' + >['line']; if (!series || series.seriesOrder.length === 0) { return undefined; diff --git a/packages/x-charts/src/LineChart/seriesConfig/index.ts b/packages/x-charts/src/LineChart/seriesConfig/index.ts index d5631a46e5a1b..c4eb7740e051a 100644 --- a/packages/x-charts/src/LineChart/seriesConfig/index.ts +++ b/packages/x-charts/src/LineChart/seriesConfig/index.ts @@ -16,7 +16,7 @@ import { } from '../../internals/plugins/featurePlugins/useChartHighlight'; import descriptionGetter from './descriptionGetter'; -export const lineSeriesConfig: ChartSeriesTypeConfig<'line'> = { +export const lineSeriesConfig: ChartSeriesTypeConfig<'line', 'cartesian'> = { colorProcessor: getColor, seriesProcessor, legendGetter, diff --git a/packages/x-charts/src/LineChart/seriesConfig/tooltip.ts b/packages/x-charts/src/LineChart/seriesConfig/tooltip.ts index d2b8a3eac03b5..25c3ece46900b 100644 --- a/packages/x-charts/src/LineChart/seriesConfig/tooltip.ts +++ b/packages/x-charts/src/LineChart/seriesConfig/tooltip.ts @@ -4,7 +4,7 @@ import type { TooltipGetter, } from '../../internals/plugins/corePlugins/useChartSeriesConfig'; -const tooltipGetter: TooltipGetter<'line'> = (params) => { +const tooltipGetter: TooltipGetter<'line', 'cartesian'> = (params) => { const { series, getColor, identifier } = params; if (!identifier || identifier.dataIndex === undefined) { diff --git a/packages/x-charts/src/hooks/useAxisSystem.tsx b/packages/x-charts/src/hooks/useAxisSystem.tsx index d69100f71d052..0beaf49fcf34f 100644 --- a/packages/x-charts/src/hooks/useAxisSystem.tsx +++ b/packages/x-charts/src/hooks/useAxisSystem.tsx @@ -13,13 +13,13 @@ import { useStore } from '../internals/store/useStore'; * The hook assumes polar and cartesian are never implemented at the same time. * @returns The coordinate system */ -export function useAxisSystem(): 'none' | 'polar' | 'cartesian' { +export function useAxisSystem(): 'none' | 'radial' | 'cartesian' { const store = useStore<[UseChartPolarAxisSignature]>(); const rawRotationAxis = store.use(selectorChartRawRotationAxis); const rawXAxis = store.use(selectorChartRawXAxis); if (rawRotationAxis !== undefined) { - return 'polar'; + return 'radial'; } if (rawXAxis !== undefined) { return 'cartesian'; diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index 3a6ba535dbf77..65c2550377cb9 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -4,8 +4,10 @@ import { type SeriesId } from '../models/seriesType/common'; import { type ChartSeriesDefaultized } from '../models/seriesType/config'; import { useSeriesOfType, useAllSeriesOfType } from '../internals/seriesSelectorOfType'; -export type UseLineSeriesReturnValue = ChartSeriesDefaultized<'line'>; -export type UseLineSeriesContextReturnValue = ProcessedSeries['line']; +export type UseLineSeriesReturnValue = + ChartSeriesDefaultized<'line', AxisType>; +export type UseLineSeriesContextReturnValue = + ProcessedSeries<'line', AxisType>['line']; /** * Get access to the internal state of line series. @@ -13,7 +15,9 @@ export type UseLineSeriesContextReturnValue = ProcessedSeries['line']; * @param {SeriesId} seriesId The id of the series to get. * @returns {UseLineSeriesReturnValue} the line series */ -export function useLineSeries(seriesId: SeriesId): UseLineSeriesReturnValue | undefined; +export function useLineSeries( + seriesId: SeriesId, +): UseLineSeriesReturnValue | undefined; /** * Get access to the internal state of line series. * @@ -21,14 +25,18 @@ export function useLineSeries(seriesId: SeriesId): UseLineSeriesReturnValue | un * * @returns {UseLineSeriesReturnValue[]} the line series */ -export function useLineSeries(): UseLineSeriesReturnValue[]; +export function useLineSeries< + AxisType extends 'cartesian' | 'radial' = 'cartesian', +>(): UseLineSeriesReturnValue[]; /** * Get access to the internal state of line series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {UseLineSeriesReturnValue[]} the line series */ -export function useLineSeries(seriesIds: SeriesId[]): UseLineSeriesReturnValue[]; +export function useLineSeries( + seriesIds: SeriesId[], +): UseLineSeriesReturnValue[]; export function useLineSeries(seriesIds?: SeriesId | SeriesId[]) { return useSeriesOfType('line', seriesIds); } @@ -41,6 +49,8 @@ export function useLineSeries(seriesIds?: SeriesId | SeriesId[]) { * - stackingGroups: the array of stacking groups. Each group contains the series ids stacked and the strategy to use. * @returns the line series */ -export function useLineSeriesContext(): UseLineSeriesContextReturnValue { +export function useLineSeriesContext< + AxisType extends 'cartesian' | 'radial' = 'cartesian', +>(): UseLineSeriesContextReturnValue { return useAllSeriesOfType('line'); } diff --git a/packages/x-charts/src/internals/configInit.ts b/packages/x-charts/src/internals/configInit.ts index 708648c2453cb..05b4eee2aed65 100644 --- a/packages/x-charts/src/internals/configInit.ts +++ b/packages/x-charts/src/internals/configInit.ts @@ -61,3 +61,4 @@ cartesianSeriesTypes.addType('scatter'); export const polarSeriesTypes = new PolarSeriesTypes(); polarSeriesTypes.addType('radar'); +polarSeriesTypes.addType('line'); diff --git a/packages/x-charts/src/internals/isCartesian.ts b/packages/x-charts/src/internals/isCartesian.ts index 6aca5f40be1e9..c9ee1b30d3210 100644 --- a/packages/x-charts/src/internals/isCartesian.ts +++ b/packages/x-charts/src/internals/isCartesian.ts @@ -11,6 +11,6 @@ export function isCartesianSeriesType(seriesType: string): seriesType is Cartesi export function isCartesianSeries( series: ChartSeriesDefaultized, -): series is ChartSeriesDefaultized { +): series is ChartSeriesDefaultized { return isCartesianSeriesType(series.type); } diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeries/useChartSeries.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeries/useChartSeries.types.ts index 19a341b58c780..c78511a8c5715 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeries/useChartSeries.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeries/useChartSeries.types.ts @@ -56,8 +56,11 @@ export type UseChartSeriesDefaultizedParameters< theme: 'light' | 'dark'; }; -export type ProcessedSeries = { - [type in SeriesType]?: SeriesProcessorResult; +export type ProcessedSeries< + SeriesType extends ChartSeriesType = ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = { + [type in SeriesType]?: SeriesProcessorResult; }; export type SeriesLayout = { diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/cartesianExtremumGetter.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/cartesianExtremumGetter.types.ts index fafb307731328..9a9ca3c0358c9 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/cartesianExtremumGetter.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/cartesianExtremumGetter.types.ts @@ -6,7 +6,7 @@ import type { AxisConfig, AxisId } from '../../../../../models/axis'; import type { SeriesId } from '../../../../../models/seriesType/common'; type CartesianExtremumGetterParams = { - series: Record>; + series: Record>; axis: AxisConfig; axisIndex: number; isDefaultAxis: boolean; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/getItemAtPosition.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/getItemAtPosition.types.ts index e0964b346422e..0d9791f140307 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/getItemAtPosition.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/getItemAtPosition.types.ts @@ -3,7 +3,10 @@ import type { ChartState } from '../../../models/chart'; import type { ChartSeriesType } from '../../../../../models/seriesType/config'; import type { ChartSeriesTypeRequiredPlugins } from './seriesConfig.types'; -export type GetItemAtPosition = ( - state: ChartState>, +export type GetItemAtPosition< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial', +> = ( + state: ChartState>, point: { x: number; y: number }, ) => SeriesItemIdentifierWithType | undefined; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesConfig.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesConfig.types.ts index 6bffb5402aa66..443dadb0d2da9 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesConfig.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesConfig.types.ts @@ -24,14 +24,43 @@ import { type UseChartPolarAxisSignature } from '../../../featurePlugins/useChar import { type HighlightCreator } from '../../../featurePlugins/useChartHighlight/highlightCreator.types'; import { type AxisTooltipContentProps, type ItemTooltipContentProps } from './TooltipContent.types'; -export type ChartSeriesTypeRequiredPlugins = - ChartsSeriesConfig[SeriesType] extends { axisType: 'cartesian' } - ? [UseChartCartesianAxisSignature] - : ChartsSeriesConfig[SeriesType] extends { axisType: 'polar' } - ? [UseChartPolarAxisSignature] - : []; +export type ChartSeriesTypeRequiredPlugins< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = + Extract extends { axisType: infer A } + ? 'cartesian' extends A + ? 'radial' extends A + ? [] // Dual-mode series (both cartesian and polar): should be [polar] | [cartesian], but this look too complex to maintain compared to its benefits. + : [UseChartCartesianAxisSignature] + : 'radial' extends A + ? [UseChartPolarAxisSignature] + : [] + : []; -export type ChartSeriesTypeConfig = { +/** + * Helper type to compute the axis directions available for a given series type. + * Dual-mode series (both cartesian and polar) get all four directions. + */ +type ChartSeriesTypeAxisDirections< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = + | (SeriesType extends CartesianChartSeriesType + ? AxisType extends 'cartesian' + ? 'x' | 'y' + : never + : never) + | (SeriesType extends PolarChartSeriesType + ? AxisType extends 'radial' + ? 'rotation' | 'radius' + : never + : never); + +export type ChartSeriesTypeConfig< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = { seriesProcessor: SeriesProcessor; /** * A processor to add series layout when the layout does not depend from other series. @@ -57,27 +86,39 @@ export type ChartSeriesTypeConfig = { * @returns {SeriesItemIdentifierWithType} A cleaned identifier with only the relevant properties. */ identifierCleaner: IdentifierCleaner; - getItemAtPosition?: GetItemAtPosition; + getItemAtPosition?: GetItemAtPosition; descriptionGetter: DescriptionGetter; isHighlightedCreator: HighlightCreator; isFadedCreator: HighlightCreator; } & (SeriesType extends CartesianChartSeriesType - ? { - xExtremumGetter: CartesianExtremumGetter; - yExtremumGetter: CartesianExtremumGetter; - axisTooltipGetter?: AxisTooltipGetter; - AxisTooltipContent?: React.ComponentType>; - } + ? AxisType extends 'cartesian' + ? { + xExtremumGetter: CartesianExtremumGetter; + yExtremumGetter: CartesianExtremumGetter; + } + : {} : {}) & (SeriesType extends PolarChartSeriesType + ? AxisType extends 'radial' + ? { + rotationExtremumGetter: PolarExtremumGetter; + radiusExtremumGetter: PolarExtremumGetter; + } + : {} + : {}) & + (SeriesType extends CartesianChartSeriesType | PolarChartSeriesType ? { - rotationExtremumGetter: PolarExtremumGetter; - radiusExtremumGetter: PolarExtremumGetter; - axisTooltipGetter?: AxisTooltipGetter; AxisTooltipContent?: React.ComponentType>; + axisTooltipGetter?: AxisTooltipGetter< + SeriesType, + ChartSeriesTypeAxisDirections + >; } : {}); -export type ChartSeriesConfig = { - [Key in SeriesType]: ChartSeriesTypeConfig; +export type ChartSeriesConfig< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = { + [Key in SeriesType]: ChartSeriesTypeConfig; }; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesProcessor.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesProcessor.types.ts index 1b85be65944a0..10ba62585fe52 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesProcessor.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/seriesProcessor.types.ts @@ -13,8 +13,11 @@ export type SeriesProcessorParams = { seriesOrder: SeriesId[]; }; -export type SeriesProcessorResult = { - series: Record>; +export type SeriesProcessorResult< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = { + series: Record>; seriesOrder: SeriesId[]; } & (ChartsSeriesConfig[SeriesType] extends { canBeStacked: true; @@ -22,8 +25,11 @@ export type SeriesProcessorResult = { ? { stackingGroups: StackingGroupsType } : {}); -export type SeriesProcessor = ( +export type SeriesProcessor< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = ( params: SeriesProcessorParams, dataset?: Readonly, isItemVisible?: IsItemVisibleFunction, -) => SeriesProcessorResult; +) => SeriesProcessorResult; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/tooltipGetter.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/tooltipGetter.types.ts index a5655a978b6f9..81ef206f2dd71 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/tooltipGetter.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/tooltipGetter.types.ts @@ -72,8 +72,11 @@ export interface TooltipGetterAxesConfig { radius?: PolarAxisDefaultized; } -export type TooltipGetter = (params: { - series: ChartSeriesDefaultized; +export type TooltipGetter< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = (params: { + series: ChartSeriesDefaultized; axesConfig: TooltipGetterAxesConfig; getColor: ColorGetter; identifier: SeriesItemIdentifierWithType | null; @@ -93,5 +96,8 @@ export type AxisTooltipGetter< SeriesType extends ChartSeriesType, Directions extends 'x' | 'y' | 'rotation' | 'radius' = 'x' | 'y', > = ( - series: Record>, + series: Record< + SeriesId, + ChartSeriesDefaultized + >, ) => { direction: Directions; axisId: AxisId | undefined }[]; diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisDomainLimit.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisDomainLimit.ts index 3c786a60a0969..d5fc577955170 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisDomainLimit.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisDomainLimit.ts @@ -7,7 +7,7 @@ export const getAxisDomainLimit = ( axis: Pick, axisDirection: 'x' | 'y', axisIndex: number, - formattedSeries: ProcessedSeries, + formattedSeries: ProcessedSeries, ): | 'nice' | 'strict' diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtrema.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtrema.ts index 4f5f92d056cbd..1bfa388c6b5fe 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtrema.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/getAxisExtrema.ts @@ -13,7 +13,7 @@ const axisExtremumCallback = ( chartType: SeriesType, axis: AxisConfig, axisDirection: 'x' | 'y', - seriesConfig: ChartSeriesConfig, + seriesConfig: ChartSeriesConfig, axisIndex: number, formattedSeries: ProcessedSeries, getFilters?: GetZoomAxisFilters, diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.ts index ca3dae760a7fc..e132f6b568051 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.ts @@ -18,6 +18,8 @@ import { selectorChartsInteractionIsInitialized } from '../useChartInteraction'; import { selectorChartAxisInteraction } from './useChartCartesianInteraction.selectors'; import { checkHasInteractionPlugin } from '../useChartInteraction/checkHasInteractionPlugin'; import { type ChartsAxisData, type SeriesId } from '../../../../models'; +import { type ProcessedSeries } from '../../corePlugins/useChartSeries'; +import { type ChartSeriesType } from '../../../../models/seriesType/config'; const AXIS_CLICK_SERIES_TYPES = new Set(['bar', 'rangeBar', 'line'] as const); type AxisClickSeriesType = typeof AXIS_CLICK_SERIES_TYPES extends Set ? U : never; @@ -47,7 +49,9 @@ export const useChartCartesianAxis: ChartPlugin = store.use( + selectorChartSeriesProcessed, + ); const isInteractionEnabled = store.use(selectorChartsInteractionIsInitialized); const { axis: xAxisWithScale, axisIds: xAxisIds } = store.use(selectorChartXAxis); diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartPolarAxis/getAxisExtremum.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartPolarAxis/getAxisExtremum.ts index 12343061a381e..b54c84d9eb523 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartPolarAxis/getAxisExtremum.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartPolarAxis/getAxisExtremum.ts @@ -1,8 +1,9 @@ import { type AxisConfig } from '../../../../models/axis'; import { type PolarChartSeriesType } from '../../../../models/seriesType/config'; -import { - type ChartSeriesConfig, - type PolarExtremumGetterResult, +import type { + PolarExtremumGetter, + ChartSeriesConfig, + PolarExtremumGetterResult, } from '../../corePlugins/useChartSeriesConfig'; import { type ProcessedSeries } from '../../corePlugins/useChartSeries/useChartSeries.types'; import { isPolarSeriesType } from '../../../isPolar'; @@ -12,7 +13,7 @@ const axisExtremumCallback = ( chartType: SeriesType, axis: AxisConfig, axisDirection: 'rotation' | 'radius', - seriesConfig: ChartSeriesConfig, + seriesConfig: ChartSeriesConfig, axisIndex: number, formattedSeries: ProcessedSeries, ): PolarExtremumGetterResult => { @@ -22,7 +23,7 @@ const axisExtremumCallback = ( : seriesConfig[chartType].radiusExtremumGetter; const series = formattedSeries[chartType]?.series ?? {}; - const [minChartTypeData, maxChartTypeData] = getter?.({ + const [minChartTypeData, maxChartTypeData] = (getter as PolarExtremumGetter)?.({ series, axis, axisIndex, diff --git a/packages/x-charts/src/internals/seriesSelectorOfType.ts b/packages/x-charts/src/internals/seriesSelectorOfType.ts index 413453bf64a8b..3cd967a6c8525 100644 --- a/packages/x-charts/src/internals/seriesSelectorOfType.ts +++ b/packages/x-charts/src/internals/seriesSelectorOfType.ts @@ -1,7 +1,11 @@ import { warnOnce } from '@mui/x-internals/warning'; import { createSelector, createSelectorMemoized } from '@mui/x-internals/store'; -import { type ChartSeriesDefaultized, type ChartsSeriesConfig } from '../models/seriesType/config'; -import { type SeriesId } from '../models/seriesType/common'; +import type { + ChartSeriesType, + ChartSeriesDefaultized, + ChartsSeriesConfig, +} from '../models/seriesType/config'; +import type { SeriesId } from '../models/seriesType/common'; import { selectorChartSeriesProcessed } from './plugins/corePlugins/useChartSeries/useChartSeries.selectors'; import type { ProcessedSeries } from './plugins/corePlugins/useChartSeries'; import { useStore } from './store/useStore'; @@ -53,18 +57,26 @@ export const selectorSeriesOfType = createSelectorMemoized( }, ); -export const useAllSeriesOfType = (seriesType: T) => { +export const useAllSeriesOfType = < + T extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +>( + seriesType: T, +) => { const store = useStore(); - return store.use(selectorAllSeriesOfType, seriesType) as ProcessedSeries[T]; + return store.use(selectorAllSeriesOfType, seriesType) as ProcessedSeries[T]; }; -export const useSeriesOfType = ( +export const useSeriesOfType = < + T extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +>( seriesType: T, seriesId?: SeriesId | SeriesId[], ) => { const store = useStore(); return store.use(selectorSeriesOfType, seriesType, seriesId) as - | ChartSeriesDefaultized - | ChartSeriesDefaultized[] + | ChartSeriesDefaultized + | ChartSeriesDefaultized[] | undefined; }; diff --git a/packages/x-charts/src/models/seriesType/common.ts b/packages/x-charts/src/models/seriesType/common.ts index 8b2b654dd7f9d..44a908be006b9 100644 --- a/packages/x-charts/src/models/seriesType/common.ts +++ b/packages/x-charts/src/models/seriesType/common.ts @@ -79,6 +79,17 @@ export type CartesianSeriesType = { yAxisId?: AxisId; }; +export type RadialSeriesType = { + /** + * The id of the rotation axis used to render the series. + */ + rotationAxisId?: AxisId; + /** + * The id of the radius axis used to render the series. + */ + radiusAxisId?: AxisId; +}; + export type StackableSeriesType = { /** * The key that identifies the stacking group. diff --git a/packages/x-charts/src/models/seriesType/config.ts b/packages/x-charts/src/models/seriesType/config.ts index 4747753af15ba..affb532ac21b6 100644 --- a/packages/x-charts/src/models/seriesType/config.ts +++ b/packages/x-charts/src/models/seriesType/config.ts @@ -5,7 +5,13 @@ import type { ScatterItemIdentifier, ScatterValueType, } from './scatter'; -import type { LineSeriesType, DefaultizedLineSeriesType, LineItemIdentifier } from './line'; +import type { + LineSeriesType, + DefaultizedLineSeriesType, + LineItemIdentifier, + RadialLineSeriesType, + DefaultizedRadialLineSeriesType, +} from './line'; import type { BarItemIdentifier, BarSeriesType, DefaultizedBarSeriesType } from './bar'; import type { PieSeriesType, @@ -70,30 +76,55 @@ export interface ChartsSeriesConfig { dataIndex?: number | undefined; }; }; - line: { - seriesInput: DefaultizedProps & - MakeRequired, 'color'>; - series: DefaultizedLineSeriesType; - seriesLayout: {}; - seriesProp: LineSeriesType; - itemIdentifier: LineItemIdentifier; - itemIdentifierWithData: LineItemIdentifier; - valueType: number | null; - canBeStacked: true; - axisType: 'cartesian'; - highlightScope: CommonHighlightScope; - descriptionGetterParams: { - identifier: LineItemIdentifier; - xAxis: ComputedXAxis; - yAxis: ComputedYAxis; - series: DefaultizedLineSeriesType; - }; - highlightIdentifier: { - type: 'line'; - seriesId: SeriesId; - dataIndex?: number; - }; - }; + line: + | { + seriesInput: DefaultizedProps & + MakeRequired, 'color'>; + series: DefaultizedLineSeriesType; + seriesLayout: {}; + seriesProp: LineSeriesType; + itemIdentifier: LineItemIdentifier; + itemIdentifierWithData: LineItemIdentifier; + valueType: number | null; + canBeStacked: true; + axisType: 'cartesian'; + highlightScope: CommonHighlightScope; + descriptionGetterParams: { + identifier: LineItemIdentifier; + xAxis: ComputedXAxis; + yAxis: ComputedYAxis; + series: DefaultizedLineSeriesType; + }; + highlightIdentifier: { + type: 'line'; + seriesId: SeriesId; + dataIndex?: number; + }; + } + | { + seriesInput: DefaultizedProps & + MakeRequired, 'color'>; + series: DefaultizedRadialLineSeriesType; + seriesLayout: {}; + seriesProp: RadialLineSeriesType; + itemIdentifier: LineItemIdentifier; + itemIdentifierWithData: LineItemIdentifier; + valueType: number | null; + canBeStacked: true; + axisType: 'radial'; + highlightScope: CommonHighlightScope; + descriptionGetterParams: { + identifier: LineItemIdentifier; + xAxis: ComputedXAxis; + yAxis: ComputedYAxis; + series: DefaultizedRadialLineSeriesType; + }; + highlightIdentifier: { + type: 'line'; + seriesId: SeriesId; + dataIndex?: number; + }; + }; scatter: { seriesInput: DefaultizedProps & MakeRequired, 'color'>; @@ -149,7 +180,7 @@ export interface ChartsSeriesConfig { itemIdentifier: RadarItemIdentifier; itemIdentifierWithData: RadarItemIdentifier; valueType: number; - axisType: 'polar'; + axisType: 'radial'; highlightScope: CommonHighlightScope; descriptionGetterParams: { identifier: RadarItemIdentifier; @@ -173,8 +204,10 @@ export type ChartSeriesType = keyof ChartsSeriesConfig; export type CartesianChartSeriesType = keyof Pick< ChartsSeriesConfig, { - [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { axisType: 'cartesian' } - ? Key + [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { axisType: infer A } + ? 'cartesian' extends A + ? Key + : never : never; }[ChartSeriesType] >; @@ -193,7 +226,11 @@ export type SeriesTypeWithDataIndex = { export type PolarChartSeriesType = keyof Pick< ChartsSeriesConfig, { - [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { axisType: 'polar' } ? Key : never; + [Key in ChartSeriesType]: ChartsSeriesConfig[Key] extends { axisType: infer A } + ? 'radial' extends A + ? Key + : never + : never; }[ChartSeriesType] >; @@ -204,18 +241,28 @@ export type StackableChartSeriesType = keyof Pick< }[ChartSeriesType] >; -export type ChartSeries = - ChartsSeriesConfig[SeriesType]['seriesInput']; +export type ChartSeries< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = AxisType extends 'cartesian' | 'radial' + ? Extract['seriesInput'] + : ChartsSeriesConfig[SeriesType]['seriesInput']; -export type ChartSeriesDefaultized = - ChartsSeriesConfig[SeriesType] extends { +export type ChartSeriesDefaultized< + SeriesType extends ChartSeriesType, + AxisType extends 'cartesian' | 'radial' = any, +> = (AxisType extends 'cartesian' | 'radial' + ? Extract['series'] + : ChartsSeriesConfig[SeriesType]['series']) & + (ChartsSeriesConfig[SeriesType] extends { canBeStacked: true; } - ? ChartsSeriesConfig[SeriesType]['series'] & { + ? { visibleStackedData: [number, number][]; + stackedData: [number, number][]; } - : ChartsSeriesConfig[SeriesType]['series']; + : {}); export type ChartSeriesLayout = ChartsSeriesConfig[SeriesType] extends any diff --git a/packages/x-charts/src/models/seriesType/line.ts b/packages/x-charts/src/models/seriesType/line.ts index 74155a0ec6ef5..c028ebf51fa64 100644 --- a/packages/x-charts/src/models/seriesType/line.ts +++ b/packages/x-charts/src/models/seriesType/line.ts @@ -1,11 +1,12 @@ import { type DefaultizedProps } from '@mui/x-internals/types'; import type { StackOffsetType } from '../stacking'; -import { - type CartesianSeriesType, - type CommonDefaultizedProps, - type CommonSeriesType, - type SeriesId, - type StackableSeriesType, +import type { + RadialSeriesType, + CartesianSeriesType, + CommonDefaultizedProps, + CommonSeriesType, + SeriesId, + StackableSeriesType, } from './common'; import { type DatasetElementType } from './config'; import { type CurveType } from '../curve'; @@ -35,8 +36,8 @@ export interface ShowMarkParams { export type MarkShape = 'circle' | 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye'; -export interface LineSeriesType - extends CommonSeriesType, CartesianSeriesType, StackableSeriesType { +interface CommonLineSeriesType + extends CommonSeriesType, StackableSeriesType { type: 'line'; /** * Data associated to the line. @@ -113,6 +114,10 @@ export interface LineSeriesType baseline?: number | 'min' | 'max'; } +export interface LineSeriesType extends CommonLineSeriesType, CartesianSeriesType {} + +export interface RadialLineSeriesType extends CommonLineSeriesType, RadialSeriesType {} + /** * An object that allows to identify a single line. * Used for item interaction @@ -132,3 +137,10 @@ export interface DefaultizedLineSeriesType extends DefaultizedProps< > { hidden: boolean; } + +export interface DefaultizedRadialLineSeriesType extends DefaultizedProps< + RadialLineSeriesType, + CommonDefaultizedProps | 'color' +> { + hidden: boolean; +} diff --git a/scripts/x-charts-premium.exports.json b/scripts/x-charts-premium.exports.json index 9e452abd3f86d..06c798ff910be 100644 --- a/scripts/x-charts-premium.exports.json +++ b/scripts/x-charts-premium.exports.json @@ -246,6 +246,7 @@ { "name": "DefaultizedPieSeriesType", "kind": "Interface" }, { "name": "DefaultizedPieValueType", "kind": "TypeAlias" }, { "name": "DefaultizedRadarSeriesType", "kind": "Interface" }, + { "name": "DefaultizedRadialLineSeriesType", "kind": "Interface" }, { "name": "DefaultizedRangeBarSeriesType", "kind": "Interface" }, { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, @@ -497,6 +498,7 @@ { "name": "RadarSeriesPlot", "kind": "Function" }, { "name": "RadarSeriesPlotProps", "kind": "Interface" }, { "name": "RadarSeriesType", "kind": "Interface" }, + { "name": "RadialLineSeriesType", "kind": "Interface" }, { "name": "RadiusAxis", "kind": "TypeAlias" }, { "name": "rainbowSurgePalette", "kind": "Variable" }, { "name": "rainbowSurgePaletteDark", "kind": "Variable" }, diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index 04938f7cd0edb..a9d5b8ca7cec4 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -240,6 +240,7 @@ { "name": "DefaultizedPieSeriesType", "kind": "Interface" }, { "name": "DefaultizedPieValueType", "kind": "TypeAlias" }, { "name": "DefaultizedRadarSeriesType", "kind": "Interface" }, + { "name": "DefaultizedRadialLineSeriesType", "kind": "Interface" }, { "name": "DefaultizedSankeySeriesType", "kind": "Interface" }, { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, @@ -477,6 +478,7 @@ { "name": "RadarSeriesPlot", "kind": "Function" }, { "name": "RadarSeriesPlotProps", "kind": "Interface" }, { "name": "RadarSeriesType", "kind": "Interface" }, + { "name": "RadialLineSeriesType", "kind": "Interface" }, { "name": "RadiusAxis", "kind": "TypeAlias" }, { "name": "rainbowSurgePalette", "kind": "Variable" }, { "name": "rainbowSurgePaletteDark", "kind": "Variable" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index a4d43093c3cb1..b2b7e371c9278 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -204,6 +204,7 @@ { "name": "DefaultizedPieSeriesType", "kind": "Interface" }, { "name": "DefaultizedPieValueType", "kind": "TypeAlias" }, { "name": "DefaultizedRadarSeriesType", "kind": "Interface" }, + { "name": "DefaultizedRadialLineSeriesType", "kind": "Interface" }, { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, { "name": "Direction", "kind": "TypeAlias" }, @@ -360,6 +361,7 @@ { "name": "RadarSeriesPlot", "kind": "Function" }, { "name": "RadarSeriesPlotProps", "kind": "Interface" }, { "name": "RadarSeriesType", "kind": "Interface" }, + { "name": "RadialLineSeriesType", "kind": "Interface" }, { "name": "RadiusAxis", "kind": "TypeAlias" }, { "name": "rainbowSurgePalette", "kind": "Variable" }, { "name": "rainbowSurgePaletteDark", "kind": "Variable" },