Skip to content

Commit 11f4a0e

Browse files
committed
Merge branch 'master' into misc-perf
2 parents ea883e6 + 51a479b commit 11f4a0e

24 files changed

+817
-221
lines changed

src/constants/alignment.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright 2012-2017, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
// fraction of some size to get to a named position
12+
module.exports = {
13+
// from bottom left: this is the origin of our paper-reference
14+
// positioning system
15+
FROM_BL: {
16+
left: 0,
17+
center: 0.5,
18+
right: 1,
19+
bottom: 0,
20+
middle: 0.5,
21+
top: 1
22+
},
23+
// from top left: this is the screen pixel positioning origin
24+
FROM_TL: {
25+
left: 0,
26+
center: 0.5,
27+
right: 1,
28+
bottom: 1,
29+
middle: 0.5,
30+
top: 0
31+
}
32+
};

src/lib/coerce.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ exports.valObjects = {
4444
if(opts.coerceNumber) v = +v;
4545
if(opts.values.indexOf(v) === -1) propOut.set(dflt);
4646
else propOut.set(v);
47+
},
48+
validateFunction: function(v, opts) {
49+
if(opts.coerceNumber) v = +v;
50+
51+
var values = opts.values;
52+
for(var i = 0; i < values.length; i++) {
53+
var k = String(values[i]);
54+
55+
if((k.charAt(0) === '/' && k.charAt(k.length - 1) === '/')) {
56+
var regex = new RegExp(k.substr(1, k.length - 2));
57+
if(regex.test(v)) return true;
58+
} else if(v === values[i]) return true;
59+
}
60+
return false;
4761
}
4862
},
4963
'boolean': {

src/plot_api/plot_api.js

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ var manageArrays = require('./manage_arrays');
3232
var helpers = require('./helpers');
3333
var subroutines = require('./subroutines');
3434
var cartesianConstants = require('../plots/cartesian/constants');
35-
var enforceAxisConstraints = require('../plots/cartesian/constraints');
35+
var axisConstraints = require('../plots/cartesian/constraints');
36+
var enforceAxisConstraints = axisConstraints.enforce;
37+
var cleanAxisConstraints = axisConstraints.clean;
3638
var axisIds = require('../plots/cartesian/axis_ids');
3739

3840

@@ -218,19 +220,19 @@ Plotly.plot = function(gd, data, layout, config) {
218220

219221
// in case the margins changed, draw margin pushers again
220222
function marginPushersAgain() {
221-
var seq = JSON.stringify(fullLayout._size) === oldmargins ?
222-
[] :
223-
[marginPushers, subroutines.layoutStyles];
223+
if(JSON.stringify(fullLayout._size) === oldmargins) return;
224224

225-
// re-initialize cartesian interaction,
226-
// which are sometimes cleared during marginPushers
227-
seq = seq.concat(initInteractions);
228-
229-
return Lib.syncOrAsync(seq, gd);
225+
return Lib.syncOrAsync([
226+
marginPushers,
227+
subroutines.layoutStyles
228+
], gd);
230229
}
231230

232231
function positionAndAutorange() {
233-
if(!recalc) return;
232+
if(!recalc) {
233+
enforceAxisConstraints(gd);
234+
return;
235+
}
234236

235237
var subplots = Plots.getSubplotIds(fullLayout, 'cartesian'),
236238
modules = fullLayout._modules;
@@ -268,7 +270,10 @@ Plotly.plot = function(gd, data, layout, config) {
268270

269271
var axList = Plotly.Axes.list(gd, '', true);
270272
for(var i = 0; i < axList.length; i++) {
271-
Plotly.Axes.doAutoRange(axList[i]);
273+
var ax = axList[i];
274+
cleanAxisConstraints(gd, ax);
275+
276+
Plotly.Axes.doAutoRange(ax);
272277
}
273278

274279
enforceAxisConstraints(gd);
@@ -363,11 +368,13 @@ Plotly.plot = function(gd, data, layout, config) {
363368
drawFramework,
364369
marginPushers,
365370
marginPushersAgain,
371+
initInteractions,
366372
positionAndAutorange,
367373
subroutines.layoutStyles,
368374
drawAxes,
369375
drawData,
370376
finalDraw,
377+
initInteractions,
371378
Plots.rehover
372379
];
373380

@@ -1915,10 +1922,12 @@ function _relayout(gd, aobj) {
19151922
// we're editing the (auto)range of, so we can tell the others constrained
19161923
// to scale with them that it's OK for them to shrink
19171924
var rangesAltered = {};
1925+
var axId;
19181926

19191927
function recordAlteredAxis(pleafPlus) {
19201928
var axId = axisIds.name2id(pleafPlus.split('.')[0]);
19211929
rangesAltered[axId] = 1;
1930+
return axId;
19221931
}
19231932

19241933
// alter gd.layout
@@ -1961,11 +1970,25 @@ function _relayout(gd, aobj) {
19611970
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) {
19621971
doextra(ptrunk + '.autorange', false);
19631972
recordAlteredAxis(pleafPlus);
1973+
Lib.nestedProperty(fullLayout, ptrunk + '._inputRange').set(null);
19641974
}
19651975
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.autorange$/)) {
19661976
doextra([ptrunk + '.range[0]', ptrunk + '.range[1]'],
19671977
undefined);
19681978
recordAlteredAxis(pleafPlus);
1979+
Lib.nestedProperty(fullLayout, ptrunk + '._inputRange').set(null);
1980+
var axFull = Lib.nestedProperty(fullLayout, ptrunk).get();
1981+
if(axFull._inputDomain) {
1982+
// if we're autoranging and this axis has a constrained domain,
1983+
// reset it so we don't get locked into a shrunken size
1984+
axFull._input.domain = axFull._inputDomain.slice();
1985+
}
1986+
}
1987+
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.domain(\[[0|1]\])?$/)) {
1988+
Lib.nestedProperty(fullLayout, ptrunk + '._inputDomain').set(null);
1989+
}
1990+
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.constrain.*$/)) {
1991+
flags.docalc = true;
19691992
}
19701993
else if(pleafPlus.match(/^aspectratio\.[xyz]$/)) {
19711994
doextra(proot + '.aspectmode', 'manual');
@@ -2045,6 +2068,7 @@ function _relayout(gd, aobj) {
20452068
// will not make sense, so autorange it.
20462069
doextra(ptrunk + '.autorange', true);
20472070
}
2071+
Lib.nestedProperty(fullLayout, ptrunk + '._inputRange').set(null);
20482072
}
20492073
else if(pleaf.match(cartesianConstants.AX_NAME_PATTERN)) {
20502074
var fullProp = Lib.nestedProperty(fullLayout, ai).get(),
@@ -2191,7 +2215,7 @@ function _relayout(gd, aobj) {
21912215

21922216
// figure out if we need to recalculate axis constraints
21932217
var constraints = fullLayout._axisConstraintGroups;
2194-
for(var axId in rangesAltered) {
2218+
for(axId in rangesAltered) {
21952219
for(i = 0; i < constraints.length; i++) {
21962220
var group = constraints[i];
21972221
if(group[axId]) {

src/plot_api/validate.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ function crawl(objIn, objOut, schema, list, base, path) {
219219
else if(!Lib.validate(valIn, nestedSchema)) {
220220
list.push(format('value', base, p, valIn));
221221
}
222+
else if(nestedSchema.valType === 'enumerated' &&
223+
((nestedSchema.coerceNumber && valIn !== +valOut) || valIn !== valOut)
224+
) {
225+
list.push(format('dynamic', base, p, valIn, valOut));
226+
}
222227
}
223228

224229
return list;
@@ -267,6 +272,16 @@ var code2msgFunc = {
267272

268273
return inBase(base) + target + ' ' + astr + ' did not get coerced';
269274
},
275+
dynamic: function(base, astr, valIn, valOut) {
276+
return [
277+
inBase(base) + 'key',
278+
astr,
279+
'(set to \'' + valIn + '\')',
280+
'got reset to',
281+
'\'' + valOut + '\'',
282+
'during defaults.'
283+
].join(' ');
284+
},
270285
invisible: function(base) {
271286
return 'Trace ' + base[1] + ' got defaulted to be not visible';
272287
},
@@ -284,7 +299,7 @@ function inBase(base) {
284299
return 'In ' + base + ', ';
285300
}
286301

287-
function format(code, base, path, valIn) {
302+
function format(code, base, path, valIn, valOut) {
288303
path = path || '';
289304

290305
var container, trace;
@@ -301,8 +316,8 @@ function format(code, base, path, valIn) {
301316
trace = null;
302317
}
303318

304-
var astr = convertPathToAttributeString(path),
305-
msg = code2msgFunc[code](base, astr, valIn);
319+
var astr = convertPathToAttributeString(path);
320+
var msg = code2msgFunc[code](base, astr, valIn, valOut);
306321

307322
// log to console if logger config option is enabled
308323
Lib.log(msg);

src/plots/cartesian/axes.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,13 @@ axes.expand = function(ax, data, options) {
455455
i, j, v, di, dmin, dmax,
456456
ppadiplus, ppadiminus, includeThis, vmin, vmax;
457457

458+
// domain-constrained axes: base extrappad on the unconstrained
459+
// domain so it's consistent as the domain changes
460+
if(extrappad && (ax.constrain === 'domain') && ax._inputDomain) {
461+
extrappad *= (ax._inputDomain[1] - ax._inputDomain[0]) /
462+
(ax.domain[1] - ax.domain[0]);
463+
}
464+
458465
function getPad(item) {
459466
if(Array.isArray(item)) {
460467
return function(i) { return Math.max(Number(item[i]||0), 0); };

src/plots/cartesian/constraint_defaults.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,25 @@ var id2name = require('./axis_ids').id2name;
1515

1616
module.exports = function handleConstraintDefaults(containerIn, containerOut, coerce, allAxisIds, layoutOut) {
1717
var constraintGroups = layoutOut._axisConstraintGroups;
18+
var thisID = containerOut._id;
19+
var letter = thisID.charAt(0);
1820

19-
if(containerOut.fixedrange || !containerIn.scaleanchor) return;
21+
if(containerOut.fixedrange) return;
2022

21-
var constraintOpts = getConstraintOpts(constraintGroups, containerOut._id, allAxisIds, layoutOut);
23+
// coerce the constraint mechanics even if this axis has no scaleanchor
24+
// because it may be the anchor of another axis.
25+
coerce('constrain');
26+
Lib.coerce(containerIn, containerOut, {
27+
constraintoward: {
28+
valType: 'enumerated',
29+
values: letter === 'x' ? ['left', 'center', 'right'] : ['bottom', 'middle', 'top'],
30+
dflt: letter === 'x' ? 'center' : 'middle'
31+
}
32+
}, 'constraintoward');
33+
34+
if(!containerIn.scaleanchor) return;
35+
36+
var constraintOpts = getConstraintOpts(constraintGroups, thisID, allAxisIds, layoutOut);
2237

2338
var scaleanchor = Lib.coerce(containerIn, containerOut, {
2439
scaleanchor: {
@@ -37,7 +52,7 @@ module.exports = function handleConstraintDefaults(containerIn, containerOut, co
3752
if(!scaleratio) scaleratio = containerOut.scaleratio = 1;
3853

3954
updateConstraintGroups(constraintGroups, constraintOpts.thisGroup,
40-
containerOut._id, scaleanchor, scaleratio);
55+
thisID, scaleanchor, scaleratio);
4156
}
4257
else if(allAxisIds.indexOf(containerIn.scaleanchor) !== -1) {
4358
Lib.warn('ignored ' + containerOut._name + '.scaleanchor: "' +

0 commit comments

Comments
 (0)