pmndrs / use-gesture

👇Bread n butter utility for component-tied mouse/touch gestures in React and Vanilla Javascript.

Home Page:https://use-gesture.netlify.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.