-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restore d3.{mouse,touch,touches}; add d3.pointers. #253
Conversation
I explicitly did not bring back the implicit pulling out of event.changedTouches[0] in d3.mouse, since that still feels too surprising. |
Re: changedTouches it's nice to be able to query the position on touchend / dbltap. This is useful for example for a dbltap to launch a zoom at the right place in d3-zoom, as we do in https://github.com/d3/d3-zoom/blob/523ccff340187a3e3c044eaa4d4a7391ea97272b/src/zoom.js#L350 |
Not sure what you’re saying. Are you suggesting we want to call d3.mouse here and have it pull out event.changedTouches[0]? |
Yes, I'd prefer to know where an event happened with d3.mouse(event). With the current proposal, on mouseup and pointerup events, d3.mouse return [x, y], but on touchend it returns [NaN, NaN]. |
It’s doesn’t make sense to call d3.mouse on a touch event, though; that’s not a mouse event. If the spec authors had thought it appropriate to give a TouchEvent a “primary” pointer, they would have put event.clientX and event.clientY properties on the TouchEvent. They didn’t, so it feels inappropriate for us to magically pull out the first changed touch, and it’s almost certainly an indication of a broken touch implementation if the caller were to do so (since it ignores the other touches). |
I understand this choice on principles. My point is that in practice this makes the "one-finger touch" case more difficult than necessary when you don't need fancy multitouch (for example https://observablehq.com/@d3/delaunay-find reacts on click and mousemove, but could get the "touchmove" for free if this worked). Also, it doesn't help with multitouch. However, a good solution might be to use pointer events instead (https://observablehq.com/d/d86d69071bef1f76):
|
Well, you already get touchmove for free because of emulated mouse events, albeit the emulated mousemove doesn’t occur until after the touch gesture ends. And if you want to handle touchmove events directly, it’s never strictly free because you still have to explicitly listen for them (i.e. replacing .on("mousemove", (event, context) => draw(context, delaunay.find(...d3.pointer(event))))
.on("touchmove", (event, context) => draw(context, delaunay.find(...d3.pointer(event.touches[0])))) I think the “ideal” behavior for this particular example would be to plot multiple points simultaneously if there are multiple touches. Something like: .on("mousemove", (event, context) => find(context, [d3.pointer(event)]))
.on("touchmove", (event, context) => find(context, d3.pointers(event.touches))) Obviously that’s trickier to do for the animation case, since you’d need to track concurrent animations, ideally for each touch independently. But my point is that you have a relatively easy way to just use a single touch, if that’s what you want. And I don’t think it’s a good idea for D3 to apply that logic for you automatically because it’s usually wrong. |
That's a great start for a documentation! Here's a different point of view, on d3.pointers, which might be less wrong than my previous argument on d3.mouse. Let's say I've coded a "multitouch-first"
or in a drag behavior: Wouldn't it help if we could just call |
Okay, I’m thinking about an alternative where d3.pointer does the sourceEvent traversal, and so does d3.pointers, but d3.pointers can also optionally take a TouchList directly, and if given a non-touch event, returns a single-element array. I think that would be reasonably straightforward and convenient. There’s the remaining question of whether we want a d3.touch method that pulls out the touch with a particular identifier, but I don’t expect that’s needed often so maybe it’s fine to remove. Also in some sense I think it’s better to not provide a non-backwards-compatible d3.mouse method because it’ll be more obvious that the code needs to be changed to upgrade. |
Excellent! Yeah I don't think we need d3.touch(…identifier). At this level of detail one would work with the actual events (or with pointer events https://observablehq.com/@fil/pointer-events#trackPointer). It will be much simpler to have to learn only d3.pointer (for single touch) and pointers (if multitouch is possible). |
Closing in favor of #255. |
Needs documentation (and tests, ideally).