force-graph icon indicating copy to clipboard operation
force-graph copied to clipboard

node hover-out event fired on Chrome when using touchscreen to longpress node

Open xlfe opened this issue 4 years ago • 5 comments

I've been doing some testing of different touch interactions, and came across a weird one where the hover event was getting called twice (ie hover in hover out) when I was doing a long press on a node on a laptop touch screen. I think it's because the drag sensitivity on a laptop might be different from on other devices?

Would it be possible to expose the drag sensitivity here to allow it to be set (with the intent that things like screen resolution, device type would be taken into account)

https://github.com/vasturiano/force-graph/blob/3f2aac755ab76e1950eb776e8b753639f77a1f62/src/force-graph.js#L505

Thank you!

xlfe avatar Aug 03 '21 06:08 xlfe

@xlfe thanks for surfacing this.

This is a tricky one. Ideally you'd want the component to handle these interactions correctly regardless of the device, so I'd rather not make it a component setting, which would just pass on the dilemma to the consuming app.

But, for my understanding are you saying that 1) the drag got triggered when it shouldn't have or 2) the drag didn't trigger even though you were dragging a node?

Are you able to test what are the movementX/Y typical values per pointermove event in the touch device where you observed this issue? There is an interactive demo for this here: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX

vasturiano avatar Aug 04 '21 23:08 vasturiano

@vasturiano thanks for the link to the interactive demo - that's helped - I think what is happening is as follows

(this is on a laptop with a touch screen, in chrome)

mouse is somewhere on the canvas, but not near the node of interest I use the touch screen to long-press on the node of interest i get a hover-in and hover-out event with about ~200ms between them no click event is registered (even after touchend)

when I do the same thing in the mozilla interactive demo, this is the entries:-

movement: 0, 0
movement: -293, -14

Could it be that the initial pointerdown happens and the movement is then registered?

I'm not seeing a click event so the longpress isn't being registered either even after touchend. Infact I don't think I can consistently trigger a click event when I do a long-press on the node using a touch screen - I just see the hover-in hover-out

For comparison

  • same device, etc I can register a longpress click when I use the mouse though.
  • On iPad /Safari touch screen, I see a hover-in event for the same scenario but not a hover-out event. Longpress works fine.

xlfe avatar Aug 05 '21 02:08 xlfe

@xlfe thanks for this investigation.

So I think what is unusual with this case is that when you touch the screen it will register a large movement from the place where the cursor "currently" is. This is unlike a regular touch screen where the movement is 0,0 from the instant of the tap, because there is no concept of the pointer being in certain location. Sounds like this is a way to maintain a hybrid combo of mouse and touch controls for a single pointer. I don't currently own a device like that so it's difficult to test, but I'm interested to see if we can reach a general solution in this interaction that takes that case into account.

In any case, are you able to check what happens first when you touch the screen, the pointerdown or pointermove event?

vasturiano avatar Aug 06 '21 00:08 vasturiano

That sounds great

Testing on this page, when the cursor is somewhere else on the page and I use the touch-screen to tap the button, the log looks like

pointerover
pointerenter (0ms)
mouseover (0ms)
mouseenter (0ms)
pointermove (0ms)
mousemove (0ms)
pointerover (0ms)
pointerenter (0ms)
pointerdown (0ms)
touchstart (0ms)
gotpointercapture (56ms)
pointermove (0ms)
pointermove (11ms)
pointermove (10ms)
pointermove (20ms)
pointermove (10ms)
pointermove (19ms)
pointermove (10ms)
pointermove (20ms)
pointermove (20ms)
pointermove (9ms)
pointerup (40ms)
lostpointercapture (0ms)
pointerout (0ms)
pointerleave (0ms)
touchend (0ms)
mousemove (1ms)
mousedown (0ms)
focus (1ms)
mouseup (0ms)
click (0ms)

If i then tap somewhere else on the button (ie the cursor starts on the button) it looks like

pointerover
pointerenter (0ms)
mouseover (0ms)
mouseenter (0ms)
pointermove (0ms)
mousemove (0ms)
pointerover (0ms)
pointerenter (0ms)
pointerdown (0ms)
touchstart (0ms)
gotpointercapture (37ms)
pointerup (0ms)
lostpointercapture (0ms)
pointerout (0ms)
pointerleave (0ms)
touchend (0ms)
mousemove (1ms)
mousedown (0ms)
focus (1ms)
mouseup (0ms)
click (0ms)

xlfe avatar Aug 06 '21 03:08 xlfe

@xlfe thanks for checking that.

Thinking more about this, it seems the problem is not so much the hover-in and out events whenever touch-and-hold on a node, that is a standard behaviour that happens even with mouse cursors when the sequence of actions is 1) move pointer over the node (trigger hover-in), 2) press pointer down, and most importantly 3) drag the pointer (initiates drag and trigger hover-out).

In your case what may be happening is that it doesn't feel like you're doing step 3) but - while you're long-pressing - small changes are detected by drag module. Am I right to assume that if you don't long-press the node but simply tap, the click event triggers correctly?

We rely on d3-drag to detect drag interactions, on this section of the code: https://github.com/vasturiano/force-graph/blob/3f2aac755ab76e1950eb776e8b753639f77a1f62/src/force-graph.js#L400-L423

Are you able to test with d3-drag to see if drag interactions are involuntarily being triggered when you long-hold?

vasturiano avatar Aug 06 '21 10:08 vasturiano