diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 5cfc30ce8cc..0e21d292802 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -346,6 +346,7 @@ function handleCamera3d(gd, ev) { var sceneId = sceneIds[i]; var camera = sceneId + '.camera'; var aspectratio = sceneId + '.aspectratio'; + var aspectmode = sceneId + '.aspectmode'; var scene = fullLayout[sceneId]._scene; var didUpdate; @@ -365,6 +366,7 @@ function handleCamera3d(gd, ev) { aobj[aspectratio + '.x'] = scene.viewInitial.aspectratio.x; aobj[aspectratio + '.y'] = scene.viewInitial.aspectratio.y; aobj[aspectratio + '.z'] = scene.viewInitial.aspectratio.z; + aobj[aspectmode] = scene.viewInitial.aspectmode; } } diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index 5efb94d4bc4..f57e273ddf9 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -155,7 +155,7 @@ proto.tryCreatePlot = function() { 'webgl setup failed possibly due to', isMobile ? 'disabling' : 'enabling', 'preserveDrawingBuffer config.', - 'The device may not be supported by isMobile module!', + 'The device may not be supported by is-mobile module!', 'Inverting preserveDrawingBuffer option in second attempt to create webgl scene.' ].join(' ')); isMobile = opts.glOptions.preserveDrawingBuffer = !opts.glOptions.preserveDrawingBuffer; @@ -219,6 +219,12 @@ proto.initializeGLPlot = function() { if(scene.isAspectChanged(layout)) { // scene updates update[scene.id + '.aspectratio'] = scene.glplot.getAspectratio(); + + if(layout[scene.id].aspectmode !== 'manual') { + scene.fullSceneLayout.aspectmode = + layout[scene.id].aspectmode = + update[scene.id + '.aspectmode'] = 'manual'; + } } return update; @@ -246,7 +252,6 @@ proto.initializeGLPlot = function() { y: s * o.y, z: s * o.z }); - scene.fullSceneLayout.aspectmode = layout[scene.id].aspectmode = 'manual'; } relayoutCallback(scene); @@ -778,7 +783,7 @@ proto.plot = function(sceneData, fullLayout, layout) { */ scene.glplot.setAspectratio(fullSceneLayout.aspectratio); - // save 'initial' camera view settings for modebar button + // save 'initial' aspectratio & aspectmode view settings for modebar buttons if(!scene.viewInitial.aspectratio) { scene.viewInitial.aspectratio = { x: fullSceneLayout.aspectratio.x, @@ -786,6 +791,9 @@ proto.plot = function(sceneData, fullLayout, layout) { z: fullSceneLayout.aspectratio.z }; } + if(!scene.viewInitial.aspectmode) { + scene.viewInitial.aspectmode = fullSceneLayout.aspectmode; + } // Update frame position for multi plots var domain = fullSceneLayout.domain || null; diff --git a/test/jasmine/tests/gl3d_plot_interact_test.js b/test/jasmine/tests/gl3d_plot_interact_test.js index 8b611d706ef..b77003fb8d1 100644 --- a/test/jasmine/tests/gl3d_plot_interact_test.js +++ b/test/jasmine/tests/gl3d_plot_interact_test.js @@ -575,13 +575,19 @@ describe('Test gl3d modebar handlers - perspective case', function() { buttonDefault.click(); }); - it('@gl button resetCameraDefault3d should reset to initial aspectratios', function(done) { + it('@gl button resetCameraDefault3d should reset to initial aspectmode & aspectratios', function(done) { var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectmode).toEqual('auto'); + expect(gd._fullLayout.scene2._scene.viewInitial.aspectmode).toEqual('manual'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectratio).toEqual({ x: 1, y: 1, z: 1 }); expect(gd._fullLayout.scene2._scene.viewInitial.aspectratio).toEqual({ x: 3, y: 2, z: 1 }); gd.once('plotly_relayout', function() { + expect(gd._fullLayout.scene._scene.fullSceneLayout.aspectmode).toBe('auto'); + expect(gd._fullLayout.scene2._scene.fullSceneLayout.aspectmode).toBe('manual'); + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().x).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().y).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().z).toBeCloseTo(1); @@ -595,9 +601,12 @@ describe('Test gl3d modebar handlers - perspective case', function() { buttonDefault.click(); }); - it('@gl button resetCameraLastSave3d should reset to initial aspectratios', function(done) { + it('@gl button resetCameraLastSave3d should reset to initial aspectmode & aspectratios', function(done) { var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectmode).toEqual('auto'); + expect(gd._fullLayout.scene2._scene.viewInitial.aspectmode).toEqual('manual'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectratio).toEqual({ x: 1, y: 1, z: 1 }); expect(gd._fullLayout.scene2._scene.viewInitial.aspectratio).toEqual({ x: 3, y: 2, z: 1 }); @@ -771,13 +780,19 @@ describe('Test gl3d modebar handlers - orthographic case', function() { buttonDefault.click(); }); - it('@gl button resetCameraDefault3d should reset to initial aspectratios', function(done) { + it('@gl button resetCameraDefault3d should reset to initial aspectmode & aspectratios', function(done) { var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectmode).toEqual('auto'); + expect(gd._fullLayout.scene2._scene.viewInitial.aspectmode).toEqual('manual'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectratio).toEqual({ x: 1, y: 1, z: 1 }); expect(gd._fullLayout.scene2._scene.viewInitial.aspectratio).toEqual({ x: 3, y: 2, z: 1 }); gd.once('plotly_relayout', function() { + expect(gd._fullLayout.scene._scene.aspectmode).toEqual(undefined); + expect(gd._fullLayout.scene2._scene.aspectmode).toEqual(undefined); + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().x).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().y).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().z).toBeCloseTo(1); @@ -791,13 +806,19 @@ describe('Test gl3d modebar handlers - orthographic case', function() { buttonDefault.click(); }); - it('@gl button resetCameraLastSave3d should reset to initial aspectratios', function(done) { + it('@gl button resetCameraLastSave3d should reset to initial aspectmode & aspectratios', function(done) { var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectmode).toEqual('auto'); + expect(gd._fullLayout.scene2._scene.viewInitial.aspectmode).toEqual('manual'); + expect(gd._fullLayout.scene._scene.viewInitial.aspectratio).toEqual({ x: 1, y: 1, z: 1 }); expect(gd._fullLayout.scene2._scene.viewInitial.aspectratio).toEqual({ x: 3, y: 2, z: 1 }); gd.once('plotly_relayout', function() { + expect(gd._fullLayout.scene._scene.fullSceneLayout.aspectmode).toBe('auto'); + expect(gd._fullLayout.scene2._scene.fullSceneLayout.aspectmode).toBe('manual'); + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().x).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().y).toBeCloseTo(1); expect(gd._fullLayout.scene._scene.glplot.getAspectratio().z).toBeCloseTo(1); @@ -1175,7 +1196,7 @@ describe('Test gl3d drag and wheel interactions', function() { .then(done); }); - it('@gl should update the scene aspectratio when zooming with scroll wheel i.e. orthographic case', function(done) { + it('@gl should update the scene aspectmode & aspectratio when zooming with scroll wheel i.e. orthographic case', function(done) { var sceneLayout, sceneLayout2, sceneTarget, sceneTarget2; var mock = { @@ -1192,8 +1213,13 @@ describe('Test gl3d drag and wheel interactions', function() { var aspectratio; var relayoutEvent; var relayoutCnt = 0; + var modeBar; Plotly.plot(gd, mock) + .then(delay(20)) + .then(function() { + modeBar = gd._fullLayout._modeBar; + }) .then(function() { gd.on('plotly_relayout', function(e) { relayoutCnt++; @@ -1218,6 +1244,9 @@ describe('Test gl3d drag and wheel interactions', function() { expect(aspectratio.x).toBeCloseTo(0.909, 3, 'aspectratio.x'); expect(aspectratio.y).toBeCloseTo(0.909, 3, 'aspectratio.y'); expect(aspectratio.z).toBeCloseTo(0.909, 3, 'aspectratio.z'); + + expect(relayoutEvent['scene.aspectmode']).toBe('manual'); + expect(gd._fullLayout.scene._scene.fullSceneLayout.aspectmode).toBe('manual'); }) .then(function() { return scroll(sceneTarget2); @@ -1229,6 +1258,25 @@ describe('Test gl3d drag and wheel interactions', function() { expect(aspectratio.x).toBeCloseTo(2.727, 3, 'aspectratio.x'); expect(aspectratio.y).toBeCloseTo(1.818, 3, 'aspectratio.y'); expect(aspectratio.z).toBeCloseTo(0.909, 3, 'aspectratio.z'); + + expect(relayoutEvent['scene2.aspectmode']).toBe('manual'); + expect(gd._fullLayout.scene2._scene.fullSceneLayout.aspectmode).toBe('manual'); + }) + .then(function() { + var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d'); + + buttonDefault.click(); + }) + .then(function() { + expect(gd._fullLayout.scene._scene.aspectmode).toEqual(undefined); + expect(gd._fullLayout.scene2._scene.aspectmode).toEqual(undefined); + + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().x).toBeCloseTo(1); + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().y).toBeCloseTo(1); + expect(gd._fullLayout.scene._scene.glplot.getAspectratio().z).toBeCloseTo(1); + expect(gd._fullLayout.scene2._scene.glplot.getAspectratio().x).toBeCloseTo(3); + expect(gd._fullLayout.scene2._scene.glplot.getAspectratio().y).toBeCloseTo(2); + expect(gd._fullLayout.scene2._scene.glplot.getAspectratio().z).toBeCloseTo(1); }) .catch(failTest) .then(done); @@ -1279,6 +1327,7 @@ describe('Test gl3d drag and wheel interactions', function() { Object.keys(relayoutEvent).sort().forEach(function(key) { expect(Object.keys(events[0])).toContain(key); expect(key).not.toBe('scene.aspectratio'); + expect(key).not.toBe('scene.aspectmode'); }); }) .catch(failTest) @@ -1329,6 +1378,7 @@ describe('Test gl3d drag and wheel interactions', function() { Object.keys(relayoutEvent).sort().forEach(function(key) { expect(Object.keys(events[0])).toContain(key); expect(key).not.toBe('scene.aspectratio'); + expect(key).not.toBe('scene.aspectmode'); }); }) .catch(failTest) @@ -1456,6 +1506,9 @@ describe('Test gl3d drag and wheel interactions', function() { expect(aspectratio.x).toBeCloseTo(0.816, 3, 'aspectratio.x'); expect(aspectratio.y).toBeCloseTo(0.725, 3, 'aspectratio.y'); expect(aspectratio.z).toBeCloseTo(1.269, 3, 'aspectratio.z'); + + expect(relayoutEvent['scene.aspectmode']).toBe('manual'); + expect(gd._fullLayout.scene._scene.fullSceneLayout.aspectmode).toBe('manual'); }) .then(function() { // select a point