@@ -2248,13 +2248,32 @@ axes.draw = function(gd, arg, opts) {
2248
2248
2249
2249
var axList = ( ! arg || arg === 'redraw' ) ? axes . listIds ( gd ) : arg ;
2250
2250
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
+
2251
2262
return Lib . syncOrAsync ( axList . map ( function ( axId ) {
2252
2263
return function ( ) {
2253
2264
if ( ! axId ) return ;
2254
2265
2255
2266
var ax = axes . getFromId ( gd , axId ) ;
2267
+
2268
+ if ( ! opts ) opts = { } ;
2269
+ opts . axShifts = axShifts ;
2270
+ opts . overlayingShiftedAx = overlayingShiftedAx ;
2271
+
2256
2272
var axDone = axes . drawOne ( gd , ax , opts ) ;
2257
2273
2274
+ if ( ax . _shiftPusher ) {
2275
+ incrementShift ( ax , ax . _fullDepth || 0 , axShifts , true ) ;
2276
+ }
2258
2277
ax . _r = ax . range . slice ( ) ;
2259
2278
ax . _rl = Lib . simpleMap ( ax . _r , ax . r2l ) ;
2260
2279
@@ -2293,6 +2312,9 @@ axes.draw = function(gd, arg, opts) {
2293
2312
axes . drawOne = function ( gd , ax , opts ) {
2294
2313
opts = opts || { } ;
2295
2314
2315
+ var axShifts = opts . axShifts || { } ;
2316
+ var overlayingShiftedAx = opts . overlayingShiftedAx || [ ] ;
2317
+
2296
2318
var i , sp , plotinfo ;
2297
2319
2298
2320
ax . setScale ( ) ;
@@ -2306,15 +2328,35 @@ axes.drawOne = function(gd, ax, opts) {
2306
2328
// this happens when updating matched group with 'missing' axes
2307
2329
if ( ! mainPlotinfo ) return ;
2308
2330
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
+
2309
2350
var mainAxLayer = mainPlotinfo [ axLetter + 'axislayer' ] ;
2310
2351
var mainLinePosition = ax . _mainLinePosition ;
2352
+ var mainLinePositionShift = mainLinePosition += ax . _shift ;
2311
2353
var mainMirrorPosition = ax . _mainMirrorPosition ;
2312
2354
2313
2355
var vals = ax . _vals = axes . calcTicks ( ax ) ;
2314
2356
2315
2357
// Add a couple of axis properties that should cause us to recreate
2316
2358
// elements. Used in d3 data function.
2317
- var axInfo = [ ax . mirror , mainLinePosition , mainMirrorPosition ] . join ( '_' ) ;
2359
+ var axInfo = [ ax . mirror , mainLinePositionShift , mainMirrorPosition ] . join ( '_' ) ;
2318
2360
for ( i = 0 ; i < vals . length ; i ++ ) {
2319
2361
vals [ i ] . axInfo = axInfo ;
2320
2362
}
@@ -2409,8 +2451,8 @@ axes.drawOne = function(gd, ax, opts) {
2409
2451
var minorTickSigns = axes . getTickSigns ( ax , 'minor' ) ;
2410
2452
2411
2453
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 } ) ;
2414
2456
2415
2457
var mirrorMajorTickPath ;
2416
2458
var mirrorMinorTickPath ;
@@ -2496,7 +2538,7 @@ axes.drawOne = function(gd, ax, opts) {
2496
2538
layer : mainAxLayer ,
2497
2539
plotinfo : plotinfo ,
2498
2540
transFn : transTickLabelFn ,
2499
- labelFns : axes . makeLabelFns ( ax , mainLinePosition )
2541
+ labelFns : axes . makeLabelFns ( ax , mainLinePositionShift )
2500
2542
} ) ;
2501
2543
} ) ;
2502
2544
@@ -2515,28 +2557,34 @@ axes.drawOne = function(gd, ax, opts) {
2515
2557
repositionOnUpdate : true ,
2516
2558
secondary : true ,
2517
2559
transFn : transTickFn ,
2518
- labelFns : axes . makeLabelFns ( ax , mainLinePosition + standoff * majorTickSigns [ 4 ] )
2560
+ labelFns : axes . makeLabelFns ( ax , mainLinePositionShift + standoff * majorTickSigns [ 4 ] )
2519
2561
} ) ;
2520
2562
} ) ;
2521
2563
2522
2564
seq . push ( function ( ) {
2523
- ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePosition ) ;
2565
+ ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePositionShift ) ;
2524
2566
2525
2567
return drawDividers ( gd , ax , {
2526
2568
vals : dividerVals ,
2527
2569
layer : mainAxLayer ,
2528
- path : axes . makeTickPath ( ax , mainLinePosition , majorTickSigns [ 4 ] , { len : ax . _depth } ) ,
2570
+ path : axes . makeTickPath ( ax , mainLinePositionShift , majorTickSigns [ 4 ] , { len : ax . _depth } ) ,
2529
2571
transFn : transTickFn
2530
2572
} ) ;
2531
2573
} ) ;
2532
2574
} else if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2533
2575
seq . push ( function ( ) {
2534
- ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePosition ) ;
2576
+ ax . _depth = majorTickSigns [ 4 ] * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePositionShift ) ;
2535
2577
} ) ;
2536
2578
}
2537
2579
2538
2580
var hasRangeSlider = Registry . getComponentMethod ( 'rangeslider' , 'isVisible' ) ( ax ) ;
2539
2581
2582
+ if ( ! opts . skipTitle &&
2583
+ ! ( hasRangeSlider && ax . side === 'bottom' )
2584
+ ) {
2585
+ seq . push ( function ( ) { return drawTitle ( gd , ax ) ; } ) ;
2586
+ }
2587
+
2540
2588
seq . push ( function ( ) {
2541
2589
var s = ax . side . charAt ( 0 ) ;
2542
2590
var sMirror = OPPOSITE_SIDE [ ax . side ] . charAt ( 0 ) ;
@@ -2548,7 +2596,7 @@ axes.drawOne = function(gd, ax, opts) {
2548
2596
var mirrorPush ;
2549
2597
var rangeSliderPush ;
2550
2598
2551
- if ( ax . automargin || hasRangeSlider ) {
2599
+ if ( ax . automargin || hasRangeSlider || ax . _shiftPusher ) {
2552
2600
if ( ax . type === 'multicategory' ) {
2553
2601
llbbox = getLabelLevelBbox ( 'tick2' ) ;
2554
2602
} else {
@@ -2559,10 +2607,27 @@ axes.drawOne = function(gd, ax, opts) {
2559
2607
}
2560
2608
}
2561
2609
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
+
2562
2627
if ( ax . automargin ) {
2563
2628
push = { x : 0 , y : 0 , r : 0 , l : 0 , t : 0 , b : 0 } ;
2564
2629
var domainIndices = [ 0 , 1 ] ;
2565
-
2630
+ var shift = typeof ax . _shift === 'number' ? ax . _shift : 0 ;
2566
2631
if ( axLetter === 'x' ) {
2567
2632
if ( s === 'b' ) {
2568
2633
push [ s ] = ax . _depth ;
@@ -2585,9 +2650,11 @@ axes.drawOne = function(gd, ax, opts) {
2585
2650
}
2586
2651
} else {
2587
2652
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 ;
2589
2655
} 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 ;
2591
2658
domainIndices . reverse ( ) ;
2592
2659
}
2593
2660
@@ -2626,7 +2693,6 @@ axes.drawOne = function(gd, ax, opts) {
2626
2693
}
2627
2694
}
2628
2695
}
2629
-
2630
2696
if ( hasRangeSlider ) {
2631
2697
rangeSliderPush = Registry . getComponentMethod ( 'rangeslider' , 'autoMarginOpts' ) ( gd , ax ) ;
2632
2698
}
@@ -2641,12 +2707,6 @@ axes.drawOne = function(gd, ax, opts) {
2641
2707
Plots . autoMargin ( gd , rangeSliderAutoMarginID ( ax ) , rangeSliderPush ) ;
2642
2708
} ) ;
2643
2709
2644
- if ( ! opts . skipTitle &&
2645
- ! ( hasRangeSlider && ax . side === 'bottom' )
2646
- ) {
2647
- seq . push ( function ( ) { return drawTitle ( gd , ax ) ; } ) ;
2648
- }
2649
-
2650
2710
return Lib . syncOrAsync ( seq ) ;
2651
2711
} ;
2652
2712
@@ -3779,7 +3839,7 @@ axes.getPxPosition = function(gd, ax) {
3779
3839
} ;
3780
3840
} else if ( axLetter === 'y' ) {
3781
3841
anchorAxis = {
3782
- _offset : gs . l + ( ax . position || 0 ) * gs . w ,
3842
+ _offset : gs . l + ( ax . position || 0 ) * gs . w + ax . _shift ,
3783
3843
_length : 0
3784
3844
} ;
3785
3845
}
@@ -3902,6 +3962,8 @@ function drawTitle(gd, ax) {
3902
3962
}
3903
3963
}
3904
3964
3965
+ ax . _titleStandoff = titleStandoff ;
3966
+
3905
3967
return Titles . draw ( gd , axId + 'title' , {
3906
3968
propContainer : ax ,
3907
3969
propName : ax . _name + '.title.text' ,
@@ -4211,3 +4273,27 @@ function hideCounterAxisInsideTickLabels(ax, opts) {
4211
4273
}
4212
4274
}
4213
4275
}
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