Delegate drag to remaining finger after pinch or support multi-finger drag
gustavopch opened this issue · comments
Describe the bug
Suppose you start dragging a box. The gesture has only one finger initially. Then you use a second finger to start pinching. Although you're using 2 fingers, it's the first one who's responsible for the drag, so if you stop pinching by removing the second finger (and keep moving the first one), the drag will continue happening, but if instead you stop pinching by removing the first finger (and keep moving the second one), your attempt to keep dragging will be ignored.
It's a bit strange because my intuition says I should be able to keep dragging regardless of which finger I removed from the screen after a pinch.
I think it would be nice if the second finger automatically assumed the drag, or a new drag was automatically started with the finger that remained on the screen.
Ideally though, I'd like multi-finger drags to be supported. I'm replacing a custom gesture implementation with @use-gesture/react
. In my implementation I would calculate the drag with the midpoint of all fingers touching the screen, so all of them would contribute to the drag. Isn't that something @use-gesture
could also do? It feels much better. At least my intuition says all my fingers should contribute. I don't intuitively think the whole drag should be performed by a single finger if I'm touching the screen with 2 or more.
P.S.: thanks for this awesome lib.
Information:
- Use Gesture version: 10.2.27
- Device: iPhone XR
- OS: iOS 16
- Browser: Safari
Checklist:
- I've read the documentation.
- If this is an issue with drag, I've tried setting
touch-action: none
to the draggable element.
Hey, thanks for the comment. Let me think about it.
Here's the implementation that I mentioned: https://gist.github.com/gustavopch/adcbe559eaa1efaeb42f2a81120536e1
As long as there's at least 1 finger on the screen, it considers a drag to be happening and calculates the midpoint between all fingers to determine the movement. You can see the delta is calculated as the difference between the current midpoint and previous midpoint. Of course, when you add or remove a finger, the midpoint abruptly changes, but we know it's not because of a real, intentional movement. So whenever the quantity of fingers change, the previous midpoint is reset to null, forcing the delta to be zero instead of generating an abrupt delta.
if (events[0].buttons === 1) {
// ...
const midPointX =
events.reduce((value, event) => {
return value + event.pageX
}, 0) / events.length
const midPointY =
events.reduce((value, event) => {
return value + event.pageY
}, 0) / events.length
if (events.length !== prevEvents.length) {
prevMidPointX = null
prevMidPointY = null
}
if (prevMidPointX != null && prevMidPointY != null) {
delta.panX += midPointX - prevMidPointX
delta.panY += midPointY - prevMidPointY
}
This is nowhere near the complexity of @use-gesture
, but I hope it can illustrate what's on my mind.