-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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] fix x-axis tick label overflow #16709
[charts] fix x-axis tick label overflow #16709
Conversation
Deploy preview: https://deploy-preview-16709--material-ui-x.netlify.app/ Updated pages: |
8e61dfe
to
961878d
Compare
2b2dc4c
to
acd8b68
Compare
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
a1d7350
to
ba2165a
Compare
CodSpeed Performance ReportMerging #16709 will not alter performanceComparing Summary
|
7c0b2c2
to
87d9dfe
Compare
There's a small conflict with overflow + text-anchor next to the limit of the chart. In this case (circled blue), we have 60px to the left of the X axis to render the tick label. However, the There are at least these two options:
Obviously, number 2 would be preferable, but I'm worried it might increase the scope of this PR too much since it might create more questions. One I can think of is:
@alexfauquette @JCQuintas what do you think? |
885c737
to
3472b18
Compare
Seems good
I'm good with this solution. It's a realy nich issue |
83dc895
to
da69e85
Compare
do { | ||
lastLength = newLength; | ||
newLength = Math.floor(text.length * by); | ||
|
||
ellipsizedText = sliceUntil(text, newLength).trim(); | ||
const fits = doesTextFitInRect(ellipsizedText + ELLIPSIS, config); | ||
step += 1; | ||
|
||
if (fits) { | ||
longestFittingText = ellipsizedText; | ||
by += 1 / 2 ** step; | ||
} else { | ||
by -= 1 / 2 ** step; | ||
} | ||
} while (newLength !== lastLength); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal of this algorithm is to search for the point where text is longest and fits.
Let's say you have a string with 32 characters. The algorithm will first check if the 32 characters fit. If not, it'll check if 16 characters fit, then:
- If 16 characters don't fit, it'll check if 8 characters fit
- If the 16 characters fit, it will check if 24 characters fit
The idea is to split the search space in two in every iteration. The algorithm will eventually stop when it can no longer split the search space.
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
9eed1a4
to
d276110
Compare
f24a704
to
dcb8a3f
Compare
|
||
let count = 0; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/naming-convention,no-underscore-dangle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to disable all of these, otherwise CI will fail 🤣
segments
is an iterator, so we need to iterate it to count. I could do Array.from()
but didn't want to allocate an array just to obtain its length.
As such, the _unused
var is useless, but I can't name it _
or unused
because that will cause different lint errors to fire.

9d09700
to
3aefeeb
Compare
|
||
const tickLabels = isClient | ||
? shortenLabels(visibleLabels, drawingArea, tickLabelsMaxHeight, axisTickLabelProps.style) | ||
: new Map(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we should no labels or all labels when server-side rendering.
All labels would make more sense for the cases when there's no overlap, but they wouldn't look good for cases with an overlap 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All labels would make more sense for the cases when there's no overlap
I agree on this one, especially if devs don't care at all about SSR, they might use the responsive charts wich do not render on server because they don't have access to their height/width. And if they care, they can filter values by themself to remove overflow
This reverts commit 6bd18f2.
8cc3c1c
to
1d4d31b
Compare
There's this hydration issue that's causing the axis labels to be incorrectly positioned. For some reason, Next isn't updating the Screen.Recording.2025-03-11.at.14.58.36.mov |
I have this fix, but I'm not too happy about it because we're applying a transform that might not make sense to apply if the user is customizing the component. @alexfauquette @JCQuintas do you see any other option? |
Is this happening because |
Yes. |
Would changing the anchor solve the issue, instead of calculating the line height? |
Yeah, it could work, but how would you go about it? I tried changing the |
It seems you can try to get funky with
|
Disclaimer, test on different browsers, not sure how they will react to this 😆 |
@bernardobelchior I pushed the fix from JC suggestion. |
const isClient = useIsClient(); | ||
|
||
const wordsByLines = React.useMemo( | ||
() => getWordsByLines({ style, needsComputation: text.includes('\n'), text }), | ||
[style, text], | ||
() => getWordsByLines({ style, needsComputation: isClient && text.includes('\n'), text }), | ||
[style, text, isClient], | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed similar hydration issues when using \n
in axes labels. SO I added this fix that ignore the size computation during the hydration phase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, technically isClient
is not correct, because the hydration is on the client. It's more isHydrationDone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, technically isClient is not correct, because the hydration is on the client. It's more isHydrationDone
I'll rename it in a follow-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: #16937
); | ||
|
||
let startDy: number; | ||
switch (dominantBaseline) { | ||
case 'hanging': | ||
case 'text-before-edge': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I adde dthis one and the text-after-edge
because it gives better result.
Makes me realise the hanging
and auto
are not 100% correctly computed but nobody complained about it
I found a solution that works for almost all browsers, but unfortunately it doesn't work on Safari <= 18.3 (i.e,. in Safari, it only works in the current beta, which is 18.4). The problem is that the line-height unit ( Here's an example CodeSandbox. Screen.Recording.2025-03-12.at.10.27.46.mov |
Thank you! |
Part of #10928.
Fix x-axis tick label overflow by applying an ellipsis for overflowing labels.
This PR does not change the algorithm for tick label visibility, so that logic should remain the same. The only difference is if those label would cause an overflow, they no longer will. This is especially noticeable for angles !== 0 and for tick labels at the extremities of charts.
Before
After
Checklist
Test multi-line labels

Test multiple anchors/baselines
Test with zoom
Screen.Recording.2025-03-04.at.09.42.23.mov
Test ellipsis with unicode characters

Changelog
Tick labels in the x-axis of cartesian charts will now have an ellipsis applied to prevent overflow.
If your tick labels are being clipped sooner than you would like, you can increase the x-axis size by increasing its
height
property.The default line-height has also been changed to 1.25, so if you aren't customizing the line height for x-axis tick labels, make sure to double check if the result is desirable.