Skip to content

Emit a plotly_relayout' event upon mouseup, wheel #466

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
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a7177f2
#30a emit an event upon manipulation
monfera Apr 22, 2016
1b19b3a
#30a removing preexisting lint exemption directives and fixing former…
monfera Apr 22, 2016
34d15aa
#30a removing preexisting lint exemption directives and fixing former…
monfera Apr 22, 2016
3d8fe81
#30a covering 2D WebGL plot with the plotly_relayout event on pan / zoom
monfera Apr 28, 2016
a10caec
#30a test case for mouse drag and wheel on gl3d plots
monfera Apr 29, 2016
604d739
#30a proper grouping by interaction type
monfera Apr 29, 2016
ee8ff65
#30a test case for mouse drag on gl2d plots
monfera Apr 29, 2016
da01879
#30a reifying plotly_relayout callback count, as well as layout data …
monfera May 2, 2016
48682a4
#30a adding graphDiv to Scene2d similarly to Scene / thanks @etpinard
monfera May 2, 2016
63ec931
#30a bumping jasmine to 2.4 to enjoy its new facilities such as spy.t…
monfera May 2, 2016
19c478d
#30a panning test on WebGL canvas; adding the DIV update for scene2d
monfera May 3, 2016
e467c88
#30a saving the camera position on the DIV layout when the projection…
monfera May 3, 2016
b212086
#30a PR feedback: not expose scene id and use axis names. Plus: test …
monfera May 3, 2016
e8aa9cb
#30a PR feedback: remove `delay`
monfera May 3, 2016
e02a3f6
#30a adding tests for the 3d callback and DIV layout camera data update
monfera May 3, 2016
4975417
#30a PR feedback: commenting and removing disused binding
monfera May 4, 2016
7c23e2e
#30a PR feedback: adding test case with partially set camera and solv…
monfera May 6, 2016
7eef2e1
#30a removing new test case from the test file that's currently ignor…
monfera May 6, 2016
2a13e92
#30a excluding gl_plot_interact_basic_test.js from the CI run. Benefi…
monfera May 6, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"fs-extra": "^0.28.0",
"fuse.js": "^2.2.0",
"glob": "^7.0.0",
"jasmine-core": "^2.3.4",
"jasmine-core": "^2.4.1",
"karma": "^0.13.15",
"karma-browserify": "^5.0.1",
"karma-chrome-launcher": "^0.2.1",
Expand Down
3 changes: 2 additions & 1 deletion src/plots/gl2d/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ exports.plot = function plotGl2d(gd) {
// If Scene is not instantiated, create one!
if(scene === undefined) {
scene = new Scene2D({
container: gd.querySelector('.gl-container'),
id: subplotId,
graphDiv: gd,
container: gd.querySelector('.gl-container'),
staticPlot: gd._context.staticPlot,
plotGlPixelRatio: gd._context.plotGlPixelRatio
},
Expand Down
22 changes: 22 additions & 0 deletions src/plots/gl2d/scene2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var STATIC_CANVAS, STATIC_CONTEXT;

function Scene2D(options, fullLayout) {
this.container = options.container;
this.graphDiv = options.graphDiv;
this.pixelRatio = options.plotGlPixelRatio || window.devicePixelRatio;
this.id = options.id;
this.staticPlot = !!options.staticPlot;
Expand Down Expand Up @@ -268,6 +269,26 @@ proto.updateFx = function(options) {
fullLayout.hovermode = options.hovermode;
};

var relayoutCallback = function(scene) {

var update = {},
xrange = scene.xaxis.range,
yrange = scene.yaxis.range;

// Update the layout on the DIV
scene.graphDiv.layout.xaxis.range = xrange.slice(0);
scene.graphDiv.layout.yaxis.range = yrange.slice(0);

// Make a meaningful value to be passed on to the possible 'plotly_relayout' subscriber(s)
update[scene.id] = { // scene.camera has no many useful projection or scale information
lastInputTime: scene.camera.lastInputTime, // helps determine which one is the latest input (if async)
xrange: xrange.slice(0),
yrange: yrange.slice(0)
};
Copy link
Contributor

Choose a reason for hiding this comment

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

In gl2d, scene is purely internal. I'd vote for something like:

update = {
  lastInputTime: scene.camera.lastInputTime  // great idea here!
};
update[xaxis._name] = xrange.slice();
update[yaxis._name] = yrange.slice();

where ?axis.name will be xaxis, xaxis2, yaxis, yaxis2 ...


scene.graphDiv.emit('plotly_relayout', update);
};

proto.cameraChanged = function() {
var camera = this.camera,
xrange = this.xaxis.range,
Expand All @@ -285,6 +306,7 @@ proto.cameraChanged = function() {
this.glplotOptions.ticks = nextTicks;
this.glplotOptions.dataBox = camera.dataBox;
this.glplot.update(this.glplotOptions);
relayoutCallback(this);
}
};

Expand Down
91 changes: 51 additions & 40 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
*/


/*eslint block-scoped-var: 0*/
/*eslint no-redeclare: 0*/

'use strict';

var createPlot = require('gl-plot3d');
Expand All @@ -34,6 +31,8 @@ var STATIC_CANVAS, STATIC_CONTEXT;

function render(scene) {

var trace;

// update size of svg container
var svgContainer = scene.svgContainer;
var clientRect = scene.container.getBoundingClientRect();
Expand All @@ -50,7 +49,7 @@ function render(scene) {
var lastPicked = null;
var selection = scene.glplot.selection;
for(var i = 0; i < keys.length; ++i) {
var trace = scene.traces[keys[i]];
trace = scene.traces[keys[i]];
if(trace.handlePick(selection)) {
lastPicked = trace;
}
Expand All @@ -68,9 +67,9 @@ function render(scene) {
var oldEventData;

if(lastPicked !== null) {
var pdata = project(scene.glplot.cameraParams, selection.dataCoordinate),
trace = lastPicked.data,
hoverinfo = trace.hoverinfo;
var pdata = project(scene.glplot.cameraParams, selection.dataCoordinate);
trace = lastPicked.data;
var hoverinfo = trace.hoverinfo;

var xVal = formatter('xaxis', selection.traceCoordinate[0]),
yVal = formatter('yaxis', selection.traceCoordinate[1]),
Expand Down Expand Up @@ -172,6 +171,15 @@ function initializeGLPlot(scene, fullLayout, canvas, gl) {
showNoWebGlMsg(scene);
}

var relayoutCallback = function(scene) {
var update = {};
update[scene.id] = getLayoutCamera(scene.camera);
scene.graphDiv.emit('plotly_relayout', update);
};

scene.glplot.canvas.addEventListener('mouseup', relayoutCallback.bind(null, scene));
scene.glplot.canvas.addEventListener('wheel', relayoutCallback.bind(null, scene));
Copy link
Contributor

Choose a reason for hiding this comment

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

Great. It would be nice to add a mouse wheel test. See the legend_scroll for inspiration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback!


if(!scene.staticMode) {
scene.glplot.canvas.addEventListener('webglcontextlost', function(ev) {
console.log('lost context');
Expand Down Expand Up @@ -255,7 +263,7 @@ function Scene(options, fullLayout) {

this.contourLevels = [ [], [], [] ];

if(!initializeGLPlot(this, fullLayout)) return;
if(!initializeGLPlot(this, fullLayout)) return; // todo check the necessity for this line
}

var proto = Scene.prototype;
Expand Down Expand Up @@ -283,18 +291,19 @@ proto.recoverContext = function() {
var axisProperties = [ 'xaxis', 'yaxis', 'zaxis' ];

function coordinateBound(axis, coord, d, bounds) {
var x;
for(var i=0; i<coord.length; ++i) {
if(Array.isArray(coord[i])) {
for(var j=0; j<coord[i].length; ++j) {
var x = axis.d2l(coord[i][j]);
x = axis.d2l(coord[i][j]);
if(!isNaN(x) && isFinite(x)) {
bounds[0][d] = Math.min(bounds[0][d], x);
bounds[1][d] = Math.max(bounds[1][d], x);
}
}
}
else {
var x = axis.d2l(coord[i]);
x = axis.d2l(coord[i]);
if(!isNaN(x) && isFinite(x)) {
bounds[0][d] = Math.min(bounds[0][d], x);
bounds[1][d] = Math.max(bounds[1][d], x);
Expand All @@ -317,7 +326,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
if(this.glplot.contextLost) return;

var data, trace;
var i, j;
var i, j, axis, axisType;
var fullSceneLayout = fullLayout[this.id];
var sceneLayout = layout[this.id];

Expand All @@ -341,7 +350,7 @@ proto.plot = function(sceneData, fullLayout, layout) {

// Update axes functions BEFORE updating traces
for(i = 0; i < 3; ++i) {
var axis = fullSceneLayout[axisProperties[i]];
axis = fullSceneLayout[axisProperties[i]];
setConvert(axis);
}

Expand All @@ -354,14 +363,14 @@ proto.plot = function(sceneData, fullLayout, layout) {
[Infinity, Infinity, Infinity],
[-Infinity, -Infinity, -Infinity]
];
for(var i=0; i<sceneData.length; ++i) {
var data = sceneData[i];
for(i=0; i<sceneData.length; ++i) {
data = sceneData[i];
if(data.visible !== true) continue;

computeTraceBounds(this, data, dataBounds);
}
var dataScale = [1,1,1];
for(var j=0; j<3; ++j) {
for(j=0; j<3; ++j) {
if(dataBounds[0][j] > dataBounds[1][j]) {
dataScale[j] = 1.0;
}
Expand All @@ -379,7 +388,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
this.dataScale = dataScale;

//Update traces
for(var i = 0; i < sceneData.length; ++i) {
for(i = 0; i < sceneData.length; ++i) {
data = sceneData[i];
if(data.visible!==true) {
continue;
Expand Down Expand Up @@ -416,8 +425,8 @@ proto.plot = function(sceneData, fullLayout, layout) {
axisTypeRatios = {};

for(i = 0; i < 3; ++i) {
var axis = fullSceneLayout[axisProperties[i]];
var axisType = axis.type;
axis = fullSceneLayout[axisProperties[i]];
axisType = axis.type;

if(axisType in axisTypeRatios) {
axisTypeRatios[axisType].acc *= dataScale[i];
Expand Down Expand Up @@ -471,9 +480,9 @@ proto.plot = function(sceneData, fullLayout, layout) {
var axesScaleRatio = [1, 1, 1];

//Compute axis scale per category
for(var i=0; i<3; ++i) {
var axis = fullSceneLayout[axisProperties[i]];
var axisType = axis.type;
for(i=0; i<3; ++i) {
axis = fullSceneLayout[axisProperties[i]];
axisType = axis.type;
var axisRatio = axisTypeRatios[axisType];
axesScaleRatio[i] = Math.pow(axisRatio.acc, 1.0/axisRatio.count) / dataScale[i];
}
Expand Down Expand Up @@ -567,33 +576,35 @@ proto.setCameraToDefault = function setCameraToDefault() {
});
};

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

var up = this.glplot.camera.up;
var center = this.glplot.camera.center;
var eye = this.glplot.camera.eye;
// getOrbitCamera :: plotly_coords -> orbit_camera_coords
// inverse of getLayoutCamera
function getOrbitCamera(camera) {
return [
[camera.eye.x, camera.eye.y, camera.eye.z],
[camera.center.x, camera.center.y, camera.center.z],
[camera.up.x, camera.up.y, camera.up.z]
];
}

// getLayoutCamera :: orbit_camera_coords -> plotly_coords
// inverse of getOrbitCamera
function getLayoutCamera(camera) {
return {
up: {x: up[0], y: up[1], z: up[2]},
center: {x: center[0], y: center[1], z: center[2]},
eye: {x: eye[0], y: eye[1], z: eye[2]}
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]}
};
}

// 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);
};

// set camera position with a set of plotly coords
proto.setCamera = function setCamera(cameraData) {

// getOrbitCamera :: plotly_coords -> orbit_camera_coords
function getOrbitCamera(camera) {
return [
[camera.eye.x, camera.eye.y, camera.eye.z],
[camera.center.x, camera.center.y, camera.center.z],
[camera.up.x, camera.up.y, camera.up.z]
];
}

var update = {};

update[this.id] = cameraData;
Expand Down
Loading