@@ -2248,13 +2248,32 @@ axes.draw = function(gd, arg, opts) {
22482248
22492249 var axList = ( ! arg || arg === 'redraw' ) ? axes . listIds ( gd ) : arg ;
22502250
2251+ var fullAxList = axes . list ( gd ) ;
2252+ // Get the list of the overlaying axis for all 'shift' axes
2253+ var overlayingShiftedAx = fullAxList . filter ( function ( ax ) {
2254+ return ax . autoshift ;
2255+ } ) . map ( function ( ax ) {
2256+ return ax . overlaying ;
2257+ } ) ;
2258+
2259+
2260+ var axShifts = { 'false' : { 'left' : 0 , 'right' : 0 } } ;
2261+
22512262 return Lib . syncOrAsync ( axList . map ( function ( axId ) {
22522263 return function ( ) {
22532264 if ( ! axId ) return ;
22542265
22552266 var ax = axes . getFromId ( gd , axId ) ;
2267+
2268+ if ( ! opts ) opts = { } ;
2269+ opts . axShifts = axShifts ;
2270+ opts . overlayingShiftedAx = overlayingShiftedAx ;
2271+
22562272 var axDone = axes . drawOne ( gd , ax , opts ) ;
22572273
2274+ if ( ax . _shiftPusher ) {
2275+ incrementShift ( ax , ax . _fullDepth || 0 , axShifts , true ) ;
2276+ }
22582277 ax . _r = ax . range . slice ( ) ;
22592278 ax . _rl = Lib . simpleMap ( ax . _r , ax . r2l ) ;
22602279
@@ -2293,6 +2312,9 @@ axes.draw = function(gd, arg, opts) {
22932312axes . drawOne = function ( gd , ax , opts ) {
22942313 opts = opts || { } ;
22952314
2315+ var axShifts = opts . axShifts || { } ;
2316+ var overlayingShiftedAx = opts . overlayingShiftedAx || [ ] ;
2317+
22962318 var i , sp , plotinfo ;
22972319
22982320 ax . setScale ( ) ;
@@ -2306,15 +2328,35 @@ axes.drawOne = function(gd, ax, opts) {
23062328 // this happens when updating matched group with 'missing' axes
23072329 if ( ! mainPlotinfo ) return ;
23082330
2331+ ax . _shiftPusher = ax . autoshift ||
2332+ overlayingShiftedAx . indexOf ( ax . _id ) !== - 1 ||
2333+ overlayingShiftedAx . indexOf ( ax . overlaying ) !== - 1 ;
2334+ // An axis is also shifted by 1/2 of its own linewidth and inside tick length if applicable
2335+ // as well as its manually specified `shift` val if we're in the context of `autoshift`
2336+ if ( ax . _shiftPusher & ax . anchor === 'free' ) {
2337+ var selfPush = ( ax . linewidth / 2 || 0 ) ;
2338+ if ( ax . ticks === 'inside' ) {
2339+ selfPush += ax . ticklen ;
2340+ }
2341+ incrementShift ( ax , selfPush , axShifts , true ) ;
2342+ incrementShift ( ax , ( ax . shift || 0 ) , axShifts , false ) ;
2343+ }
2344+
2345+ // Somewhat inelegant way of making sure that the shift value is only updated when the
2346+ // Axes.DrawOne() function is called from the right context. An issue when redrawing the
2347+ // axis as result of using the dragbox, for example.
2348+ if ( opts . skipTitle !== true || ax . _shift === undefined ) ax . _shift = setShiftVal ( ax , axShifts ) ;
2349+
23092350 var mainAxLayer = mainPlotinfo [ axLetter + 'axislayer' ] ;
23102351 var mainLinePosition = ax . _mainLinePosition ;
2352+ var mainLinePositionShift = mainLinePosition += ax . _shift ;
23112353 var mainMirrorPosition = ax . _mainMirrorPosition ;
23122354
23132355 var vals = ax . _vals = axes . calcTicks ( ax ) ;
23142356
23152357 // Add a couple of axis properties that should cause us to recreate
23162358 // elements. Used in d3 data function.
2317- var axInfo = [ ax . mirror , mainLinePosition , mainMirrorPosition ] . join ( '_' ) ;
2359+ var axInfo = [ ax . mirror , mainLinePositionShift , mainMirrorPosition ] . join ( '_' ) ;
23182360 for ( i = 0 ; i < vals . length ; i ++ ) {
23192361 vals [ i ] . axInfo = axInfo ;
23202362 }
@@ -2409,8 +2451,8 @@ axes.drawOne = function(gd, ax, opts) {
24092451 var minorTickSigns = axes . getTickSigns ( ax , 'minor' ) ;
24102452
24112453 if ( ax . ticks || ( ax . minor && ax . minor . ticks ) ) {
2412- var majorTickPath = axes . makeTickPath ( ax , mainLinePosition , majorTickSigns [ 2 ] ) ;
2413- var minorTickPath = axes . makeTickPath ( ax , mainLinePosition , minorTickSigns [ 2 ] , { minor : true } ) ;
2454+ var majorTickPath = axes . makeTickPath ( ax , mainLinePositionShift , majorTickSigns [ 2 ] ) ;
2455+ var minorTickPath = axes . makeTickPath ( ax , mainLinePositionShift , minorTickSigns [ 2 ] , { minor : true } ) ;
24142456
24152457 var mirrorMajorTickPath ;
24162458 var mirrorMinorTickPath ;
@@ -2496,7 +2538,7 @@ axes.drawOne = function(gd, ax, opts) {
24962538 layer : mainAxLayer ,
24972539 plotinfo : plotinfo ,
24982540 transFn : transTickLabelFn ,
2499- labelFns : axes . makeLabelFns ( ax , mainLinePosition )
2541+ labelFns : axes . makeLabelFns ( ax , mainLinePositionShift )
25002542 } ) ;
25012543 } ) ;
25022544
@@ -2515,28 +2557,34 @@ axes.drawOne = function(gd, ax, opts) {
25152557 repositionOnUpdate : true ,
25162558 secondary : true ,
25172559 transFn : transTickFn ,
2518- labelFns : axes . makeLabelFns ( ax , mainLinePosition + standoff * majorTickSigns [ 4 ] )
2560+ labelFns : axes . makeLabelFns ( ax , mainLinePositionShift + standoff * majorTickSigns [ 4 ] )
25192561 } ) ;
25202562 } ) ;
25212563
25222564 seq . push ( function ( ) {
2523- ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePosition ) ;
2565+ ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePositionShift ) ;
25242566
25252567 return drawDividers ( gd , ax , {
25262568 vals : dividerVals ,
25272569 layer : mainAxLayer ,
2528- path : axes . makeTickPath ( ax , mainLinePosition , majorTickSigns [ 4 ] , { len : ax . _depth } ) ,
2570+ path : axes . makeTickPath ( ax , mainLinePositionShift , majorTickSigns [ 4 ] , { len : ax . _depth } ) ,
25292571 transFn : transTickFn
25302572 } ) ;
25312573 } ) ;
25322574 } else if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
25332575 seq . push ( function ( ) {
2534- ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePosition ) ;
2576+ ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePositionShift ) ;
25352577 } ) ;
25362578 }
25372579
25382580 var hasRangeSlider = Registry . getComponentMethod ( 'rangeslider' , 'isVisible' ) ( ax ) ;
25392581
2582+ if ( ! opts . skipTitle &&
2583+ ! ( hasRangeSlider && ax . side === 'bottom' )
2584+ ) {
2585+ seq . push ( function ( ) { return drawTitle ( gd , ax ) ; } ) ;
2586+ }
2587+
25402588 seq . push ( function ( ) {
25412589 var s = ax . side . charAt ( 0 ) ;
25422590 var sMirror = OPPOSITE_SIDE [ ax . side ] . charAt ( 0 ) ;
@@ -2548,7 +2596,7 @@ axes.drawOne = function(gd, ax, opts) {
25482596 var mirrorPush ;
25492597 var rangeSliderPush ;
25502598
2551- if ( ax . automargin || hasRangeSlider ) {
2599+ if ( ax . automargin || hasRangeSlider || ax . _shiftPusher ) {
25522600 if ( ax . type === 'multicategory' ) {
25532601 llbbox = getLabelLevelBbox ( 'tick2' ) ;
25542602 } else {
@@ -2559,10 +2607,27 @@ axes.drawOne = function(gd, ax, opts) {
25592607 }
25602608 }
25612609
2610+ var axDepth = 0 ;
2611+ var titleDepth = 0 ;
2612+ if ( ax . _shiftPusher ) {
2613+ axDepth = Math . max (
2614+ outsideTickLen ,
2615+ llbbox . height > 0 ? ( s === 'l' ? pos - llbbox . left : llbbox . right - pos ) : 0
2616+ ) ;
2617+ if ( ax . title . text !== fullLayout . _dfltTitle [ axLetter ] ) {
2618+ titleDepth = ( ax . _titleStandoff || 0 ) + ( ax . _titleScoot || 0 ) ;
2619+ if ( s === 'l' ) {
2620+ titleDepth += approxTitleDepth ( ax ) ;
2621+ }
2622+ }
2623+
2624+ ax . _fullDepth = Math . max ( axDepth , titleDepth ) ;
2625+ }
2626+
25622627 if ( ax . automargin ) {
25632628 push = { x : 0 , y : 0 , r : 0 , l : 0 , t : 0 , b : 0 } ;
25642629 var domainIndices = [ 0 , 1 ] ;
2565-
2630+ var shift = typeof ax . _shift === 'number' ? ax . _shift : 0 ;
25662631 if ( axLetter === 'x' ) {
25672632 if ( s === 'b' ) {
25682633 push [ s ] = ax . _depth ;
@@ -2585,9 +2650,11 @@ axes.drawOne = function(gd, ax, opts) {
25852650 }
25862651 } else {
25872652 if ( s === 'l' ) {
2588- push [ s ] = ax . _depth = Math . max ( llbbox . height > 0 ? pos - llbbox . left : 0 , outsideTickLen ) ;
2653+ ax . _depth = Math . max ( llbbox . height > 0 ? pos - llbbox . left : 0 , outsideTickLen ) ;
2654+ push [ s ] = ax . _depth - shift ;
25892655 } else {
2590- push [ s ] = ax . _depth = Math . max ( llbbox . height > 0 ? llbbox . right - pos : 0 , outsideTickLen ) ;
2656+ ax . _depth = Math . max ( llbbox . height > 0 ? llbbox . right - pos : 0 , outsideTickLen ) ;
2657+ push [ s ] = ax . _depth + shift ;
25912658 domainIndices . reverse ( ) ;
25922659 }
25932660
@@ -2626,7 +2693,6 @@ axes.drawOne = function(gd, ax, opts) {
26262693 }
26272694 }
26282695 }
2629-
26302696 if ( hasRangeSlider ) {
26312697 rangeSliderPush = Registry . getComponentMethod ( 'rangeslider' , 'autoMarginOpts' ) ( gd , ax ) ;
26322698 }
@@ -2641,12 +2707,6 @@ axes.drawOne = function(gd, ax, opts) {
26412707 Plots . autoMargin ( gd , rangeSliderAutoMarginID ( ax ) , rangeSliderPush ) ;
26422708 } ) ;
26432709
2644- if ( ! opts . skipTitle &&
2645- ! ( hasRangeSlider && ax . side === 'bottom' )
2646- ) {
2647- seq . push ( function ( ) { return drawTitle ( gd , ax ) ; } ) ;
2648- }
2649-
26502710 return Lib . syncOrAsync ( seq ) ;
26512711} ;
26522712
@@ -3779,7 +3839,7 @@ axes.getPxPosition = function(gd, ax) {
37793839 } ;
37803840 } else if ( axLetter === 'y' ) {
37813841 anchorAxis = {
3782- _offset : gs . l + ( ax . position || 0 ) * gs . w ,
3842+ _offset : gs . l + ( ax . position || 0 ) * gs . w + ax . _shift ,
37833843 _length : 0
37843844 } ;
37853845 }
@@ -3902,6 +3962,8 @@ function drawTitle(gd, ax) {
39023962 }
39033963 }
39043964
3965+ ax . _titleStandoff = titleStandoff ;
3966+
39053967 return Titles . draw ( gd , axId + 'title' , {
39063968 propContainer : ax ,
39073969 propName : ax . _name + '.title.text' ,
@@ -4211,3 +4273,27 @@ function hideCounterAxisInsideTickLabels(ax, opts) {
42114273 }
42124274 }
42134275}
4276+
4277+ function incrementShift ( ax , shiftVal , axShifts , normalize ) {
4278+ // Need to set 'overlay' for anchored axis
4279+ var overlay = ( ( ax . anchor !== 'free' ) && ( ( ax . overlaying === undefined ) || ( ax . overlaying === false ) ) ) ? ax . _id : ax . overlaying ;
4280+ var shiftValAdj ;
4281+ if ( normalize ) {
4282+ shiftValAdj = ax . side === 'right' ? shiftVal : - shiftVal ;
4283+ } else {
4284+ shiftValAdj = shiftVal ;
4285+ }
4286+ if ( ! ( overlay in axShifts ) ) {
4287+ axShifts [ overlay ] = { } ;
4288+ }
4289+ if ( ! ( ax . side in axShifts [ overlay ] ) ) {
4290+ axShifts [ overlay ] [ ax . side ] = 0 ;
4291+ }
4292+ axShifts [ overlay ] [ ax . side ] += shiftValAdj ;
4293+ }
4294+
4295+ function setShiftVal ( ax , axShifts ) {
4296+ return ax . autoshift ?
4297+ axShifts [ ax . overlaying ] [ ax . side ] :
4298+ ( ax . shift || 0 ) ;
4299+ }
0 commit comments