diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index d81255aa7f2..9804f2d50ff 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -199,6 +199,7 @@ exports.plot = function(gd, data, layout, config) { // draw framework first so that margin-pushing // components can position themselves correctly + var drawFrameworkCalls = 0; function drawFramework() { var basePlotModules = fullLayout._basePlotModules; @@ -242,6 +243,28 @@ exports.plot = function(gd, data, layout, config) { fullLayout._glcanvas .attr('width', fullLayout.width) .attr('height', fullLayout.height); + + var regl = fullLayout._glcanvas.data()[0].regl; + if(regl) { + // Unfortunately, this can happen when relayouting to large + // width/height on some browsers. + if(fullLayout.width !== regl._gl.drawingBufferWidth || + fullLayout.height !== regl._gl.drawingBufferHeight + ) { + var msg = 'WebGL context buffer and canvas dimensions do not match due to browser/WebGL bug.'; + if(drawFrameworkCalls) { + Lib.error(msg); + } else { + Lib.log(msg + ' Clearing graph and plotting again.'); + Plots.cleanPlot([], {}, gd._fullData, fullLayout, gd.calcdata); + Plots.supplyDefaults(gd); + fullLayout = gd._fullLayout; + Plots.doCalcdata(gd); + drawFrameworkCalls++; + return drawFramework(); + } + } + } } return Plots.previousPromises(gd); diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 6f74bd9b922..37781d39c78 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -682,6 +682,59 @@ describe('Test splom interactions:', function() { .catch(failTest) .then(done); }); + + it('@gl should clear graph and replot when canvas and WebGL context dimensions do not match', function(done) { + var fig = Lib.extendDeep({}, require('@mocks/splom_iris.json')); + + function assertDims(msg, w, h) { + var canvas = gd._fullLayout._glcanvas; + expect(canvas.node().width).toBe(w, msg); + expect(canvas.node().height).toBe(h, msg); + + var gl = canvas.data()[0].regl._gl; + expect(gl.drawingBufferWidth).toBe(w, msg); + expect(gl.drawingBufferHeight).toBe(h, msg); + } + + var methods = ['cleanPlot', 'supplyDefaults', 'doCalcdata']; + + methods.forEach(function(m) { spyOn(Plots, m).and.callThrough(); }); + + function assetsFnCall(msg, exp) { + methods.forEach(function(m) { + expect(Plots[m]).toHaveBeenCalledTimes(exp[m], msg); + Plots[m].calls.reset(); + }); + } + + spyOn(Lib, 'log'); + + Plotly.plot(gd, fig).then(function() { + assetsFnCall('base', { + cleanPlot: 1, // called once from inside Plots.supplyDefaults + supplyDefaults: 1, + doCalcdata: 1 + }); + assertDims('base', 600, 500); + expect(Lib.log).toHaveBeenCalledTimes(0); + + spyOn(gd._fullData[0]._module, 'plot').and.callThrough(); + + return Plotly.relayout(gd, {width: 4810, height: 3656}); + }) + .then(function() { + assetsFnCall('after', { + cleanPlot: 4, // 3 three from supplyDefaults, once in drawFramework + supplyDefaults: 3, // 1 from relayout, 1 from automargin, 1 in drawFramework + doCalcdata: 1 // once in drawFramework + }); + assertDims('after', 4810, 3656); + expect(Lib.log) + .toHaveBeenCalledWith('WebGL context buffer and canvas dimensions do not match due to browser/WebGL bug. Clearing graph and plotting again.'); + }) + .catch(failTest) + .then(done); + }); }); describe('Test splom hover:', function() {