react-native-gesture-handler icon indicating copy to clipboard operation
react-native-gesture-handler copied to clipboard

[Web] Fix `anchor` and `focal` points.

Open m-bert opened this issue 2 months ago • 0 comments

Description

On web, anchor and focal points are calculated with respect to window, not the actual handlers' view. This PR changes this behavior so that both of these points are calculated correctly.

Fixes #2929.

Test plan

Tested on example app and example from #2929

Test code
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',
  },
});

m-bert avatar Jun 03 '24 13:06 m-bert