diff --git a/src/components/fx/click.js b/src/components/fx/click.js index 0fb3ed79828..32f4b767eec 100644 --- a/src/components/fx/click.js +++ b/src/components/fx/click.js @@ -9,10 +9,19 @@ 'use strict'; var Registry = require('../../registry'); +var hover = require('./hover').hover; -module.exports = function click(gd, evt) { +module.exports = function click(gd, evt, subplot) { var annotationsDone = Registry.getComponentMethod('annotations', 'onClick')(gd, gd._hoverdata); + // fallback to fail-safe in case the plot type's hover method doesn't pass the subplot. + // Ternary, for example, didn't, but it was caught because tested. + if(subplot !== undefined) { + // The true flag at the end causes it to re-run the hover computation to figure out *which* + // point is being clicked. Without this, clicking is somewhat unreliable. + hover(gd, evt, subplot, true); + } + function emitClick() { gd.emit('plotly_click', {points: gd._hoverdata, event: evt}); } if(gd._hoverdata && evt && evt.target) { diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 6f68788bd38..051d8c9c709 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -66,7 +66,7 @@ var HOVERTEXTPAD = constants.HOVERTEXTPAD; // // We wrap the hovers in a timer, to limit their frequency. // The actual rendering is done by private function _hover. -exports.hover = function hover(gd, evt, subplot) { +exports.hover = function hover(gd, evt, subplot, noHoverEvent) { if(typeof gd === 'string') gd = document.getElementById(gd); if(gd._lastHoverTime === undefined) gd._lastHoverTime = 0; @@ -78,13 +78,13 @@ exports.hover = function hover(gd, evt, subplot) { // Is it more than 100ms since the last update? If so, force // an update now (synchronously) and exit if(Date.now() > gd._lastHoverTime + constants.HOVERMINTIME) { - _hover(gd, evt, subplot); + _hover(gd, evt, subplot, noHoverEvent); gd._lastHoverTime = Date.now(); return; } // Queue up the next hover for 100ms from now (if no further events) gd._hoverTimer = setTimeout(function() { - _hover(gd, evt, subplot); + _hover(gd, evt, subplot, noHoverEvent); gd._lastHoverTime = Date.now(); gd._hoverTimer = undefined; }, constants.HOVERMINTIME); @@ -168,8 +168,8 @@ exports.loneHover = function loneHover(hoverItem, opts) { }; // The actual implementation is here: -function _hover(gd, evt, subplot) { - if(subplot === 'pie' || subplot === 'sankey') { +function _hover(gd, evt, subplot, noHoverEvent) { + if((subplot === 'pie' || subplot === 'sankey') && !noHoverEvent) { gd.emit('plotly_hover', { event: evt.originalEvent, points: [evt] @@ -505,7 +505,7 @@ function _hover(gd, evt, subplot) { } // don't emit events if called manually - if(!evt.target || !hoverChanged(gd, evt, oldhoverdata)) return; + if(!evt.target || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return; if(oldhoverdata) { gd.emit('plotly_unhover', { diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 410e693fe09..508029a96ba 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -97,7 +97,7 @@ module.exports = function initInteractions(gd) { }; maindrag.onclick = function(evt) { - Fx.click(gd, evt); + Fx.click(gd, evt, subplot); }; // corner draggers diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 4c1e6a8c6a3..fa9fcbfcf67 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -631,7 +631,7 @@ proto.initInteractions = function() { }; dragger.onclick = function(evt) { - Fx.click(gd, evt); + Fx.click(gd, evt, _this.id); }; dragElement.init(dragOptions); diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 5a723bc871f..72dee431d46 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -587,6 +587,23 @@ describe('hover info', function() { Plotly.plot(gd, data, layout).then(done); }); + it('should skip the hover event if explicitly instructed', function(done) { + var hoverHandler = jasmine.createSpy(); + gd.on('plotly_hover', hoverHandler); + + var gdBB = gd.getBoundingClientRect(); + var event = {clientX: gdBB.left + 300, clientY: gdBB.top + 200}; + + Promise.resolve().then(function() { + Fx.hover(gd, event, 'xy', true); + }) + .then(function() { + expect(hoverHandler).not.toHaveBeenCalled(); + }) + .catch(fail) + .then(done); + }); + it('should emit events only if the event looks user-driven', function(done) { var hoverHandler = jasmine.createSpy(); gd.on('plotly_hover', hoverHandler);