-
Notifications
You must be signed in to change notification settings - Fork 19.7k
fix: xAxis label overflow fixed when containLabel=true #16880
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
base: master
Are you sure you want to change the base?
Conversation
Thanks for your contribution! |
src/coord/cartesian/Grid.ts
Outdated
@@ -202,10 +200,32 @@ class Grid implements CoordinateSystemMaster { | |||
} | |||
} | |||
}); | |||
|
|||
//Adjust grid.width to keep xAxis labels in dom | |||
const [xAxis, yAxis] = axesList[0].isHorizontal() ? axesList : axesList.slice().reverse(); |
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 think we don't need complex logic to check the first label and last label here.
In the
echarts/src/coord/cartesian/Grid.ts
Line 193 in c8a4906
gridRect[dim] -= labelUnionRect[dim] + margin; |
x
/width
based on the labels of yAxis. We can also check if the union rect of xAxis labels excced the canvas size. Then adjust x
/width
to avoid labels overflow.
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 function labelUnionRect
actually returns the largest bounding box of all labels of an axis, not the union bounding box. So I am not sure how to get the union rect of xAxis with this function. Also it would be hard to get the real size of displayed bounding box of labels because echarts seems to automatically clip labels according to axis length. That's why we just need to make sure the first/last label does not exceed the dom. Please correct me if I misunderstand you.
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 function labelUnionRect actually returns the largest bounding box of all labels of an axis, not the union bounding box
The method estimateLabelUnionRect
returns the union bounding box of all labels, not the largest.
so it would be hard to get the real size of displayed bounding box of labels because echarts seems to automatically clip labels according to axis length
I'm not sure what do you mean by clip labels. Correct me if I'm wrong. Indeed we only pick some of the labels if there are amount of theme, especially in category axis.
echarts/src/coord/axisHelper.ts
Line 324 in 4a52199
if (tickCount > 40) { |
Perhaps the last label will also be skipped. We can add some extra logic to ensure the first label and last label are also included.
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.
Also the current logic of estimating interval
and get formatted labels seems has been capsulated in the method
Line 223 in 4a52199
getViewLabels(): ReturnType<typeof createAxisLabels>['labels'] { |
Using this method to get all formatted labels will be more accurate and performant.
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 method estimateLabelUnionRect returns the union bounding box of all labels, not the largest.
The logic of function rect.union
is returning the union of bounding rect.
But here in echarts, if you trace the dataflow, every singleRect
has {x: 0, y: 0}
. So when you use union
on two rects at the same position, you are just returning the larger one. That's why I say it actually returns the largest bounding rect of all labels.
echarts/src/coord/axisHelper.ts
Lines 327 to 338 in 4a52199
for (let i = 0; i < tickCount; i += step) { | |
const tick = realNumberScaleTicks | |
? realNumberScaleTicks[i] | |
: { | |
value: categoryScaleExtent[0] + i | |
}; | |
const label = labelFormatter(tick, i); | |
const unrotatedSingleRect = axisLabelModel.getTextRect(label); | |
const singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0); | |
rect ? rect.union(singleRect) : (rect = singleRect); | |
} |
This doesn't result in errors for now because only
x/height
and y/width
is used in older version, and they are the same for union rect and largest rect.
However, thanks to your suggestion, I double-checked Axis.ts and found the function getTicksCoords
, which returns all displayed labels' (or ticks', they bind each other) coordinates. So I rewrite the changes and now I can accurately grab the first and the last label and check whether they would exceed the dom. Please review again.
P.S. Do you mind telling me how to get the dom size in Echarts? I struggled to get dom attributes but failed.
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.
So what I want to emphasize is right-most DISPLAYED label. The function getTicksCoord
would only return the labels that would be DISPLAYED. Those which are automatically hidden will not be included so I can just call getTicksCoord()[0]
to get the left-most DISPLAYED label and the right-most alike.
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.
Of course, xAxis.inverse
is also considered. For example, left-most label will be treated as the right-most if xAxis.inverse = true
.
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.
So what I want to emphasize is right-most DISPLAYED label. The function getTicksCoord would only return the labels that would be DISPLAYED. Those which are automatically hidden will not be included so I can just call getTicksCoord()[0] to get the left-most DISPLAYED label and the right-most alike.
I think that's not the difference. The union bounding rect should also be from the displayed labels .
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.
Hmmm, do you mean use getTicksCoord
to find displayed labels index, find their bounding box and implement union bounding rects on them? I don't see why we need to do that. Are you worrying that some too long in-middle label would exceed the dom too?
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.
getViewLabels
will return the labels that will be finally displayed on the chart. See how it is used when rendering the axis.
https://github.com/apache/echarts/blob/master/src/component/axis/AxisBuilder.ts
However the getTicksCoord
will have a different result when user-set axisTick.interval
and axisLabel.interval
are different. getTicksCoord
will use the axisTick.interval
to skip the tick lines and getViewLabels
will use axisLabel.interval
to skip the coord.
That's a good point. I rewrite the method with |
Just updated the code and delete the "simple optimization" of |
Just update another fix to check the axis type before using |
Hello, what's the state of this PR? Thanks 🙂 |
any updates on this? |
Brief Information
This pull request is in the type of:
What does this PR do?
Fix the problem of xAxis label overflow when
grid.contailLabel
is true.Fixed issues
Details
Before: What was the problem?
As is described in #16875 (comment), overflow of x-axis label is not considered when applying
grid.containLabel
.After: How is it fixed in this PR?
Judgements whether the label will exceed boundary are added and grid will be adjusted accordingly.
Misc
Related test cases or examples to use the new APIs
Attached
Merging options