@@ -56,7 +56,8 @@ function getAutoRange(gd, ax) {
5656 var i , j ;
5757 var newRange = [ ] ;
5858
59- var getPad = makePadFn ( ax ) ;
59+ var getPadMin = makePadFn ( ax , 0 ) ;
60+ var getPadMax = makePadFn ( ax , 1 ) ;
6061 var extremes = concatExtremes ( gd , ax ) ;
6162 var minArray = extremes . min ;
6263 var maxArray = extremes . max ;
@@ -97,29 +98,16 @@ function getAutoRange(gd, ax) {
9798 // don't allow padding to reduce the data to < 10% of the length
9899 var minSpan = axLen / 10 ;
99100
100- // find axis rangebreaks in [v0,v1] and compute its length in value space
101- var calcBreaksLength = function ( v0 , v1 ) {
102- var lBreaks = 0 ;
103- if ( ax . rangebreaks ) {
104- var rangebreaksOut = ax . locateBreaks ( v0 , v1 ) ;
105- for ( var i = 0 ; i < rangebreaksOut . length ; i ++ ) {
106- var brk = rangebreaksOut [ i ] ;
107- lBreaks += brk . max - brk . min ;
108- }
109- }
110- return lBreaks ;
111- } ;
112-
113101 var mbest = 0 ;
114102 var minpt , maxpt , minbest , maxbest , dp , dv ;
115103
116104 for ( i = 0 ; i < minArray . length ; i ++ ) {
117105 minpt = minArray [ i ] ;
118106 for ( j = 0 ; j < maxArray . length ; j ++ ) {
119107 maxpt = maxArray [ j ] ;
120- dv = maxpt . val - minpt . val - calcBreaksLength ( minpt . val , maxpt . val ) ;
108+ dv = maxpt . val - minpt . val - calcBreaksLength ( ax , minpt . val , maxpt . val ) ;
121109 if ( dv > 0 ) {
122- dp = axLen - getPad ( minpt ) - getPad ( maxpt ) ;
110+ dp = axLen - getPadMin ( minpt ) - getPadMax ( maxpt ) ;
123111 if ( dp > minSpan ) {
124112 if ( dv / dp > mbest ) {
125113 minbest = minpt ;
@@ -137,8 +125,8 @@ function getAutoRange(gd, ax) {
137125 }
138126 }
139127
140- function getMaxPad ( prev , pt ) {
141- return Math . max ( prev , getPad ( pt ) ) ;
128+ function maximumPad ( prev , pt ) {
129+ return Math . max ( prev , getPadMax ( pt ) ) ;
142130 }
143131
144132 if ( minmin === maxmax ) {
@@ -152,7 +140,7 @@ function getAutoRange(gd, ax) {
152140 // 'tozero' pins 0 to the low end, so follow that.
153141 newRange = [ 0 , 1 ] ;
154142 } else {
155- var maxPad = ( minmin > 0 ? maxArray : minArray ) . reduce ( getMaxPad , 0 ) ;
143+ var maxPad = ( minmin > 0 ? maxArray : minArray ) . reduce ( maximumPad , 0 ) ;
156144 // we're pushing a single value away from the edge due to its
157145 // padding, with the other end clamped at zero
158146 // 0.5 means don't push it farther than the center.
@@ -173,7 +161,7 @@ function getAutoRange(gd, ax) {
173161 maxbest = { val : 0 , pad : 0 } ;
174162 }
175163 } else if ( nonNegative ) {
176- if ( minbest . val - mbest * getPad ( minbest ) < 0 ) {
164+ if ( minbest . val - mbest * getPadMin ( minbest ) < 0 ) {
177165 minbest = { val : 0 , pad : 0 } ;
178166 }
179167 if ( maxbest . val <= 0 ) {
@@ -182,12 +170,12 @@ function getAutoRange(gd, ax) {
182170 }
183171
184172 // in case it changed again...
185- mbest = ( maxbest . val - minbest . val - calcBreaksLength ( minpt . val , maxpt . val ) ) /
186- ( axLen - getPad ( minbest ) - getPad ( maxbest ) ) ;
173+ mbest = ( maxbest . val - minbest . val - calcBreaksLength ( ax , minpt . val , maxpt . val ) ) /
174+ ( axLen - getPadMin ( minbest ) - getPadMax ( maxbest ) ) ;
187175
188176 newRange = [
189- minbest . val - mbest * getPad ( minbest ) ,
190- maxbest . val + mbest * getPad ( maxbest )
177+ minbest . val - mbest * getPadMin ( minbest ) ,
178+ maxbest . val + mbest * getPadMax ( maxbest )
191179 ] ;
192180 }
193181
@@ -197,13 +185,41 @@ function getAutoRange(gd, ax) {
197185 return Lib . simpleMap ( newRange , ax . l2r || Number ) ;
198186}
199187
188+ // find axis rangebreaks in [v0,v1] and compute its length in value space
189+ function calcBreaksLength ( ax , v0 , v1 ) {
190+ var lBreaks = 0 ;
191+ if ( ax . rangebreaks ) {
192+ var rangebreaksOut = ax . locateBreaks ( v0 , v1 ) ;
193+ for ( var i = 0 ; i < rangebreaksOut . length ; i ++ ) {
194+ var brk = rangebreaksOut [ i ] ;
195+ lBreaks += brk . max - brk . min ;
196+ }
197+ }
198+ return lBreaks ;
199+ }
200+
200201/*
201202 * calculate the pixel padding for ax._min and ax._max entries with
202203 * optional extrapad as 5% of the total axis length
203204 */
204- function makePadFn ( ax ) {
205+ function makePadFn ( ax , max ) {
205206 // 5% padding for points that specify extrapad: true
206- var extrappad = ax . _length / 20 ;
207+ var extrappad = 0.05 * ax . _length ;
208+
209+ if (
210+ ( ax . ticklabelposition || '' ) . indexOf ( 'inside' ) !== - 1 ||
211+ ( ( ax . _anchorAxis || { } ) . ticklabelposition || '' ) . indexOf ( 'inside' ) !== - 1
212+ ) {
213+ var axReverse = ax . autorange === 'reversed' ;
214+ if ( ! axReverse ) {
215+ var rng = Lib . simpleMap ( ax . range , ax . r2l ) ;
216+ axReverse = rng [ 1 ] < rng [ 0 ] ;
217+ }
218+ if ( axReverse ) max = ! max ;
219+ }
220+
221+ extrappad = adjustPadForInsideLabelsOnAnchorAxis ( extrappad , ax , max ) ;
222+ extrappad = adjustPadForInsideLabelsOnThisAxis ( extrappad , ax , max ) ;
207223
208224 // domain-constrained axes: base extrappad on the unconstrained
209225 // domain so it's consistent as the domain changes
@@ -215,6 +231,96 @@ function makePadFn(ax) {
215231 return function getPad ( pt ) { return pt . pad + ( pt . extrapad ? extrappad : 0 ) ; } ;
216232}
217233
234+ var TEXTPAD = 3 ;
235+
236+ function adjustPadForInsideLabelsOnThisAxis ( extrappad , ax , max ) {
237+ var ticklabelposition = ax . ticklabelposition || '' ;
238+ var has = function ( str ) {
239+ return ticklabelposition . indexOf ( str ) !== - 1 ;
240+ } ;
241+
242+ if ( ! has ( 'inside' ) ) return extrappad ;
243+ var isTop = has ( 'top' ) ;
244+ var isLeft = has ( 'left' ) ;
245+ var isRight = has ( 'right' ) ;
246+ var isBottom = has ( 'bottom' ) ;
247+ var isAligned = isBottom || isLeft || isTop || isRight ;
248+
249+ if (
250+ ( max && ( isLeft || isBottom ) ) ||
251+ ( ! max && ( isRight || isTop ) )
252+ ) {
253+ return extrappad ;
254+ }
255+
256+ // increase padding to make more room for inside tick labels of the axis
257+ var fontSize = ax . tickfont ? ax . tickfont . size : 12 ;
258+ var isX = ax . _id . charAt ( 0 ) === 'x' ;
259+ var morePad = ( isX ? 1.2 : 0.6 ) * fontSize ;
260+
261+ if ( isAligned ) {
262+ morePad *= 2 ;
263+ morePad += ( ax . tickwidth || 0 ) / 2 ;
264+ }
265+
266+ morePad += TEXTPAD ;
267+
268+ extrappad = Math . max ( extrappad , morePad ) ;
269+
270+ return extrappad ;
271+ }
272+
273+ function adjustPadForInsideLabelsOnAnchorAxis ( extrappad , ax , max ) {
274+ var anchorAxis = ( ax . _anchorAxis || { } ) ;
275+ if ( ( anchorAxis . ticklabelposition || '' ) . indexOf ( 'inside' ) !== - 1 ) {
276+ // increase padding to make more room for inside tick labels of the counter axis
277+ if ( (
278+ ! max && (
279+ anchorAxis . side === 'left' ||
280+ anchorAxis . side === 'bottom'
281+ )
282+ ) || (
283+ max && (
284+ anchorAxis . side === 'top' ||
285+ anchorAxis . side === 'right'
286+ )
287+ ) ) {
288+ var isX = ax . _id . charAt ( 0 ) === 'x' ;
289+
290+ var morePad = 0 ;
291+ if ( anchorAxis . _vals ) {
292+ var rad = Lib . deg2rad ( anchorAxis . _tickAngles [ anchorAxis . _id + 'tick' ] || 0 ) ;
293+ var cosA = Math . abs ( Math . cos ( rad ) ) ;
294+ var sinA = Math . abs ( Math . sin ( rad ) ) ;
295+
296+ // use bounding boxes
297+ anchorAxis . _vals . forEach ( function ( t ) {
298+ if ( t . bb ) {
299+ var w = t . bb . width ;
300+ var h = t . bb . height ;
301+
302+ morePad = Math . max ( morePad , isX ?
303+ Math . max ( w * cosA , h * sinA ) :
304+ Math . max ( h * cosA , w * sinA )
305+ ) ;
306+
307+ // add extra pad around label
308+ morePad += 3 ;
309+ }
310+ } ) ;
311+ }
312+
313+ if ( anchorAxis . ticks === 'inside' && anchorAxis . ticklabelposition === 'inside' ) {
314+ morePad += anchorAxis . ticklen || 0 ;
315+ }
316+
317+ extrappad = Math . max ( extrappad , morePad ) ;
318+ }
319+ }
320+
321+ return extrappad ;
322+ }
323+
218324function concatExtremes ( gd , ax , noMatch ) {
219325 var axId = ax . _id ;
220326 var fullData = gd . _fullData ;
0 commit comments