@@ -32,9 +32,8 @@ const useUtilityClasses = (ownerState: ChartsXAxisProps & { theme: Theme }) => {
32
32
return composeClasses ( slots , getAxisUtilityClass , classes ) ;
33
33
} ;
34
34
35
- type LabelExtraData = { skipLabel ?: boolean } ;
36
-
37
- function addLabelDimension (
35
+ /* Returns a set of indices of the tick labels that should be visible. */
36
+ function getVisibleLabels (
38
37
xTicks : TickItemType [ ] ,
39
38
{
40
39
tickLabelStyle : style ,
@@ -49,7 +48,7 @@ function addLabelDimension(
49
48
isMounted : boolean ;
50
49
isPointInside : ( position : number ) => boolean ;
51
50
} ,
52
- ) : ( TickItemType & LabelExtraData ) [ ] {
51
+ ) : Set < number > {
53
52
const getTickLabelSize = ( tick : TickItemType ) => {
54
53
if ( ! isMounted || tick . formattedValue === undefined ) {
55
54
return { width : 0 , height : 0 } ;
@@ -64,54 +63,52 @@ function addLabelDimension(
64
63
} ;
65
64
66
65
if ( typeof tickLabelInterval === 'function' ) {
67
- return xTicks . map ( ( item , index ) => {
68
- const skipLabel = ! tickLabelInterval ( item . value , index ) ;
69
- const size = skipLabel ? { width : 0 , height : 0 } : getTickLabelSize ( item ) ;
70
-
71
- return {
72
- ...item ,
73
- ...size ,
74
- skipLabel,
75
- } ;
76
- } ) ;
66
+ return new Set (
67
+ xTicks . filter ( ( item , index ) => tickLabelInterval ( item . value , index ) ) . map ( ( _ , i ) => i ) ,
68
+ ) ;
77
69
}
78
70
79
71
// Filter label to avoid overlap
80
72
let previousTextLimit = 0 ;
81
73
const direction = reverse ? - 1 : 1 ;
82
74
83
- return xTicks . map ( ( item , labelIndex ) => {
84
- const { offset, labelOffset } = item ;
85
- const textPosition = offset + labelOffset ;
86
-
87
- if (
88
- labelIndex > 0 &&
89
- direction * textPosition < direction * ( previousTextLimit + tickLabelMinGap )
90
- ) {
91
- return { ...item , skipLabel : true } ;
92
- }
93
-
94
- if ( ! isPointInside ( textPosition ) ) {
95
- return { ...item , skipLabel : true } ;
96
- }
97
-
98
- const { width, height } = getTickLabelSize ( item ) ;
99
-
100
- const distance = getMinXTranslation ( width , height , style ?. angle ) ;
101
-
102
- const currentTextLimit = textPosition - ( direction * distance ) / 2 ;
103
- if (
104
- labelIndex > 0 &&
105
- direction * currentTextLimit < direction * ( previousTextLimit + tickLabelMinGap )
106
- ) {
107
- // Except for the first label, we skip all label that overlap with the last accepted.
108
- // Notice that the early return prevents `previousTextLimit` from being updated.
109
- return { ...item , skipLabel : true } ;
110
- }
111
-
112
- previousTextLimit = textPosition + ( direction * distance ) / 2 ;
113
- return item ;
114
- } ) ;
75
+ return new Set (
76
+ xTicks
77
+ . filter ( ( item , labelIndex ) => {
78
+ const { offset, labelOffset } = item ;
79
+ const textPosition = offset + labelOffset ;
80
+
81
+ if (
82
+ labelIndex > 0 &&
83
+ direction * textPosition < direction * ( previousTextLimit + tickLabelMinGap )
84
+ ) {
85
+ return false ;
86
+ }
87
+
88
+ if ( ! isPointInside ( textPosition ) ) {
89
+ return false ;
90
+ }
91
+
92
+ /* Measuring text width is expensive, so we need to delay it as much as possible to improve performance. */
93
+ const { width, height } = getTickLabelSize ( item ) ;
94
+
95
+ const distance = getMinXTranslation ( width , height , style ?. angle ) ;
96
+
97
+ const currentTextLimit = textPosition - ( direction * distance ) / 2 ;
98
+ if (
99
+ labelIndex > 0 &&
100
+ direction * currentTextLimit < direction * ( previousTextLimit + tickLabelMinGap )
101
+ ) {
102
+ // Except for the first label, we skip all label that overlap with the last accepted.
103
+ // Notice that the early return prevents `previousTextLimit` from being updated.
104
+ return false ;
105
+ }
106
+
107
+ previousTextLimit = textPosition + ( direction * distance ) / 2 ;
108
+ return true ;
109
+ } )
110
+ . map ( ( _ , i ) => i ) ,
111
+ ) ;
115
112
}
116
113
117
114
const XAxisRoot = styled ( AxisRoot , {
@@ -206,7 +203,7 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
206
203
tickLabelPlacement,
207
204
} ) ;
208
205
209
- const xTicksWithDimension = addLabelDimension ( xTicks , {
206
+ const visibleLabels = getVisibleLabels ( xTicks , {
210
207
tickLabelStyle : axisTickLabelProps . style ,
211
208
tickLabelInterval,
212
209
reverse,
@@ -252,7 +249,7 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
252
249
< Line x1 = { left } x2 = { left + width } className = { classes . line } { ...slotProps ?. axisLine } />
253
250
) }
254
251
255
- { xTicksWithDimension . map ( ( { formattedValue, offset, labelOffset, skipLabel } , index ) => {
252
+ { xTicks . map ( ( { formattedValue, offset, labelOffset } , index ) => {
256
253
const xTickLabel = labelOffset ?? 0 ;
257
254
const yTickLabel = positionSign * ( tickSize + 3 ) ;
258
255
@@ -261,6 +258,8 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
261
258
{ x : offset + xTickLabel , y : - 1 } ,
262
259
{ direction : 'x' } ,
263
260
) ;
261
+ const skipLabel = ! visibleLabels . has ( index ) ;
262
+
264
263
return (
265
264
< g key = { index } transform = { `translate(${ offset } , 0)` } className = { classes . tickContainer } >
266
265
{ ! disableTicks && showTick && (
0 commit comments