Skip to content

Keep orthographic zoom scales in fullLayout #4292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 25, 2019
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"gl-mat4": "^1.2.0",
"gl-mesh3d": "^2.1.1",
"gl-plot2d": "^1.4.2",
"gl-plot3d": "^2.2.2",
"gl-plot3d": "git://github.com/gl-vis/gl-plot3d.git#83e9c9406976e5ee92bf1f1851e4366e516c06f7",
"gl-pointcloud2d": "^1.0.2",
"gl-scatter3d": "^1.2.2",
"gl-select-box": "^1.0.3",
Expand Down
3 changes: 1 addition & 2 deletions src/plot_api/subroutines.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,7 @@ exports.doCamera = function(gd) {
var sceneLayout = fullLayout[sceneIds[i]];
var scene = sceneLayout._scene;

var cameraData = sceneLayout.camera;
scene.setCamera(cameraData);
scene.setViewport(sceneLayout);
}
};

Expand Down
87 changes: 69 additions & 18 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

'use strict';

var createCamera = require('gl-plot3d').createCamera;
var createPlot = require('gl-plot3d').createScene;
var glPlot3d = require('gl-plot3d');
var createCamera = glPlot3d.createCamera;
var createPlot = glPlot3d.createScene;

var getContext = require('webgl-context');
var passiveSupported = require('has-passive-events');

