Triggering plotly_hover or plotly_click from native JS

Hi folks,

I’ve been attempting to trigger the hover tooltip by generating a correctly-formatted mouse event. In particular, this event is triggered by a touch tap (where a “tap” event is available in the framework I’m working in).

I’ve been following the examples here (1, 2) to generate a plotly_hover event. I’ve also attempted to follow the examples here (*3 , *4) to generate a plotly_click event. I’ve been unsuccessful.

Specifically, the following code does not generate a plotly_hover or a plotly_click event, yet the event itself triggers:

HTML:

<div id="myDiv"></div>

JavaScript:

var d3 = Plotly.d3,
     N = 100,
     x = d3.range(N),
    y1 = d3.range(N).map( d3.random.normal() ),
    y2 = d3.range(N).map( d3.random.normal(-2) ),
    y3 = d3.range(N).map( d3.random.normal(2) ),
trace1 = { x:x, y:y1, type:'scatter', mode:'lines', name:'Jeff' },
trace2 = { x:x, y:y2, type:'scatter', mode:'lines', name:'Terren' },
trace3 = { x:x, y:y3, type:'scatter', mode:'lines', name:'Arthur' },
  data = [ trace1, trace2, trace3 ],
layout = {
  hovermode: 'closest',
  title: 'Tap on Points to add an Annotation on it'
};

Plotly.newPlot('myDiv', data, layout);

var myPlot = document.getElementById('myDiv');
// I have a tap event available in my framework (Ionic), not normally available.
myPlot.addEventListener('tap', (event) => tapEvent(event));
myPlot.on('plotly_click', (data) => console.log('plotly_click triggered'));
myPlot.on('plotly_hover', (data) => console.log('plotly_hover triggered'));

function tapEvent(event) {
  console.log('tap event triggered');
  var fullOpts = {
    bubbles: true,
    clientX: event.center.x,
    clientY: event.center.y
  };
  event.target.dispatchEvent(new MouseEvent('mousemove', fullOpts));
  event.target.dispatchEvent(new MouseEvent('mousedown', fullOpts));
  event.target.dispatchEvent(new MouseEvent('mouseup', fullOpts));
  event.target.dispatchEvent(new MouseEvent('click', fullOpts));
}

This code dispatches the event on the tap event target, but I’ve also tried dispatchEvent on a target acquired via document.elementFromPoint(event.center.x, event.center.y) as well as my top-level graph div, document.getElementById('myDiv');. None of these targets work. I’ve also attempted dispatching just a “mouseover” event (to trigger “plotly_hover”), but this also does not work.

I’ve confirmed that the event.center.x and event.center.y exactly match the clientX and clientY values generated on a normal mouse click (a click with a mouse also generates a tap event in this framework, so I can compare the two simultaneous events generated from the same physical action – however, moving to a tap triggered by touch no longer triggers “plotly_click”).

Any suggestions or pointers on what to try next?

* New users can only put two links in a post, so the other two refs are located in the same GitHub repo at the filepaths:
*3 test/jasmine/tests/click_test.js
*4 test/jasmine/assets/click.js

Thanks for writing in.

Would you mind copying your code snippet in a reproducible jsFiddle or CodePen to help us debug? I’m having a hard time figuring out what the on-tap handler is supposed to do.

FYI, our hover/click events are a little convoluted (see this file for reference) where we add a cover slip div to the DOM on mouse down. This might conflict with your on-tap handler.

Hi @etienne, apologies, lost some characters and forgot to declare the function in my original code; now fixed (TypeScript -> JS manual translation errors). Here’s a CodePen example.

Note that the “tap” event is not normally available in pure JS, so you won’t be able to repro in full. I’ll see if I can repro in pure JS and will reply again if I can. The tap event is properly triggering (log statement is printing), it’s just that the code in tapEvent is not successfully triggering a “plotly_click” event (or a “plotly_hover” event when I change to dispatching a “mouseover” event instead of “mousemove”, “mousedown”, “mouseup”, and “click” events).

Well, I sort of reproduced in native JS, sort of didn’t…

Here’s my CodePen example using touchstart/touchmove/touchend events. Interestingly, if you go to this example in your phone, the plotly_hover and plotly_click events will not trigger. However, the hovertext will be drawn, which was my desired behavior in the first place. That was… unexpected.

Unfortunately the hovertext is not being drawn when I render the page in the Ionic framework, even when using touchstart/touchmove/touchend instead of the Ionic tap event. Might be related to the cover for the drag element, or might be some weirdness in how Ionic handles touch. Still digging… I could give you an Ionic project in which to repro, if you’d like, but that would be a pain if you’ve never used Ionic before; you’d need to get mobile emulators set up, which takes some time.

On a hunch that plotly is doing mobile device detection, I launched my Ionic app on my physical device instead of a device emulator. Tap events on my physical device are drawing the hovertext, which was my desired behavior. I don’t even need to add any listeners like I did in the CodePen example, perhaps because Ionic emits tap events as click events.

Is plotly doing some sort of device type inspection to determine correct UI responses to events? Looks like plotly.js depends on the is-mobile package, though I don’t see it used anywhere.

Either way, I do consider the issue resolved, though I don’t quite understand why it’s working. :slight_smile:

Enable touch interactions for select/lasso/others by dy · Pull Request #1804 · plotly/plotly.js · GitHub added a few touch handlers, I suspect they conflict with your attempt in https://codepen.io/MalinaKirn/pen/ZJXxyg?editors=0011.

Hmm, I’d love to help, but that’s probably outside the scope of my responsibilities on these (free) forums I’m afraid. Hopefully, someone else will be able to help you out.

@etienne, thanks for the link! I can see that the has-hover package was added in that PR, and this is what’s changing the behavior. Somehow the device emulators are not properly returning false when has-hover is checked, whereas the physical devices are properly returning false. Almost certainly an issue with the emulators or with the has-hover package.

Thanks for your time, much appreciated.

1 Like

Hi Malina,

I am trying to reproduce your code in Jupyter. Is it possible?