@@ -1643,6 +1643,7 @@ axes.draw = function(gd, arg, opts) {
16431643 * - ax._anchorAxis
16441644 * - ax._subplotsWith
16451645 * - ax._counterDomainMin, ax._counterDomainMax (optionally, from linkSubplots)
1646+ * - ax._tickAngles (on redraw only, old value relinked during supplyDefaults)
16461647 * - ax._mainLinePosition (from lsInner)
16471648 * - ax._mainMirrorPosition
16481649 * - ax._linepositions
@@ -1684,6 +1685,8 @@ axes.drawOne = function(gd, ax, opts) {
16841685 // - stash tickLabels selection, so that drawTitle can use it to scoot title
16851686 ax . _selections = { } ;
16861687 // stash tick angle (including the computed 'auto' values) per tick-label class
1688+ // linkup 'previous' tick angles on redraws
1689+ if ( ax . _tickAngles ) ax . _prevTickAngles = ax . _tickAngles ;
16871690 ax . _tickAngles = { } ;
16881691 // measure [in px] between axis position and outward-most part of bounding box
16891692 // (touching either the tick label or ticks)
@@ -2400,6 +2403,7 @@ axes.drawZeroLine = function(gd, ax, opts) {
24002403 * - {number} tickangle
24012404 * - {object (optional)} _selections
24022405 * - {object} (optional)} _tickAngles
2406+ * - {object} (optional)} _prevTickAngles
24032407 * @param {object } opts
24042408 * - {array of object} vals (calcTicks output-like)
24052409 * - {d3 selection} layer
@@ -2416,13 +2420,14 @@ axes.drawZeroLine = function(gd, ax, opts) {
24162420axes . drawLabels = function ( gd , ax , opts ) {
24172421 opts = opts || { } ;
24182422
2423+ var fullLayout = gd . _fullLayout ;
24192424 var axId = ax . _id ;
24202425 var axLetter = axId . charAt ( 0 ) ;
24212426 var cls = opts . cls || axId + 'tick' ;
24222427 var vals = opts . vals ;
24232428 var labelFns = opts . labelFns ;
24242429 var tickAngle = opts . secondary ? 0 : ax . tickangle ;
2425- var lastAngle = ( ax . _tickAngles || { } ) [ cls ] ;
2430+ var prevAngle = ( ax . _prevTickAngles || { } ) [ cls ] ;
24262431
24272432 var tickLabels = opts . layer . selectAll ( 'g.' + cls )
24282433 . data ( ax . showticklabels ? vals : [ ] , tickDataFn ) ;
@@ -2507,17 +2512,17 @@ axes.drawLabels = function(gd, ax, opts) {
25072512 // do this without waiting, using the last calculated angle to
25082513 // minimize flicker, then do it again when we know all labels are
25092514 // there, putting back the prescribed angle to check for overlaps.
2510- positionLabels ( tickLabels , lastAngle || tickAngle ) ;
2515+ positionLabels ( tickLabels , ( prevAngle + 1 ) ? prevAngle : tickAngle ) ;
25112516
25122517 function allLabelsReady ( ) {
25132518 return labelsReady . length && Promise . all ( labelsReady ) ;
25142519 }
25152520
2521+ var autoangle = null ;
2522+
25162523 function fixLabelOverlaps ( ) {
25172524 positionLabels ( tickLabels , tickAngle ) ;
25182525
2519- var autoangle = null ;
2520-
25212526 // check for auto-angling if x labels overlap
25222527 // don't auto-angle at all for log axes with
25232528 // base and digit format
@@ -2584,19 +2589,36 @@ axes.drawLabels = function(gd, ax, opts) {
25842589 positionLabels ( tickLabels , autoangle ) ;
25852590 }
25862591 }
2587-
2588- if ( ax . _tickAngles ) {
2589- ax . _tickAngles [ cls ] = autoangle === null ?
2590- ( isNumeric ( tickAngle ) ? tickAngle : 0 ) :
2591- autoangle ;
2592- }
25932592 }
25942593
25952594 if ( ax . _selections ) {
25962595 ax . _selections [ cls ] = tickLabels ;
25972596 }
25982597
2599- var done = Lib . syncOrAsync ( [ allLabelsReady , fixLabelOverlaps ] ) ;
2598+ var seq = [ allLabelsReady ] ;
2599+
2600+ // N.B. during auto-margin redraw, if the axis fixed its label overlaps
2601+ // by rotating 90 degrees, do not attempt to re-fix its label overlaps
2602+ // as this can lead to infinite redraw loops!
2603+ if ( fullLayout . _redrawFromAutoMarginCount && prevAngle === 90 ) {
2604+ autoangle = 90 ;
2605+ seq . push ( function ( ) {
2606+ positionLabels ( tickLabels , prevAngle ) ;
2607+ } ) ;
2608+ } else {
2609+ seq . push ( fixLabelOverlaps ) ;
2610+ }
2611+
2612+ // save current tick angle for future redraws
2613+ if ( ax . _tickAngles ) {
2614+ seq . push ( function ( ) {
2615+ ax . _tickAngles [ cls ] = autoangle === null ?
2616+ ( isNumeric ( tickAngle ) ? tickAngle : 0 ) :
2617+ autoangle ;
2618+ } ) ;
2619+ }
2620+
2621+ var done = Lib . syncOrAsync ( seq ) ;
26002622 if ( done && done . then ) gd . _promises . push ( done ) ;
26012623 return done ;
26022624} ;
0 commit comments