@@ -3472,13 +3472,13 @@ axes.drawLabels = function(gd, ax, opts) {
3472
3472
3473
3473
var fullLayout = gd . _fullLayout ;
3474
3474
var axId = ax . _id ;
3475
- var axLetter = axId . charAt ( 0 ) ;
3476
3475
var cls = opts . cls || axId + 'tick' ;
3477
3476
3478
3477
var vals = opts . vals . filter ( function ( d ) { return d . text ; } ) ;
3479
3478
3480
3479
var labelFns = opts . labelFns ;
3481
3480
var tickAngle = opts . secondary ? 0 : ax . tickangle ;
3481
+
3482
3482
var prevAngle = ( ax . _prevTickAngles || { } ) [ cls ] ;
3483
3483
3484
3484
var tickLabels = opts . layer . selectAll ( 'g.' + cls )
@@ -3719,21 +3719,22 @@ axes.drawLabels = function(gd, ax, opts) {
3719
3719
// check for auto-angling if x labels overlap
3720
3720
// don't auto-angle at all for log axes with
3721
3721
// base and digit format
3722
- if ( vals . length && axLetter === 'x' && ! isNumeric ( tickAngle ) &&
3722
+ if ( vals . length && ax . autotickangles &&
3723
3723
( ax . type !== 'log' || String ( ax . dtick ) . charAt ( 0 ) !== 'D' )
3724
3724
) {
3725
- autoangle = 0 ;
3725
+ autoangle = ax . autotickangles [ 0 ] ;
3726
3726
3727
3727
var maxFontSize = 0 ;
3728
3728
var lbbArray = [ ] ;
3729
3729
var i ;
3730
-
3730
+ var maxLines = 1 ;
3731
3731
tickLabels . each ( function ( d ) {
3732
3732
maxFontSize = Math . max ( maxFontSize , d . fontSize ) ;
3733
3733
3734
3734
var x = ax . l2p ( d . x ) ;
3735
3735
var thisLabel = selectTickLabel ( this ) ;
3736
3736
var bb = Drawing . bBox ( thisLabel . node ( ) ) ;
3737
+ maxLines = Math . max ( maxLines , svgTextUtils . lineCount ( thisLabel ) ) ;
3737
3738
3738
3739
lbbArray . push ( {
3739
3740
// ignore about y, just deal with x overlaps
@@ -3780,12 +3781,31 @@ axes.drawLabels = function(gd, ax, opts) {
3780
3781
var pad = ! isAligned ? 0 :
3781
3782
( ax . tickwidth || 0 ) + 2 * TEXTPAD ;
3782
3783
3783
- var rotate90 = ( tickSpacing < maxFontSize * 2.5 ) || ax . type === 'multicategory' || ax . _name === 'realaxis' ;
3784
+ // autotickangles
3785
+ var adjacent = tickSpacing ;
3786
+ var opposite = maxFontSize * 1.25 * maxLines ;
3787
+ var hypotenuse = Math . sqrt ( Math . pow ( adjacent , 2 ) + Math . pow ( opposite , 2 ) ) ;
3788
+ var maxCos = adjacent / hypotenuse ;
3789
+ var autoTickAnglesRadians = ax . autotickangles . map (
3790
+ function ( degrees ) { return degrees * Math . PI / 180 ; }
3791
+ ) ;
3792
+ var angleRadians = autoTickAnglesRadians . find (
3793
+ function ( angle ) { return Math . abs ( Math . cos ( angle ) ) <= maxCos ; }
3794
+ ) ;
3795
+ if ( angleRadians === undefined ) {
3796
+ // no angle with smaller cosine than maxCos, just pick the angle with smallest cosine
3797
+ angleRadians = autoTickAnglesRadians . reduce (
3798
+ function ( currentMax , nextAngle ) {
3799
+ return Math . abs ( Math . cos ( currentMax ) ) < Math . abs ( Math . cos ( nextAngle ) ) ? currentMax : nextAngle ;
3800
+ }
3801
+ , autoTickAnglesRadians [ 0 ]
3802
+ ) ;
3803
+ }
3804
+ var newAngle = angleRadians * ( 180 / Math . PI /* to degrees */ ) ;
3784
3805
3785
- // any overlap at all - set 30 degrees or 90 degrees
3786
3806
for ( i = 0 ; i < lbbArray . length - 1 ; i ++ ) {
3787
3807
if ( Lib . bBoxIntersect ( lbbArray [ i ] , lbbArray [ i + 1 ] , pad ) ) {
3788
- autoangle = rotate90 ? 90 : 30 ;
3808
+ autoangle = newAngle ;
3789
3809
break ;
3790
3810
}
3791
3811
}
@@ -3807,7 +3827,7 @@ axes.drawLabels = function(gd, ax, opts) {
3807
3827
// by rotating 90 degrees, do not attempt to re-fix its label overlaps
3808
3828
// as this can lead to infinite redraw loops!
3809
3829
if ( ax . automargin && fullLayout . _redrawFromAutoMarginCount && prevAngle === 90 ) {
3810
- autoangle = 90 ;
3830
+ autoangle = prevAngle ;
3811
3831
seq . push ( function ( ) {
3812
3832
positionLabels ( tickLabels , prevAngle ) ;
3813
3833
} ) ;
0 commit comments