Skip to content

Focal and anchor points are not in the coordinate space of the view on web #2929

Open
@j-piasecki

Description

@j-piasecki

Description

On Android and iOS the focal (for pinch) and anchor (for rotation) points are always in the coordinate space of the view, while on web they are not. It looks like they are in the window coordinate space, though I didn't investigate it that thoroughly.

Untitled.mov

Steps to reproduce

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
  useAnimatedStyle,
  useSharedValue,
} from 'react-native-reanimated';

function Pointer(props: { x: number; y: number }) {
  return (
    <View
      style={{
        position: 'absolute',
        left: props.x,
        top: props.y,
        width: 16,
        height: 16,
        borderRadius: 8,
        backgroundColor: 'red',
        transform: [{ translateX: -8 }, { translateY: -8 }],
      }}
    />
  );
}

export default function EmptyExample() {
  const translation = useSharedValue({ x: 0, y: 0 });

  const style = useAnimatedStyle(() => {
    return {
      transform: [
        { translateX: translation.value.x },
        { translateY: translation.value.y },
      ],
    };
  });

  const [pointerPos, setPointerPos] = React.useState({ x: 100, y: 100 });
  const [pointerVisible, setPointerVisible] = React.useState(false);

  const pan = Gesture.Pan()
    .averageTouches(true)
    .onChange((e) => {
      translation.value = {
        x: translation.value.x + e.changeX,
        y: translation.value.y + e.changeY,
      };
    });

  const pinch = Gesture.Pinch()
    .onStart((e) => {
      setPointerVisible(true);
      setPointerPos({ x: e.focalX, y: e.focalY });
    })
    .onEnd(() => {
      setPointerVisible(false);
    })
    .runOnJS(true);

  const rotation = Gesture.Rotation()
    .onStart((e) => {
      setPointerVisible(true);
      setPointerPos({ x: e.anchorX, y: e.anchorY });
    })
    .onEnd(() => {
      setPointerVisible(false);
    })
    .runOnJS(true);

  return (
    <View style={styles.container}>
      <GestureDetector gesture={Gesture.Simultaneous(pan, rotation)}>
        <Animated.View
          style={[style, { width: 200, height: 200, backgroundColor: 'blue' }]}>
          {pointerVisible && <Pointer x={pointerPos.x} y={pointerPos.y} />}
        </Animated.View>
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

The above snippet will render a red point at the relevant point (replace pinch/rotation in detector prop to see the other gesture). It should only change based on the position of the pointer relevant to the blue square, but it's also dependent on its position on the screen and that causes it to move outside the view.

Snack or a link to a repository

https://github.com/software-mansion/react-native-gesture-handler ❤️

Gesture Handler version

main branch

React Native version

0.74.1

Platforms

Web

JavaScript runtime

None

Workflow

Expo managed workflow

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

None

Device model

No response

Acknowledgements

Yes

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions