software-mansion / react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.
https://docs.swmansion.com/react-native-gesture-handler/
MIT License
6.12k stars 979 forks source link

The first time pinching between focal points works just fine but subsequently it pinching it seems a bit off. #2922

Closed moonaala closed 4 months ago

moonaala commented 5 months ago

Description

Help me fixing the issue with a function that uses react native gesture handler, the first time pinching between focal points works just fine but subsequently it pinching it seems a bit off.

Steps to reproduce

  1. Pinch on an image to zoom in or out.
  2. The first time, the focal points are captured perfectly and the pinching works well.
  3. The subsequent pinching make the focal points a bit off and the off distance is variant. Here is the code:
const panGesture = Gesture.Pan()
    .enabled(isPanEnabled)
    .minPointers(minPanPointers)
    .maxPointers(maxPanPointers)
    .onStart(event => {
      runOnJS(onPanStarted)(event);
      savedTranslate.x.value = translate.x.value;
      savedTranslate.y.value = translate.y.value;
    })
    .onUpdate(event => {
      translate.x.value = savedTranslate.x.value + event.translationX;
      translate.y.value = savedTranslate.y.value + event.translationY;
    })
    .onEnd((event, success) => {
      const rightLimit = limits.right(width, scale);
      const leftLimit = -rightLimit;
      const bottomLimit = limits.bottom(height, scale);
      const topLimit = -bottomLimit;

      if (scale.value > 1) {
        translate.x.value = withDecay(
          {
            velocity: event.velocityX * 0.6,
            rubberBandEffect: true,
            rubberBandFactor: 0.9,
            clamp: [leftLimit - focal.x.value, rightLimit - focal.x.value]
          },
          () => {
            if (event.velocityX >= event.velocityY) {
              runOnJS(onPanEnded)(event, success);
            }
          }
        );
        translate.y.value = withDecay(
          {
            velocity: event.velocityY * 0.6,
            rubberBandEffect: true,
            rubberBandFactor: 0.9,
            clamp: [topLimit - focal.y.value, bottomLimit - focal.y.value]
          },
          () => {
            if (event.velocityY > event.velocityX) {
              runOnJS(onPanEnded)(event, success);
            }
          }
        );
      } else {
        runOnJS(onPanEnded)(event, success);
      }
    });
const pinchGesture = Gesture.Pinch()
      .enabled(isPinchEnabled)
      .onStart(event => {
        runOnJS(onPinchStarted)(event);
        savedScale.value = scale.value;
        savedFocal.x.value = focal.x.value;
        savedFocal.y.value = focal.y.value;
        initialFocal.x.value = event.focalX;
        initialFocal.y.value = event.focalY;
      })
      .onUpdate(event => {
          scale.value = clamp(savedScale.value * event.scale, minScale, maxScale);
          focal.x.value =
            savedFocal.x.value +
            (center.x - initialFocal.x.value) * (scale.value - savedScale.value);
          focal.y.value =
            savedFocal.y.value +
            (center.y - initialFocal.y.value) * (scale.value - savedScale.value);
      })
      .onEnd((...args) => {
        runOnJS(onPinchEnded)(...args);
      });

Snack or a link to a repository

https://m.aala.pk/files/dozz8n3p1ifs9fsb9oaw3x3zce/public?h=x7jjZexzmZH4XWQYuc1YuMFzjP4AAkHhBMHf6wUdAD8

Gesture Handler version

2.16.1

React Native version

0.74.1

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

None

Architecture

Expo React native

Build type

Debug mode

Device

Real device

Device model

Any Android or iphone

Acknowledgements

Yes

github-actions[bot] commented 5 months ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

m-bert commented 5 months ago

Hi @moonaala! Could you please provide a copy-pastable reproduction (on snack/gist or as a link to github repository)? Those snippets use a lot of not provided variables which makes it hard to understand.

j-piasecki commented 5 months ago

To add to that, based on the video you've provided it looks like the first pinch gesture behaves correctly. This may indicate that there is a problem with the transformations you're applying. Keep in mind that the focal point is in the coordinate space of the view the detector is attached to. If you attach the detector directly to the view you're transforming, the focal point will be in the scaled coordinates.

You may want to take a look at this example which implements something similar: https://github.com/software-mansion/react-native-gesture-handler/blob/29e0ca95ceecdc1ea503e2a8414190ee091dfbda/example/src/new_api/transformations/index.tsx