Skip to content

Commit ad1ac1f

Browse files
committed
adapt getAutoRange and doAutoRange to trace _extremes
- pass gd, to look for _extremes in gd._fullData and eventually in layout container to can expand the axis ranges
1 parent be44366 commit ad1ac1f

File tree

7 files changed

+290
-268
lines changed

7 files changed

+290
-268
lines changed

src/components/rangeslider/calc_autorange.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = function calcAutorange(gd) {
2929

3030
if(opts && opts.visible && opts.autorange && ax._min.length && ax._max.length) {
3131
opts._input.autorange = true;
32-
opts._input.range = opts.range = getAutoRange(ax);
32+
opts._input.range = opts.range = getAutoRange(gd, ax);
3333
}
3434
}
3535
};

src/plot_api/subroutines.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ exports.doAutoRangeAndConstraints = function(gd) {
576576
for(var i = 0; i < axList.length; i++) {
577577
var ax = axList[i];
578578
cleanAxisConstraints(gd, ax);
579-
doAutoRange(ax);
579+
doAutoRange(gd, ax);
580580
}
581581

582582
enforceAxisConstraints(gd);

src/plots/cartesian/autorange.js

+114-46
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var isNumeric = require('fast-isnumeric');
1312

1413
var Lib = require('../../lib');
1514
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
1615

16+
var Registry = require('../../registry');
17+
1718
module.exports = {
1819
getAutoRange: getAutoRange,
1920
makePadFn: makePadFn,
@@ -22,59 +23,77 @@ module.exports = {
2223
findExtremes: findExtremes
2324
};
2425

25-
// Find the autorange for this axis
26-
//
27-
// assumes ax._min and ax._max have already been set by calling axes.expand
28-
// using calcdata from all traces. These are arrays of objects:
29-
// {
30-
// val: calcdata value,
31-
// pad: extra pixels beyond this value,
32-
// extrapad: bool, does this point want 5% extra padding
33-
// }
34-
//
35-
// Returns an array of [min, max]. These are calcdata for log and category axes
36-
// and data for linear and date axes.
37-
//
38-
// TODO: we want to change log to data as well, but it's hard to do this
39-
// maintaining backward compatibility. category will always have to use calcdata
40-
// though, because otherwise values between categories (or outside all categories)
41-
// would be impossible.
42-
function getAutoRange(ax) {
26+
/**
27+
* getAutoRange
28+
*
29+
* Collects all _extremes values corresponding to a given axis
30+
* and computes its auto range.
31+
*
32+
* getAutoRange uses return values from findExtremes where:
33+
*
34+
* {
35+
* val: calcdata value,
36+
* pad: extra pixels beyond this value,
37+
* extrapad: bool, does this point want 5% extra padding
38+
* }
39+
*
40+
* @param {object} gd:
41+
* graph div object with filled in fullData and fullLayout,
42+
* @param {object} ax:
43+
* full axis object
44+
* @return {array}
45+
* an array of [min, max]. These are calcdata for log and category axes
46+
* and data for linear and date axes.
47+
*
48+
* TODO: we want to change log to data as well, but it's hard to do this
49+
* maintaining backward compatibility. category will always have to use calcdata
50+
* though, because otherwise values between categories (or outside all categories)
51+
* would be impossible.
52+
*/
53+
function getAutoRange(gd, ax) {
54+
var i, j;
4355
var newRange = [];
44-
var minmin = ax._min[0].val;
45-
var maxmax = ax._max[0].val;
46-
var mbest = 0;
47-
var axReverse = false;
4856

4957
var getPad = makePadFn(ax);
58+
var minArray = concatExtremes(gd, ax, 'min');
59+
var maxArray = concatExtremes(gd, ax, 'max');
5060

51-
var i, j, minpt, maxpt, minbest, maxbest, dp, dv;
61+
if(minArray.length === 0 || maxArray.length === 0) {
62+
return Lib.simpleMap(ax.range, ax.r2l);
63+
}
5264

53-
for(i = 1; i < ax._min.length; i++) {
65+
var minmin = minArray[0].val;
66+
var maxmax = maxArray[0].val;
67+
68+
for(i = 1; i < minArray.length; i++) {
5469
if(minmin !== maxmax) break;
55-
minmin = Math.min(minmin, ax._min[i].val);
70+
minmin = Math.min(minmin, minArray[i].val);
5671
}
57-
for(i = 1; i < ax._max.length; i++) {
72+
for(i = 1; i < maxArray.length; i++) {
5873
if(minmin !== maxmax) break;
59-
maxmax = Math.max(maxmax, ax._max[i].val);
74+
maxmax = Math.max(maxmax, maxArray[i].val);
6075
}
6176

77+
var axReverse = false;
78+
6279
if(ax.range) {
6380
var rng = Lib.simpleMap(ax.range, ax.r2l);
6481
axReverse = rng[1] < rng[0];
6582
}
66-
6783
// one-time setting to easily reverse the axis
6884
// when plotting from code
6985
if(ax.autorange === 'reversed') {
7086
axReverse = true;
7187
ax.autorange = true;
7288
}
7389

74-
for(i = 0; i < ax._min.length; i++) {
75-
minpt = ax._min[i];
76-
for(j = 0; j < ax._max.length; j++) {
77-
maxpt = ax._max[j];
90+
var mbest = 0;
91+
var minpt, maxpt, minbest, maxbest, dp, dv;
92+
93+
for(i = 0; i < minArray.length; i++) {
94+
minpt = minArray[i];
95+
for(j = 0; j < maxArray.length; j++) {
96+
maxpt = maxArray[j];
7897
dv = maxpt.val - minpt.val;
7998
dp = ax._length - getPad(minpt) - getPad(maxpt);
8099
if(dv > 0 && dp > 0 && dv / dp > mbest) {
@@ -90,11 +109,9 @@ function getAutoRange(ax) {
90109
var upper = minmin + 1;
91110
if(ax.rangemode === 'tozero') {
92111
newRange = minmin < 0 ? [lower, 0] : [0, upper];
93-
}
94-
else if(ax.rangemode === 'nonnegative') {
112+
} else if(ax.rangemode === 'nonnegative') {
95113
newRange = [Math.max(0, lower), Math.max(0, upper)];
96-
}
97-
else {
114+
} else {
98115
newRange = [lower, upper];
99116
}
100117
}
@@ -134,11 +151,9 @@ function getAutoRange(ax) {
134151
if(ax.rangemode === 'tozero') {
135152
if(newRange[0] < 0) {
136153
newRange = [newRange[0], 0];
137-
}
138-
else if(newRange[0] > 0) {
154+
} else if(newRange[0] > 0) {
139155
newRange = [0, newRange[0]];
140-
}
141-
else {
156+
} else {
142157
newRange = [0, 1];
143158
}
144159
}
@@ -174,15 +189,68 @@ function makePadFn(ax) {
174189
return function getPad(pt) { return pt.pad + (pt.extrapad ? extrappad : 0); };
175190
}
176191

177-
function doAutoRange(ax) {
192+
function concatExtremes(gd, ax, ext) {
193+
var i;
194+
var out = [];
195+
196+
var fullData = gd._fullData;
197+
198+
// should be general enough for 3d, polar etc.
199+
200+
for(i = 0; i < fullData.length; i++) {
201+
var trace = fullData[i];
202+
var extremes = trace._extremes;
203+
204+
if(trace.visible === true) {
205+
if(Registry.traceIs(trace, 'cartesian')) {
206+
var axId = ax._id;
207+
if(extremes[axId]) {
208+
out = out.concat(extremes[axId][ext]);
209+
}
210+
} else if(Registry.traceIs(trace, 'polar')) {
211+
if(trace.subplot === ax._subplot) {
212+
out = out.concat(extremes[ax._name][ext]);
213+
}
214+
}
215+
}
216+
}
217+
218+
var fullLayout = gd._fullLayout;
219+
var annotations = fullLayout.annotations;
220+
var shapes = fullLayout.shapes;
221+
222+
if(Array.isArray(annotations)) {
223+
out = out.concat(concatComponentExtremes(annotations, ax, ext));
224+
}
225+
if(Array.isArray(shapes)) {
226+
out = out.concat(concatComponentExtremes(shapes, ax, ext));
227+
}
228+
229+
return out;
230+
}
231+
232+
function concatComponentExtremes(items, ax, ext) {
233+
var out = [];
234+
var axId = ax._id;
235+
var letter = axId.charAt(0);
236+
237+
for(var i = 0; i < items.length; i++) {
238+
var d = items[i];
239+
var extremes = d._extremes;
240+
if(d.visible && d[letter + 'ref'] === axId && extremes[axId]) {
241+
out = out.concat(extremes[axId][ext]);
242+
}
243+
}
244+
return out;
245+
}
246+
247+
function doAutoRange(gd, ax) {
178248
if(!ax._length) ax.setScale();
179249

180-
// TODO do we really need this?
181-
var hasDeps = (ax._min && ax._max && ax._min.length && ax._max.length);
182250
var axIn;
183251

184-
if(ax.autorange && hasDeps) {
185-
ax.range = getAutoRange(ax);
252+
if(ax.autorange) {
253+
ax.range = getAutoRange(gd, ax);
186254

187255
ax._r = ax.range.slice();
188256
ax._rl = Lib.simpleMap(ax._r, ax.r2l);

0 commit comments

Comments
 (0)