diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 1c1306acf9e..7b4102334fc 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -1932,25 +1932,35 @@ exports.relayout = relayout; // Optimization mostly for large splom traces where // Plots.supplyDefaults can take > 100ms function axRangeSupplyDefaultsByPass(gd, flags, specs) { - var k; + var fullLayout = gd._fullLayout; + var axisMatchGroups = fullLayout._axisMatchGroups || []; if(!flags.axrange) return false; - for(k in flags) { + for(var k in flags) { if(k !== 'axrange' && flags[k]) return false; } - for(k in specs.rangesAltered) { - var axName = Axes.id2name(k); + for(var axId in specs.rangesAltered) { + var axName = Axes.id2name(axId); var axIn = gd.layout[axName]; - var axOut = gd._fullLayout[axName]; + var axOut = fullLayout[axName]; axOut.autorange = axIn.autorange; axOut.range = axIn.range.slice(); axOut.cleanRange(); - } - // no need to consider matching axes here, - // if we keep block in doAutoRangeAndConstraints + for(var i = 0; i < axisMatchGroups.length; i++) { + var group = axisMatchGroups[i]; + if(group[axId]) { + for(var axId2 in group) { + var ax2 = fullLayout[Axes.id2name(axId2)]; + ax2.autorange = axOut.autorange; + ax2.range = axOut.range.slice(); + ax2._input.range = axOut.range.slice(); + } + } + } + } return true; } diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index f4811305d34..53a8e977d61 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -710,7 +710,7 @@ exports.doAutoRangeAndConstraints = function(gd) { enforceAxisConstraints(gd); - // TODO bypass this when matching axes aren't autoranged? + groupLoop: for(var j = 0; j < matchGroups.length; j++) { var group = matchGroups[j]; var rng = null; @@ -718,6 +718,7 @@ exports.doAutoRangeAndConstraints = function(gd) { for(id in group) { ax = Axes.getFromId(gd, id); + if(ax.autorange === false) continue groupLoop; if(rng) { if(rng[0] < rng[1]) { diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index f9b61467601..867679930ad 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -1192,6 +1192,66 @@ describe('Test axes', function() { }); }); + describe('matching axes relayout calls', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function assertRanges(msg, exp) { + exp.forEach(function(expi) { + var axNames = expi[0]; + var rng = expi[1]; + var autorng = expi[2]; + + axNames.forEach(function(n) { + var msgi = n + ' - ' + msg; + expect(gd._fullLayout[n].range).toBeCloseToArray(rng, 1.5, msgi + ' |range'); + expect(gd._fullLayout[n].autorange).toBe(autorng, msgi + ' |autorange'); + }); + }); + } + + it('should auto-range according to all matching trace data', function(done) { + Plotly.plot(gd, [ + { y: [1, 2, 1] }, + { y: [2, 1, 2, 3], xaxis: 'x2' }, + { y: [0, 1], xaxis: 'x3' } + ], { + xaxis: {domain: [0, 0.2]}, + xaxis2: {matches: 'x', domain: [0.3, 0.6]}, + xaxis3: {matches: 'x', domain: [0.65, 1]}, + width: 800, + height: 500, + }) + .then(function() { + assertRanges('base (autoranged)', [ + [['xaxis', 'xaxis2', 'xaxis3'], [-0.245, 3.245], true], + [['yaxis'], [-0.211, 3.211], true] + ]); + }) + .then(function() { return Plotly.relayout(gd, 'xaxis.range', [-1, 4]); }) + .then(function() { + assertRanges('set range', [ + [['xaxis', 'xaxis2', 'xaxis3'], [-1, 4], false], + [['yaxis'], [-0.211, 3.211], true] + ]); + }) + .then(function() { return Plotly.relayout(gd, 'xaxis2.autorange', true); }) + .then(function() { + assertRanges('back to autorange', [ + [['xaxis', 'xaxis2', 'xaxis3'], [-0.245, 3.245], true], + [['yaxis'], [-0.211, 3.211], true] + ]); + }) + .catch(failTest) + .then(done); + }); + }); + describe('categoryorder', function() { var gd;