Expand Down Expand Up @@ -260,21 +262,45 @@ function initializeGLPlot(scene, pixelRatio, canvas, gl) {

var gd = scene.graphDiv;

var makeUpdate = function() {
var update = {};

// camera updates
update[scene.id + '.camera'] = getLayoutCamera(scene.camera);

// scene updates
update[scene.id + '.aspectratio'] = scene.glplot.getAspectratio();
Copy link
Contributor

@etpinard etpinard Oct 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only part of the event data on scenes with orthographic projections

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... in other words, the event data should have the minimal set of keys that changed during the (here: scroll) interaction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in b92230a.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in d825c0e.


return update;
};

var relayoutCallback = function(scene) {
if(scene.fullSceneLayout.dragmode === false) return;

var update = {};
update[scene.id + '.camera'] = getLayoutCamera(scene.camera);
scene.saveCamera(gd.layout);
var update = makeUpdate();
scene.saveLayout(gd.layout);
scene.graphDiv.emit('plotly_relayout', update);
};

scene.glplot.canvas.addEventListener('mouseup', function() {
relayoutCallback(scene);
});

scene.glplot.canvas.addEventListener('wheel', function() {
scene.glplot.canvas.addEventListener('wheel', function(e) {
if(gd._context._scrollZoom.gl3d) {
if(scene.glplot.camera._ortho) {
var s = (e.deltaX > e.deltaY) ? 1.1 : 1.0 / 1.1;

var aspectratio = scene.fullSceneLayout.aspectratio;

aspectratio.x = scene.glplot.aspect[0] *= s;
aspectratio.y = scene.glplot.aspect[1] *= s;
aspectratio.z = scene.glplot.aspect[2] *= s;

scene.glplot.setAspectratio(aspectratio);
scene.glplot.redraw();
}

relayoutCallback(scene);
}
}, passiveSupported ? {passive: false} : false);
Expand All @@ -283,8 +309,7 @@ function initializeGLPlot(scene, pixelRatio, canvas, gl) {
if(scene.fullSceneLayout.dragmode === false) return;
if(scene.camera.mouseListener.buttons === 0) return;

var update = {};
update[scene.id + '.camera'] = getLayoutCamera(scene.camera);
var update = makeUpdate();
scene.graphDiv.emit('plotly_relayouting', update);
});

Expand Down Expand Up @@ -496,7 +521,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
this.spikeOptions.merge(fullSceneLayout);

// Update camera and camera mode
this.setCamera(fullSceneLayout.camera);
this.setViewport(fullSceneLayout);
this.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
this.camera.enableWheel = this.graphDiv._context._scrollZoom.gl3d;

Expand Down Expand Up @@ -720,8 +745,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
* Finally assign the computed aspecratio to the glplot module. This will have an effect
* on the next render cycle.
*/
this.glplot.aspect = aspectRatio;

this.glplot.setAspectratio(fullSceneLayout.aspectratio);

// Update frame position for multi plots
var domain = fullSceneLayout.domain || null;
Expand Down Expand Up @@ -751,9 +775,9 @@ proto.destroy = function() {
this.glplot = null;
};

// getOrbitCamera :: plotly_coords -> orbit_camera_coords
// getCameraArrays :: plotly_coords -> orbit_camera_coords
// inverse of getLayoutCamera
function getOrbitCamera(camera) {
function getCameraArrays(camera) {
return [
[camera.eye.x, camera.eye.y, camera.eye.z],
[camera.center.x, camera.center.y, camera.center.z],
Expand All @@ -762,7 +786,7 @@ function getOrbitCamera(camera) {
}

// getLayoutCamera :: orbit_camera_coords -> plotly_coords
// inverse of getOrbitCamera
// inverse of getCameraArrays
function getLayoutCamera(camera) {
return {
up: {x: camera.up[0], y: camera.up[1], z: camera.up[2]},
Expand All @@ -778,9 +802,12 @@ proto.getCamera = function getCamera() {
return getLayoutCamera(this.glplot.camera);
};

// set camera position with a set of plotly coords
proto.setCamera = function setCamera(cameraData) {
this.glplot.camera.lookAt.apply(this, getOrbitCamera(cameraData));
// set gl-plot3d camera position and scene aspects with a set of plotly coords
proto.setViewport = function setViewport(sceneLayout) {
var cameraData = sceneLayout.camera;

this.glplot.camera.lookAt.apply(this, getCameraArrays(cameraData));
this.glplot.setAspectratio(sceneLayout.aspectratio);

var newOrtho = (cameraData.projection.type === 'orthographic');
var oldOrtho = this.glplot.camera._ortho;
Expand All @@ -807,11 +834,17 @@ proto.setCamera = function setCamera(cameraData) {
};

// save camera to user layout (i.e. gd.layout)
proto.saveCamera = function saveCamera(layout) {
proto.saveLayout = function saveLayout(layout) {
var fullLayout = this.fullLayout;

var cameraData = this.getCamera();
var cameraNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
var cameraDataLastSave = cameraNestedProp.get();

var aspectData = this.glplot.getAspectratio();
var aspectNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
var aspectDataLastSave = aspectNestedProp.get();

var hasChanged = false;

function same(x, y, i, j) {
Expand Down Expand Up @@ -839,15 +872,33 @@ proto.saveCamera = function saveCamera(layout) {
}
}

if(!hasChanged) {
if(aspectDataLastSave === undefined) {
hasChanged = true;
} else {
if(
aspectDataLastSave.x !== aspectData.x ||
aspectDataLastSave.y !== aspectData.y ||
aspectDataLastSave.z !== aspectData.z
) {
hasChanged = true;
}
}
}

if(hasChanged) {
var preGUI = {};
preGUI[this.id + '.camera'] = cameraDataLastSave;
preGUI[this.id + '.aspectratio'] = aspectDataLastSave;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too, we should only store the aspectratio change for orthographic projections.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in b92230a.

Registry.call('_storeDirectGUIEdit', layout, fullLayout._preGUI, preGUI);

cameraNestedProp.set(cameraData);

var cameraFullNP = Lib.nestedProperty(fullLayout, this.id + '.camera');
cameraFullNP.set(cameraData);

var aspectFullNP = Lib.nestedProperty(fullLayout, this.id + '.aspectratio');
aspectFullNP.set(aspectData);
}

return hasChanged;
Expand Down
23 changes: 22 additions & 1 deletion test/jasmine/tests/gl3d_plot_interact_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,24 @@ describe('Test gl3d drag and wheel interactions', function() {
return scroll(sceneTarget2);
})
.then(function() {
expect(
gd._fullLayout.scene2.aspectratio.x
).toEqual(
gd._fullLayout.scene2._scene.glplot.aspect[0]
);

expect(
gd._fullLayout.scene2.aspectratio.y
).toEqual(
gd._fullLayout.scene2._scene.glplot.aspect[1]
);

expect(
gd._fullLayout.scene2.aspectratio.z
).toEqual(
gd._fullLayout.scene2._scene.glplot.aspect[2]
);

_assertAndReset(2);
})
.catch(failTest)
Expand Down Expand Up @@ -1169,7 +1187,10 @@ describe('Test gl3d annotations', function() {
var camera = scene.getCamera();

camera.eye = {x: x, y: y, z: z};
scene.setCamera(camera);
scene.setViewport({
camera: camera,
aspectratio: gd._fullLayout.scene.aspectratio
});
// need a fairly long delay to let the camera update here
// 300 was not robust for me (AJ), 500 seems to be.
return delay(500)();
Expand Down
13 changes: 8 additions & 5 deletions test/jasmine/tests/plot_api_react_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1968,11 +1968,14 @@ describe('Test Plotly.react + interactions under uirevision:', function() {
function _mouseup() {
var sceneLayout = gd._fullLayout.scene;
var cameraOld = sceneLayout.camera;
sceneLayout._scene.setCamera({
projection: {type: 'perspective'},
eye: {x: 2, y: 2, z: 2},
center: cameraOld.center,
up: cameraOld.up
sceneLayout._scene.setViewport({
camera: {
projection: {type: 'perspective'},
eye: {x: 2, y: 2, z: 2},
center: cameraOld.center,
up: cameraOld.up
},
aspectratio: gd._fullLayout.scene.aspectratio
});

var target = gd.querySelector('.svg-container .gl-container #scene canvas');
Expand Down