Skip to content

Commit c95783c

Browse files
[charts] improve tick rendering performance
1 parent 886bae5 commit c95783c

File tree

5 files changed

+45
-18
lines changed

5 files changed

+45
-18
lines changed

packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function ChartsGridHorizontal(props: ChartsGridHorizontalProps) {
1919

2020
const { scale, tickNumber, tickInterval } = axis;
2121

22-
const yTicks = useTicks({ scale, tickNumber, tickInterval });
22+
const yTicks = useTicks({ scale, tickNumber, tickInterval, direction: 'x' });
2323

2424
return (
2525
<React.Fragment>

packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function ChartsGridVertical(props: ChartsGridVerticalProps) {
1919

2020
const { scale, tickNumber, tickInterval } = axis;
2121

22-
const xTicks = useTicks({ scale, tickNumber, tickInterval });
22+
const xTicks = useTicks({ scale, tickNumber, tickInterval, direction: 'y' });
2323

2424
return (
2525
<React.Fragment>

packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
284284
tickInterval,
285285
tickPlacement,
286286
tickLabelPlacement,
287+
direction: 'x',
287288
});
288289

289290
const visibleLabels = getVisibleLabels(xTicks, {

packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) {
171171
tickPlacement,
172172
tickLabelPlacement,
173173
tickInterval,
174+
direction: 'y',
174175
});
175176

176177
const positionSign = position === 'right' ? 1 : -1;

packages/x-charts/src/hooks/useTicks.ts

+41-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22
import * as React from 'react';
3+
import { useChartContext } from '@mui/x-charts/context/ChartProvider';
34
import { AxisConfig, D3Scale } from '../models/axis';
45
import { isBandScale } from '../internals/isBandScale';
56
import { isInfinity } from '../internals/isInfinity';
@@ -85,6 +86,7 @@ export function useTicks(
8586
options: {
8687
scale: D3Scale;
8788
valueFormatter?: AxisConfig['valueFormatter'];
89+
direction: 'x' | 'y';
8890
} & Pick<TickParams, 'tickNumber' | 'tickInterval' | 'tickPlacement' | 'tickLabelPlacement'>,
8991
): TickItemType[] {
9092
const {
@@ -94,7 +96,9 @@ export function useTicks(
9496
tickInterval,
9597
tickPlacement = 'extremities',
9698
tickLabelPlacement: tickLabelPlacementProp,
99+
direction,
97100
} = options;
101+
const { instance } = useChartContext();
98102

99103
return React.useMemo(() => {
100104
// band scale
@@ -157,20 +161,41 @@ export function useTicks(
157161
}
158162
const tickLabelPlacement = tickLabelPlacementProp;
159163
const ticks = typeof tickInterval === 'object' ? tickInterval : scale.ticks(tickNumber);
160-
return ticks.map((value: any, i) => {
161-
return {
162-
value,
163-
formattedValue:
164-
valueFormatter?.(value, { location: 'tick', scale }) ??
165-
scale.tickFormat(tickNumber)(value),
166-
offset: scale(value),
167-
// Allowing the label to be placed in the middle of a continuous scale is weird.
168-
// But it is useful in some cases, like funnel categories with a linear scale.
169-
labelOffset:
170-
tickLabelPlacement === 'middle'
171-
? scale(ticks[i - 1] ?? 0) - (scale(value) + scale(ticks[i - 1] ?? 0)) / 2
172-
: 0,
173-
};
174-
});
175-
}, [scale, tickInterval, tickNumber, valueFormatter, tickPlacement, tickLabelPlacementProp]);
164+
165+
// Ticks inside the drawing area
166+
const visibleTicks = [];
167+
168+
for (let i = 0; i < ticks.length; i += 1) {
169+
const value = ticks[i];
170+
const offset = scale(value);
171+
const point = direction === 'x' ? { x: offset, y: 0 } : { x: 0, y: offset };
172+
173+
if (instance.isPointInside(point, { direction })) {
174+
visibleTicks.push({
175+
value,
176+
formattedValue:
177+
valueFormatter?.(value, { location: 'tick', scale }) ??
178+
scale.tickFormat(tickNumber)(value),
179+
offset,
180+
// Allowing the label to be placed in the middle of a continuous scale is weird.
181+
// But it is useful in some cases, like funnel categories with a linear scale.
182+
labelOffset:
183+
tickLabelPlacement === 'middle'
184+
? scale(ticks[i - 1] ?? 0) - (offset + scale(ticks[i - 1] ?? 0)) / 2
185+
: 0,
186+
});
187+
}
188+
}
189+
190+
return visibleTicks;
191+
}, [
192+
scale,
193+
tickLabelPlacementProp,
194+
tickInterval,
195+
tickNumber,
196+
tickPlacement,
197+
valueFormatter,
198+
direction,
199+
instance,
200+
]);
176201
}

0 commit comments

Comments
 (0)