@@ -195,14 +195,21 @@ function concatExtremes(gd, ax) {
195
195
var fullLayout = gd . _fullLayout ;
196
196
var minArray = [ ] ;
197
197
var maxArray = [ ] ;
198
+ var i , j , d ;
198
199
199
200
function _concat ( cont , indices ) {
200
- for ( var i = 0 ; i < indices . length ; i ++ ) {
201
+ for ( i = 0 ; i < indices . length ; i ++ ) {
201
202
var item = cont [ indices [ i ] ] ;
202
203
var extremes = ( item . _extremes || { } ) [ axId ] ;
203
204
if ( item . visible === true && extremes ) {
204
- minArray = minArray . concat ( extremes . min ) ;
205
- maxArray = maxArray . concat ( extremes . max ) ;
205
+ for ( j = 0 ; j < extremes . min . length ; j ++ ) {
206
+ d = extremes . min [ j ] ;
207
+ collapseMinArray ( minArray , d . val , d . pad , { extrapad : d . extrapad } ) ;
208
+ }
209
+ for ( j = 0 ; j < extremes . max . length ; j ++ ) {
210
+ d = extremes . max [ j ] ;
211
+ collapseMaxArray ( maxArray , d . val , d . pad , { extrapad : d . extrapad } ) ;
212
+ }
206
213
}
207
214
}
208
215
}
@@ -211,8 +218,6 @@ function concatExtremes(gd, ax) {
211
218
_concat ( fullLayout . annotations || [ ] , ax . _annIndices || [ ] ) ;
212
219
_concat ( fullLayout . shapes || [ ] , ax . _shapeIndices || [ ] ) ;
213
220
214
- // TODO collapse more!
215
-
216
221
return { min : minArray , max : maxArray } ;
217
222
}
218
223
@@ -295,11 +300,9 @@ function findExtremes(ax, data, options) {
295
300
var len = data . length ;
296
301
var extrapad = options . padded || false ;
297
302
var tozero = options . tozero && ( ax . type === 'linear' || ax . type === '-' ) ;
298
- var isLog = ( ax . type === 'log' ) ;
299
-
300
- var i , j , k , v , di , dmin , dmax , ppadiplus , ppadiminus , includeThis , vmin , vmax ;
301
-
303
+ var isLog = ax . type === 'log' ;
302
304
var hasArrayOption = false ;
305
+ var i , v , di , dmin , dmax , ppadiplus , ppadiminus , vmin , vmax ;
303
306
304
307
function makePadAccessor ( item ) {
305
308
if ( Array . isArray ( item ) ) {
@@ -344,6 +347,8 @@ function findExtremes(ax, data, options) {
344
347
len = 2 ;
345
348
}
346
349
350
+ var collapseOpts = { tozero : tozero , extrapad : extrapad } ;
351
+
347
352
function addItem ( i ) {
348
353
di = data [ i ] ;
349
354
if ( ! isNumeric ( di ) ) return ;
@@ -364,48 +369,11 @@ function findExtremes(ax, data, options) {
364
369
dmin = Math . min ( 0 , dmin ) ;
365
370
dmax = Math . max ( 0 , dmax ) ;
366
371
}
367
-
368
- for ( k = 0 ; k < 2 ; k ++ ) {
369
- var newVal = k ? dmax : dmin ;
370
- if ( goodNumber ( newVal ) ) {
371
- var extremes = k ? maxArray : minArray ;
372
- var newPad = k ? ppadiplus : ppadiminus ;
373
- var atLeastAsExtreme = k ? greaterOrEqual : lessOrEqual ;
374
-
375
- includeThis = true ;
376
- /*
377
- * Take items v from ax._min/_max and compare them to the presently active point:
378
- * - Since we don't yet know the relationship between pixels and values
379
- * (that's what we're trying to figure out!) AND we don't yet know how
380
- * many pixels `extrapad` represents (it's going to be 5% of the length,
381
- * but we don't want to have to redo _min and _max just because length changed)
382
- * two point must satisfy three criteria simultaneously for one to supersede the other:
383
- * - at least as extreme a `val`
384
- * - at least as big a `pad`
385
- * - an unpadded point cannot supersede a padded point, but any other combination can
386
- *
387
- * - If the item supersedes the new point, set includethis false
388
- * - If the new pt supersedes the item, delete it from ax._min/_max
389
- */
390
- for ( j = 0 ; j < extremes . length && includeThis ; j ++ ) {
391
- v = extremes [ j ] ;
392
- if ( atLeastAsExtreme ( v . val , newVal ) && v . pad >= newPad && ( v . extrapad || ! extrapad ) ) {
393
- includeThis = false ;
394
- break ;
395
- } else if ( atLeastAsExtreme ( newVal , v . val ) && v . pad <= newPad && ( extrapad || ! v . extrapad ) ) {
396
- extremes . splice ( j , 1 ) ;
397
- j -- ;
398
- }
399
- }
400
- if ( includeThis ) {
401
- var clipAtZero = ( tozero && newVal === 0 ) ;
402
- extremes . push ( {
403
- val : newVal ,
404
- pad : clipAtZero ? 0 : newPad ,
405
- extrapad : clipAtZero ? false : extrapad
406
- } ) ;
407
- }
408
- }
372
+ if ( goodNumber ( dmin ) ) {
373
+ collapseMinArray ( minArray , dmin , ppadiminus , collapseOpts ) ;
374
+ }
375
+ if ( goodNumber ( dmax ) ) {
376
+ collapseMaxArray ( maxArray , dmax , ppadiplus , collapseOpts ) ;
409
377
}
410
378
}
411
379
@@ -419,6 +387,76 @@ function findExtremes(ax, data, options) {
419
387
return { min : minArray , max : maxArray } ;
420
388
}
421
389
390
+ function collapseMinArray ( array , newVal , newPad , opts ) {
391
+ collapseArray ( array , newVal , newPad , opts , lessOrEqual ) ;
392
+ }
393
+
394
+ function collapseMaxArray ( array , newVal , newPad , opts ) {
395
+ collapseArray ( array , newVal , newPad , opts , greaterOrEqual ) ;
396
+ }
397
+
398
+ /**
399
+ * collapseArray
400
+ *
401
+ * Take items v from 'array' compare them to 'newVal', 'newPad'
402
+ *
403
+ * @param {array } array:
404
+ * current set of min or max extremes
405
+ * @param {number } newVal:
406
+ * new value to compare against
407
+ * @param {number } newPad:
408
+ * pad value associated with 'newVal'
409
+ * @param {object } opts:
410
+ * - tozero {boolean}
411
+ * - extrapad {number}
412
+ * @param {function } atLeastAsExtreme:
413
+ * comparison function, use
414
+ * - lessOrEqual for min 'array' and
415
+ * - greaterOrEqual for max 'array'
416
+ *
417
+ * In practice, 'array' is either
418
+ * - 'extremes[ax._id].min' or
419
+ * - 'extremes[ax._id].max
420
+ * found in traces and layout items that affect autorange.
421
+ *
422
+ * Since we don't yet know the relationship between pixels and values
423
+ * (that's what we're trying to figure out!) AND we don't yet know how
424
+ * many pixels `extrapad` represents (it's going to be 5% of the length,
425
+ * but we don't want to have to redo calc just because length changed)
426
+ * two point must satisfy three criteria simultaneously for one to supersede the other:
427
+ * - at least as extreme a `val`
428
+ * - at least as big a `pad`
429
+ * - an unpadded point cannot supersede a padded point, but any other combination can
430
+ *
431
+ * Then:
432
+ * - If the item supersedes the new point, set includeThis false
433
+ * - If the new pt supersedes the item, delete it from 'array'
434
+ */
435
+ function collapseArray ( array , newVal , newPad , opts , atLeastAsExtreme ) {
436
+ var tozero = opts . tozero ;
437
+ var extrapad = opts . extrapad ;
438
+ var includeThis = true ;
439
+
440
+ for ( var j = 0 ; j < array . length && includeThis ; j ++ ) {
441
+ var v = array [ j ] ;
442
+ if ( atLeastAsExtreme ( v . val , newVal ) && v . pad >= newPad && ( v . extrapad || ! extrapad ) ) {
443
+ includeThis = false ;
444
+ break ;
445
+ } else if ( atLeastAsExtreme ( newVal , v . val ) && v . pad <= newPad && ( extrapad || ! v . extrapad ) ) {
446
+ array . splice ( j , 1 ) ;
447
+ j -- ;
448
+ }
449
+ }
450
+ if ( includeThis ) {
451
+ var clipAtZero = ( tozero && newVal === 0 ) ;
452
+ array . push ( {
453
+ val : newVal ,
454
+ pad : clipAtZero ? 0 : newPad ,
455
+ extrapad : clipAtZero ? false : extrapad
456
+ } ) ;
457
+ }
458
+ }
459
+
422
460
// In order to stop overflow errors, don't consider points
423
461
// too close to the limits of js floating point
424
462
function goodNumber ( v ) {
0 commit comments