-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add autotickangles property #6790
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
Changes from 35 commits
264617b
9170f25
eb3c456
60aa918
b70ff86
be99b12
8ec9a45
3fa1c78
6d2501b
3f08ba8
7ff8d92
9473029
4b23f99
361f61b
6d3e7bd
896c247
aa6d492
8ebf1a2
0fdf52e
a9b9cc8
b8a8860
c0e2758
cdae996
80dedea
a5b1f3a
5f3f32c
f544c2a
7d8e607
e20de82
4d4e056
84bd54b
f646c15
1d47d05
2f6cd6f
c51791e
b293a11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- Add `autotickangles` to cartesian axes [[#6790](https://github.com/plotly/plotly.js/pull/6790)], with thanks to @my-tien for the contribution! | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3472,13 +3472,13 @@ axes.drawLabels = function(gd, ax, opts) { | |
|
||
var fullLayout = gd._fullLayout; | ||
var axId = ax._id; | ||
var axLetter = axId.charAt(0); | ||
var cls = opts.cls || axId + 'tick'; | ||
|
||
var vals = opts.vals.filter(function(d) { return d.text; }); | ||
|
||
var labelFns = opts.labelFns; | ||
var tickAngle = opts.secondary ? 0 : ax.tickangle; | ||
|
||
var prevAngle = (ax._prevTickAngles || {})[cls]; | ||
|
||
var tickLabels = opts.layer.selectAll('g.' + cls) | ||
|
@@ -3719,21 +3719,22 @@ axes.drawLabels = function(gd, ax, opts) { | |
// check for auto-angling if x labels overlap | ||
// don't auto-angle at all for log axes with | ||
// base and digit format | ||
if(vals.length && axLetter === 'x' && !isNumeric(tickAngle) && | ||
if(vals.length && ax.autotickangles && | ||
(ax.type !== 'log' || String(ax.dtick).charAt(0) !== 'D') | ||
) { | ||
autoangle = 0; | ||
autoangle = ax.autotickangles[0]; | ||
|
||
var maxFontSize = 0; | ||
var lbbArray = []; | ||
var i; | ||
|
||
var maxLines = 1; | ||
tickLabels.each(function(d) { | ||
maxFontSize = Math.max(maxFontSize, d.fontSize); | ||
|
||
var x = ax.l2p(d.x); | ||
var thisLabel = selectTickLabel(this); | ||
var bb = Drawing.bBox(thisLabel.node()); | ||
maxLines = Math.max(maxLines, svgTextUtils.lineCount(thisLabel)); | ||
|
||
lbbArray.push({ | ||
// ignore about y, just deal with x overlaps | ||
|
@@ -3780,12 +3781,31 @@ axes.drawLabels = function(gd, ax, opts) { | |
var pad = !isAligned ? 0 : | ||
(ax.tickwidth || 0) + 2 * TEXTPAD; | ||
|
||
var rotate90 = (tickSpacing < maxFontSize * 2.5) || ax.type === 'multicategory' || ax._name === 'realaxis'; | ||
// autotickangles | ||
var adjacent = tickSpacing; | ||
var opposite = maxFontSize * 1.25 * maxLines; | ||
var hypotenuse = Math.sqrt(Math.pow(adjacent, 2) + Math.pow(opposite, 2)); | ||
var maxCos = adjacent / hypotenuse; | ||
var autoTickAnglesRadians = ax.autotickangles.map( | ||
function(degrees) { return degrees * Math.PI / 180; } | ||
); | ||
var angleRadians = autoTickAnglesRadians.find( | ||
function(angle) { return Math.abs(Math.cos(angle)) <= maxCos; } | ||
); | ||
if(angleRadians === undefined) { | ||
// no angle with smaller cosine than maxCos, just pick the angle with smallest cosine | ||
angleRadians = autoTickAnglesRadians.reduce( | ||
function(currentMax, nextAngle) { | ||
return Math.abs(Math.cos(currentMax)) < Math.abs(Math.cos(nextAngle)) ? currentMax : nextAngle; | ||
} | ||
, autoTickAnglesRadians[0] | ||
); | ||
} | ||
var newAngle = angleRadians * (180 / Math.PI /* to degrees */); | ||
|
||
// any overlap at all - set 30 degrees or 90 degrees | ||
for(i = 0; i < lbbArray.length - 1; i++) { | ||
if(Lib.bBoxIntersect(lbbArray[i], lbbArray[i + 1], pad)) { | ||
autoangle = rotate90 ? 90 : 30; | ||
autoangle = newAngle; | ||
break; | ||
} | ||
} | ||
|
@@ -3807,7 +3827,7 @@ axes.drawLabels = function(gd, ax, opts) { | |
// by rotating 90 degrees, do not attempt to re-fix its label overlaps | ||
// as this can lead to infinite redraw loops! | ||
if(ax.automargin && fullLayout._redrawFromAutoMarginCount && prevAngle === 90) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it is safe to remove this block? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed this because of the first comment at the top of this PR. Have you checked that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I see the PR description. But still I thought that it might be something @alexcjohnson could have a second look. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TBH, this isn't even related to the feature I made. The discussion only started because I changed the check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson What do you suggest here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went back to look at where this block was originally introduced, it was in #4216 back in v1.49.5 (2019). Adapting the first codepen shown there to the latest release and to this PR, neither shows an infinite loop AFAICT, so that's great. But the current PR has some history-dependent behavior that the latest release does not. Here's on the latest release: https://codepen.io/alexcjohnson/pen/YzBovrN - the angle starts 30 degrees, then changes to 90 degrees when we shrink the width, then goes back to 30 degrees when we go back to the original width (this is font-dependent, so it's possible on other machines the specific widths will need to be adjusted) And here's on this branch: https://codepen.io/alexcjohnson/pen/abXgKad - note the angle stays at 90 degrees at the end. It doesn't go back down until you get wide enough to go back to 0 degrees. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed my changes for now, so the old behavior is restored. |
||
autoangle = 90; | ||
autoangle = prevAngle; | ||
seq.push(function() { | ||
positionLabels(tickLabels, prevAngle); | ||
}); | ||
|
Uh oh!
There was an error while loading. Please reload this page.