Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[charts] Divide CartesianProvider to use logic in Pro package #13531

Merged
merged 16 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,27 @@ function CartesianContextProvider(props: CartesianContextProviderProps) {

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(
() =>
computeValue(drawingArea, formattedSeries, xAxis, yAxis, xExtremumGetters, yExtremumGetters),
[drawingArea, formattedSeries, xAxis, xExtremumGetters, yAxis, yExtremumGetters],
() => ({
isInitialized: true,
data: {
xAxis: xValues.axis,
yAxis: yValues.axis,
xAxisIds: xValues.axisIds,
yAxisIds: yValues.axisIds,
},
}),
[xValues, yValues],
);

return <CartesianContext.Provider value={value}>{children}</CartesianContext.Provider>;
Expand Down
153 changes: 51 additions & 102 deletions packages/x-charts/src/context/CartesianProvider/computeValue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { scaleBand, scalePoint } from 'd3-scale';
import { DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '../../constants';
import { AxisConfig, ChartsXAxisProps, ScaleName } from '../../models';
import { ChartsYAxisProps, isBandScaleConfig, isPointScaleConfig } from '../../models/axis';
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';
Expand All @@ -12,31 +18,48 @@ import { FormattedSeries } from '../SeriesContextProvider';
import { MakeOptional } from '../../models/helpers';
import { getAxisExtremum } from './getAxisExtremum';

const DEFAULT_CATEGORY_GAP_RATIO = 0.2;
const DEFAULT_BAR_GAP_RATIO = 0.1;

export const computeValue = (
export function computeValue(
JCQuintas marked this conversation as resolved.
Show resolved Hide resolved
drawingArea: DrawingArea,
formattedSeries: FormattedSeries,
xAxis: MakeOptional<AxisConfig<ScaleName, any, ChartsXAxisProps>, 'id'>[] | undefined,
yAxis: MakeOptional<AxisConfig<ScaleName, any, ChartsYAxisProps>, 'id'>[] | undefined,
xExtremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter<K> },
yExtremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter<K> },
) => {
const allXAxis: AxisConfig<ScaleName, any, ChartsXAxisProps>[] = [
...(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 const }]
axis: MakeOptional<AxisConfig<ScaleName, any, ChartsYAxisProps>, 'id'>[] | undefined,
extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter<K> },
axisName: 'y',
): {
axis: DefaultizedAxisConfig<ChartsYAxisProps>;
axisIds: string[];
};
export function computeValue(
drawingArea: DrawingArea,
formattedSeries: FormattedSeries,
inAxis: MakeOptional<AxisConfig<ScaleName, any, ChartsXAxisProps>, 'id'>[] | undefined,
extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter<K> },
axisName: 'x',
): {
axis: DefaultizedAxisConfig<ChartsAxisProps>;
axisIds: string[];
};
export function computeValue(
drawingArea: DrawingArea,
formattedSeries: FormattedSeries,
inAxis: MakeOptional<AxisConfig<ScaleName, any, ChartsAxisProps>, 'id'>[] | undefined,
extremumGetters: { [K in CartesianChartSeriesType]?: ExtremumGetter<K> },
axisName: 'x' | 'y',
) {
const DEFAULT_AXIS_KEY = axisName === 'x' ? DEFAULT_X_AXIS_KEY : DEFAULT_Y_AXIS_KEY;

const allAxis: AxisConfig<ScaleName, any, ChartsAxisProps>[] = [
...(inAxis?.map((a, index) => ({ id: `defaultized-x-axis-${index}`, ...a })) ?? []),
...(inAxis === undefined || inAxis.findIndex(({ id }) => id === DEFAULT_AXIS_KEY) === -1
? [{ id: DEFAULT_AXIS_KEY, scaleType: 'linear' as const }]
: []),
];

const completedXAxis: DefaultizedAxisConfig<ChartsXAxisProps> = {};
allXAxis.forEach((axis, axisIndex) => {
const completeAxis: DefaultizedAxisConfig<ChartsAxisProps> = {};
allAxis.forEach((axis, axisIndex) => {
const isDefaultAxis = axisIndex === 0;
const [minData, maxData] = getAxisExtremum(
axis,
xExtremumGetters,
extremumGetters,
isDefaultAxis,
formattedSeries,
);
Expand All @@ -46,9 +69,12 @@ export const computeValue = (
: [drawingArea.left, drawingArea.left + drawingArea.width];

if (isBandScaleConfig(axis)) {
const DEFAULT_CATEGORY_GAP_RATIO = 0.2;
const DEFAULT_BAR_GAP_RATIO = 0.1;

const categoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO;
JCQuintas marked this conversation as resolved.
Show resolved Hide resolved
const barGapRatio = axis.barGapRatio ?? DEFAULT_BAR_GAP_RATIO;
completedXAxis[axis.id] = {
completeAxis[axis.id] = {
categoryGapRatio,
barGapRatio,
...axis,
Expand All @@ -64,7 +90,7 @@ export const computeValue = (
};
}
if (isPointScaleConfig(axis)) {
completedXAxis[axis.id] = {
completeAxis[axis.id] = {
...axis,
scale: scalePoint(axis.data!, range),
tickNumber: axis.data!.length,
Expand All @@ -89,79 +115,7 @@ export const computeValue = (
const [minDomain, maxDomain] = scale.domain();
const domain = [axis.min ?? minDomain, axis.max ?? maxDomain];

completedXAxis[axis.id] = {
...axis,
scaleType: scaleType as any,
scale: scale.domain(domain) as any,
tickNumber,
colorScale: axis.colorMap && getColorScale(axis.colorMap),
};
});

const allYAxis: AxisConfig<ScaleName, any, ChartsYAxisProps>[] = [
...(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 const }]
: []),
];

const completedYAxis: DefaultizedAxisConfig<ChartsYAxisProps> = {};
allYAxis.forEach((axis, axisIndex) => {
const isDefaultAxis = axisIndex === 0;
const [minData, maxData] = getAxisExtremum(
axis,
yExtremumGetters,
isDefaultAxis,
formattedSeries,
);
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' 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];

completedYAxis[axis.id] = {
completeAxis[axis.id] = {
...axis,
scaleType: scaleType as any,
scale: scale.domain(domain) as any,
Expand All @@ -171,12 +125,7 @@ export const computeValue = (
});

return {
isInitialized: true,
data: {
xAxis: completedXAxis,
yAxis: completedYAxis,
xAxisIds: allXAxis.map(({ id }) => id),
yAxisIds: allYAxis.map(({ id }) => id),
},
axis: completeAxis,
axisIds: allAxis.map(({ id }) => id),
};
};
}