Skip to content

Commit

Permalink
Merge pull request #3597 from plotly/fix-reset-camera3d-after-switch-…
Browse files Browse the repository at this point in the history
…projection

fix reset camera buttons to work after switching projection between perspective and orthographic
  • Loading branch information
archmoj committed Mar 5, 2019
2 parents 1fd9560 + 3c37554 commit cff31df
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 21 deletions.
16 changes: 8 additions & 8 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,14 @@ function handleCamera3d(gd, ev) {
var key = sceneId + '.camera';
var scene = fullLayout[sceneId]._scene;

if(attr === 'resetDefault') {
aobj[key] = Lib.extendDeep({}, scene.cameraInitial);
aobj[key].up = null;
aobj[key].eye = null;
aobj[key].center = null;
}
else if(attr === 'resetLastSave') {
aobj[key] = Lib.extendDeep({}, scene.cameraInitial);
if(attr === 'resetLastSave') {
aobj[key + '.up'] = scene.viewInitial.up;
aobj[key + '.eye'] = scene.viewInitial.eye;
aobj[key + '.center'] = scene.viewInitial.center;
} else if(attr === 'resetDefault') {
aobj[key + '.up'] = null;
aobj[key + '.eye'] = null;
aobj[key + '.center'] = null;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1589,7 +1589,7 @@ function _restyle(gd, aobj, traces) {
// and figure out what kind of graphics update we need to do
for(var ai in aobj) {
if(helpers.hasParent(aobj, ai)) {
throw new Error('cannot set ' + ai + 'and a parent attribute simultaneously');
throw new Error('cannot set ' + ai + ' and a parent attribute simultaneously');
}

var vi = aobj[ai];
Expand Down Expand Up @@ -2095,7 +2095,7 @@ function _relayout(gd, aobj) {
// alter gd.layout
for(var ai in aobj) {
if(helpers.hasParent(aobj, ai)) {
throw new Error('cannot set ' + ai + 'and a parent attribute simultaneously');
throw new Error('cannot set ' + ai + ' and a parent attribute simultaneously');
}

var p = layoutNP(layout, ai);
Expand Down
22 changes: 19 additions & 3 deletions src/plots/gl3d/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,25 @@ exports.plot = function plotGl3d(gd) {
sceneLayout._scene = scene;
}

// save 'initial' camera settings for modebar button
if(!scene.cameraInitial) {
scene.cameraInitial = Lib.extendDeep({}, sceneLayout.camera);
// save 'initial' camera view settings for modebar button
if(!scene.viewInitial) {
scene.viewInitial = {
up: {
x: camera.up.x,
y: camera.up.y,
z: camera.up.z
},
eye: {
x: camera.eye.x,
y: camera.eye.y,
z: camera.eye.z
},
center: {
x: camera.center.x,
y: camera.center.y,
z: camera.center.z
}
};
}

scene.plot(fullSceneData, fullLayout, gd.layout);
Expand Down
8 changes: 4 additions & 4 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ function initializeGLPlot(scene, camera, pixelRatio, canvas, gl) {
if(scene.fullSceneLayout.dragmode === false) return;

var update = {};
update[scene.id + '.camera'] = getLayoutCamera(scene.camera, scene.camera._ortho);
update[scene.id + '.camera'] = getLayoutCamera(scene.camera);
scene.saveCamera(gd.layout);
scene.graphDiv.emit('plotly_relayout', update);
};
Expand Down Expand Up @@ -758,19 +758,19 @@ function getOrbitCamera(camera) {

// getLayoutCamera :: orbit_camera_coords -> plotly_coords
// inverse of getOrbitCamera
function getLayoutCamera(camera, isOrtho) {
function getLayoutCamera(camera) {
return {
up: {x: camera.up[0], y: camera.up[1], z: camera.up[2]},
center: {x: camera.center[0], y: camera.center[1], z: camera.center[2]},
eye: {x: camera.eye[0], y: camera.eye[1], z: camera.eye[2]},
projection: {type: (isOrtho === true) ? 'orthographic' : 'perspective'}
projection: {type: (camera._ortho === true) ? 'orthographic' : 'perspective'}
};
}

// get camera position in plotly coords from 'orbit-camera' coords
proto.getCamera = function getCamera() {
this.glplot.camera.view.recalcMatrix(this.camera.view.lastT());
return getLayoutCamera(this.glplot.camera, this.glplot.camera._ortho);
return getLayoutCamera(this.glplot.camera);
};

// set camera position with a set of plotly coords
Expand Down
105 changes: 101 additions & 4 deletions test/jasmine/tests/gl3d_plot_interact_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1043,8 +1043,8 @@ describe('Test gl3d modebar handlers', function() {
it('@gl button resetCameraDefault3d should reset camera to default', function(done) {
var buttonDefault = selectButton(modeBar, 'resetCameraDefault3d');

expect(gd._fullLayout.scene._scene.cameraInitial.eye).toEqual({ x: 0.1, y: 0.1, z: 1 });
expect(gd._fullLayout.scene2._scene.cameraInitial.eye).toEqual({ x: 2.5, y: 2.5, z: 2.5 });
expect(gd._fullLayout.scene._scene.viewInitial.eye).toEqual({ x: 0.1, y: 0.1, z: 1 });
expect(gd._fullLayout.scene2._scene.viewInitial.eye).toEqual({ x: 2.5, y: 2.5, z: 2.5 });

gd.once('plotly_relayout', function() {
assertScenes(gd._fullLayout, 'camera.eye.x', 1.25);
Expand Down Expand Up @@ -1099,8 +1099,8 @@ describe('Test gl3d modebar handlers', function() {
assertCameraEye(gd._fullLayout.scene, 0.1, 0.1, 1);
assertCameraEye(gd._fullLayout.scene2, 2.5, 2.5, 2.5);

delete gd._fullLayout.scene._scene.cameraInitial;
delete gd._fullLayout.scene2._scene.cameraInitial;
delete gd._fullLayout.scene._scene.viewInitial;
delete gd._fullLayout.scene2._scene.viewInitial;

Plotly.relayout(gd, {
'scene.bgcolor': '#d3d3d3',
Expand Down Expand Up @@ -1489,6 +1489,103 @@ describe('Test gl3d relayout calls', function() {
.catch(failTest)
.then(done);
});

it('@gl should maintain projection type when resetCamera buttons clicked after switching projection type from perspective to orthographic', function(done) {
Plotly.plot(gd, {
data: [{
type: 'surface',
x: [0, 1],
y: [0, 1],
z: [[0, 1], [1, 0]]
}],
layout: {
width: 300,
height: 200,
scene: {
camera: {
eye: {
x: 2,
y: 1,
z: 0.5
}
}
}
}
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(false, 'perspective');
})
.then(function() {
return Plotly.relayout(gd, 'scene.camera.projection.type', 'orthographic');
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(true, 'orthographic');
})
.then(function() {
return selectButton(gd._fullLayout._modeBar, 'resetCameraLastSave3d').click();
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(true, 'orthographic');
})
.then(function() {
return selectButton(gd._fullLayout._modeBar, 'resetCameraDefault3d').click();
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(true, 'orthographic');
})
.catch(failTest)
.then(done);
});

it('@gl should maintain projection type when resetCamera buttons clicked after switching projection type from orthographic to perspective', function(done) {
Plotly.plot(gd, {
data: [{
type: 'surface',
x: [0, 1],
y: [0, 1],
z: [[0, 1], [1, 0]]
}],
layout: {
width: 300,
height: 200,
scene: {
camera: {
eye: {
x: 2,
y: 1,
z: 0.5
},
projection: {
type: 'orthographic'
}
}
}
}
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(true, 'orthographic');
})
.then(function() {
return Plotly.relayout(gd, 'scene.camera.projection.type', 'perspective');
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(false, 'perspective');
})
.then(function() {
return selectButton(gd._fullLayout._modeBar, 'resetCameraLastSave3d').click();
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(false, 'perspective');
})
.then(function() {
return selectButton(gd._fullLayout._modeBar, 'resetCameraDefault3d').click();
})
.then(function() {
expect(gd._fullLayout.scene._scene.camera._ortho).toEqual(false, 'perspective');
})
.catch(failTest)
.then(done);
});
});

describe('Test gl3d annotations', function() {
Expand Down

0 comments on commit cff31df

Please sign in to comment.