d3 / d3-zoom

Pan and zoom SVG, HTML or Canvas using mouse or touch input.
https://d3js.org/d3-zoom
ISC License
507 stars 143 forks source link

Drag captures clickthrough when no mouse movement #93

Closed ZeeStorm closed 7 years ago

ZeeStorm commented 7 years ago

This is somewhat related to issue #92 , however the fixes listed do not seem to work when the event is a click. It appears that both Chrome and IE (the issue doesn't seem to happen in FF), is that a mousemove event is fired during a click event, in between mousedown and mouseup. On src/zoom.js line 249, it informs the event selection that the mouse has moved (which is not true) with g.moved = true;

To correct this behavior, I simply added a few lines before the noevent() on line 248:

var newMouse = mouse(g.that);
// if the mouse didn't actually move
if (g.mouse[0][0] === newMouse[0] && g.mouse[0][1] === newMouse[1]) {
  return;
}

I'm not entirely certain my fix is ideal, but it does allow me to properly capture the click event when no drag takes place. When the user actually does mousedown and then move the mouse, the zoom mousemove behavior functions as normal. Please review as I think this is the actual expected behavior, and the bug in browsers to fire mousemove when the mouse hasn't moved is the real problem.

Edit: I have pushed the change to my fork if you need to see the full change, as I was in need of this fix immediately: https://github.com/ZeeStorm/d3-zoom/commits/master

mbostock commented 7 years ago

This seems like a duplicate of #65 in that this solution generalizes to an arbitrary distance threshold.

ZeeStorm commented 7 years ago

I feel this is slightly different, considering my fix accounts for inconsistency with browsers to create the same behavior (in that mousemove shouldn't be fired in between a mousedown and mouseup event). If a mouse hasn't actually been moved in between the down and up event, how can you say it generalizes a distance threshold or say that it was a drag event? I'm simply trying to prevent a false positive on a drag event, since the code registers a movement when no movement occurred. If you still disagree, you may close this issue. Thanks

mbostock commented 7 years ago

Under the rubric that D3 is not a browser compatibility layer, I don’t think it makes sense to introduce a special-case to prevent zero-distance mousemove events from triggering a drag event. It is preferable to have a more direct mapping between the input events and the behavioral events. For one thing, it reduces the number of documented footnotes we need in the input event table.

I support an epsilon distance threshold for suppressing click, but that feature is not to address a browser idiosyncrasy; it is to allow a more robust disambiguation between click and drag. In contrast the change proposed here would introduce a difference in behavior for a zero distance mousemove and a less-than-epsilon distance mousemove.

gokulnath95 commented 5 years ago

hi , I have built a interactive graph tool using d3v3. recently , due to our project need i migrated my code from v3 to v4. while migrating faced some issues , but i migrated alomost 90% of my code.Basically , using this tool nodes and links can be created using mouse events . for example , shift + mouse click -> node will be created under mouse position .and link can be created by pressing shift and mousedown on source node and releasing mouse up on target node. this is where my problem is exactly. By pressing mouse down im able to get the mousedown node , but by releasing it on target node im not getting mouse up event call. After i made search ... i came to know that d3v4 has prevented mouse up event and giving the control to dragend. But i cannot use dragend because both the events are different. If i use dragend i am getting the same node data as that i got in mouse down event. So is there any solution to fix this , it will be very helpful

Thanks Gokul.