Skip to content

Commit

Permalink
Merge pull request #240 from plotly/gl-hover
Browse files Browse the repository at this point in the history
Trigger hover and click events on gl3d graphs
  • Loading branch information
etpinard committed Feb 25, 2016
2 parents 5d35fd6 + fa12603 commit a7451ff
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 44 deletions.
4 changes: 2 additions & 2 deletions devtools/test_dashboard/test_gl3d.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ plots['projection-traces'] = require('@mocks/gl3d_projection-traces.json');
plots['opacity-scaling-spikes'] = require('@mocks/gl3d_opacity-scaling-spikes.json');
plots['text-weirdness'] = require('@mocks/gl3d_text-weirdness.json');
plots['wire-surface'] = require('@mocks/gl3d_wire-surface.json');
plots['triangle-mesh3d'] = require('@mocks/gl3d_triangle.json');
plots['triangle'] = require('@mocks/gl3d_triangle.json');
plots['snowden'] = require('@mocks/gl3d_snowden.json');
plots['bunny'] = require('@mocks/gl3d_bunny.json');
plots['ribbons'] = require('@mocks/gl3d_ribbons.json');
plots['scatter-time'] = require('@mocks/gl3d_scatter-date.json');
plots['scatter-date'] = require('@mocks/gl3d_scatter-date.json');
plots['cufflinks'] = require('@mocks/gl3d_cufflinks.json');
plots['chrisp-nan-1'] = require('@mocks/gl3d_chrisp-nan-1.json');
plots['marker-arrays'] = require('@mocks/gl3d_marker-arrays.json');
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"gl-mat4": "^1.1.2",
"gl-mesh3d": "^1.0.7",
"gl-plot2d": "^1.1.6",
"gl-plot3d": "^1.3.0",
"gl-plot3d": "^1.5.0",
"gl-scatter2d": "^1.0.5",
"gl-scatter2d-fancy": "^1.1.1",
"gl-scatter3d": "^1.0.4",
Expand Down
3 changes: 2 additions & 1 deletion src/plots/gl3d/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ exports.plot = function plotGl3d(gd) {
// If Scene is not instantiated, create one!
if(scene === undefined) {
scene = new Scene({
container: gd.querySelector('.gl-container'),
id: sceneId,
graphDiv: gd,
container: gd.querySelector('.gl-container'),
staticPlot: gd._context.staticPlot,
plotGlPixelRatio: gd._context.plotGlPixelRatio
},
Expand Down
65 changes: 49 additions & 16 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var STATIC_CANVAS, STATIC_CONTEXT;

function render(scene) {

//Update size of svg container
// update size of svg container
var svgContainer = scene.svgContainer;
var clientRect = scene.container.getBoundingClientRect();
var width = clientRect.width, height = clientRect.height;
Expand All @@ -45,7 +45,7 @@ function render(scene) {
computeTickMarks(scene);
scene.glplot.axes.update(scene.axesOptions);

//Check if pick has changed
// check if pick has changed
var keys = Object.keys(scene.traces);
var lastPicked = null;
var selection = scene.glplot.selection;
Expand All @@ -59,22 +59,28 @@ function render(scene) {
}

function formatter(axisName, val) {
if(val === undefined) return undefined;
if(typeof val === 'string') return val;

var axis = scene.fullSceneLayout[axisName];
return Axes.tickText(axis, axis.c2l(val), 'hover').text;
}

var oldEventData;

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

var xVal = formatter('xaxis', selection.traceCoordinate[0]),
yVal = formatter('yaxis', selection.traceCoordinate[1]),
zVal = formatter('zaxis', selection.traceCoordinate[2]);

if(hoverinfo !== 'all') {
var hoverinfoParts = hoverinfo.split('+');
if(hoverinfoParts.indexOf('x') === -1) selection.traceCoordinate[0] = undefined;
if(hoverinfoParts.indexOf('y') === -1) selection.traceCoordinate[1] = undefined;
if(hoverinfoParts.indexOf('z') === -1) selection.traceCoordinate[2] = undefined;
if(hoverinfoParts.indexOf('x') === -1) xVal = undefined;
if(hoverinfoParts.indexOf('y') === -1) yVal = undefined;
if(hoverinfoParts.indexOf('z') === -1) zVal = undefined;
if(hoverinfoParts.indexOf('text') === -1) selection.textLabel = undefined;
if(hoverinfoParts.indexOf('name') === -1) lastPicked.name = undefined;
}
Expand All @@ -83,18 +89,42 @@ function render(scene) {
Fx.loneHover({
x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
xLabel: formatter('xaxis', selection.traceCoordinate[0]),
yLabel: formatter('yaxis', selection.traceCoordinate[1]),
zLabel: formatter('zaxis', selection.traceCoordinate[2]),
xLabel: xVal,
yLabel: yVal,
zLabel: zVal,
text: selection.textLabel,
name: lastPicked.name,
color: lastPicked.color
}, {
container: svgContainer
});
}

var eventData = {
points: [{
x: xVal,
y: yVal,
z: zVal,
data: trace._input,
fullData: trace,
curveNumber: trace.index,
pointNumber: selection.data.index
}]
};

if(selection.buttons && selection.distance < 5) {
scene.graphDiv.emit('plotly_click', eventData);
}
else {
scene.graphDiv.emit('plotly_hover', eventData);
}

oldEventData = eventData;
}
else {
Fx.loneUnhover(svgContainer);
scene.graphDiv.emit('plotly_unhover', oldEventData);
}
else Fx.loneUnhover(svgContainer);
}

function initializeGLPlot(scene, fullLayout, canvas, gl) {
Expand All @@ -110,9 +140,9 @@ function initializeGLPlot(scene, fullLayout, canvas, gl) {
autoBounds: false
};

//For static plots, we reuse the WebGL context as WebKit doesn't collect them
//reliably
if (scene.staticMode) {
// for static plots, we reuse the WebGL context
// as WebKit doesn't collect them reliably
if(scene.staticMode) {
if(!STATIC_CONTEXT) {
STATIC_CANVAS = document.createElement('canvas');
try {
Expand Down Expand Up @@ -178,11 +208,14 @@ function initializeGLPlot(scene, fullLayout, canvas, gl) {

function Scene(options, fullLayout) {

//Create sub container for plot
// create sub container for plot
var sceneContainer = document.createElement('div');
var plotContainer = options.container;

//Create SVG container for hover text
// keep a ref to the graph div to fire hover+click events
this.graphDiv = options.graphDiv;

// create SVG container for hover text
var svgContainer = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg');
Expand Down
7 changes: 3 additions & 4 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,11 +476,10 @@ plots.supplyDefaults = function(gd) {
};

function cleanScenes(newFullLayout, oldFullLayout) {
var oldSceneKey,
oldSceneKeys = plots.getSubplotIds(oldFullLayout, 'gl3d');
var oldSceneKeys = plots.getSubplotIds(oldFullLayout, 'gl3d');

for (var i = 0; i < oldSceneKeys.length; i++) {
oldSceneKey = oldSceneKeys[i];
for(var i = 0; i < oldSceneKeys.length; i++) {
var oldSceneKey = oldSceneKeys[i];
if(!newFullLayout[oldSceneKey] && !!oldFullLayout[oldSceneKey]._scene) {
oldFullLayout[oldSceneKey]._scene.destroy();
}
Expand Down
11 changes: 8 additions & 3 deletions test/jasmine/assets/mouse_event.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
module.exports = function(type, x, y) {
var options = {
module.exports = function(type, x, y, opts) {
var fullOpts = {
bubbles: true,
clientX: x,
clientY: y
};

// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
if(opts && opts.buttons) {
fullOpts.buttons = opts.buttons;
}

var el = document.elementFromPoint(x,y);
var ev = new window.MouseEvent(type, options);
var ev = new window.MouseEvent(type, fullOpts);
el.dispatchEvent(ev);
};
4 changes: 1 addition & 3 deletions test/jasmine/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ func.defaultConfig = {
testFileGlob
],

// list of files to exclude
exclude: [
],
exclude: [],

// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
Expand Down
Loading

0 comments on commit a7451ff

Please sign in to comment.