0

enter image description here

Here, I would want to wrap the circle with a PanGestureHandler, make it draggable and snap to the X mark if it goes near it.

The part that confuses me is when dragging I'm using the translationX and translationY values to move the circle around which means it will always start at (0,0). How do we find the translateX and translateY values of the X mark for the circle? i.e. what translateX and translateY of circle will make it snap to the X value - how do we find this? I have the absoluteX and absoluteY values for X mark and the circle but unsure how to translate the absolute values to the translation values.

Am I over complicating this? Is there an easy way to go about this?

rohanharikr
  • 1,201
  • 1
  • 13
  • 28
  • Are you looking for a function that will tell you if the snap point is within a certain distance of the circle? Or just how to get the absolute values of the circle after translation? – Abe Jul 11 '22 at 14:52
  • @Abe To be honest, I am not really sure how this is implemented. The objective here is that you can drag the circle and if the circle is withing +10 radius of the X mark, then it snaps to the center of the X mark. – rohanharikr Jul 11 '22 at 19:56
  • Here's an easy solution with a rectangle. You can find good circle testing algorithms in geospatial applications. `if (Math.abs(currentX - targetX) < 10 && Math.abs(currentY - targetY) < 10) { // give x and y offset withTiming animations }` – Abe Jul 12 '22 at 06:11
  • Hmm Im still not sure how this is implemented - could you please provide a very minimal example. It can be just on click of circle -> it animated to the X mark (no drag needed). – rohanharikr Jul 13 '22 at 14:49

1 Answers1

0

You can pass this example code to your project, after that some thing may be clarify for you how does it work. 10-20min some tests and gaming with example and you can to run your application as need for you project

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Animated, {
  useAnimatedGestureHandler,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from 'react-native-reanimated';

import {
  GestureHandlerRootView,
  PanGestureHandler,
  PanGestureHandlerGestureEvent,
} from 'react-native-gesture-handler';

const SIZE = 100.0;
const CIRCLE_RADIUS = SIZE * 2;

type ContextType = {
  translateX: number;
  translateY: number;
};

export default function App() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const panGestureEvent = useAnimatedGestureHandler<
    PanGestureHandlerGestureEvent,
    ContextType
  >({
    onStart: (event, context) => {
      context.translateX = translateX.value;
      context.translateY = translateY.value;
    },
    onActive: (event, context) => {
      translateX.value = event.translationX + context.translateX;
      translateY.value = event.translationY + context.translateY;
    },
    onEnd: () => {
      const distance = Math.sqrt(translateX.value ** 2 + translateY.value ** 2);

      if (distance < CIRCLE_RADIUS + SIZE / 2) {
        translateX.value = withSpring(0);
        translateY.value = withSpring(0);
      }
    },
  });

  const rStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateX: translateX.value,
        },
        {
          translateY: translateY.value,
        },
      ],
    };
  });

  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <View style={styles.container}>
        <View style={styles.circle}>
          <PanGestureHandler onGestureEvent={panGestureEvent}>
            <Animated.View style={[styles.square, rStyle]} />
          </PanGestureHandler>
        </View>
      </View>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  square: {
    width: SIZE,
    height: SIZE,
    backgroundColor: 'rgba(0, 0, 256, 0.5)',
    borderRadius: 20,
  },
  circle: {
    width: CIRCLE_RADIUS * 2,
    height: CIRCLE_RADIUS * 2,
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: CIRCLE_RADIUS,
    borderWidth: 5,
    borderColor: 'rgba(0, 0, 256, 0.5)',
  },
});

I hope its help you.

Ilya Ezy
  • 34
  • 2
  • Thank for you for this, but this is not what I am looking for. I'm looking something specific to this case - where the circle snaps to a point on the screen. Here, I believe there isn't a snap logic but only this - if distance covered by circle is > or < something, do something. – rohanharikr Jul 11 '22 at 10:04
  • You can use {}} /> for get size and coordinates you own View, after that u can pass these properties to your Circle for bind these values/coordinates – Ilya Ezy Jul 11 '22 at 10:30
  • Okay, but I would be getting the absolute values right? How would I convert the absolute values of the X mark to the translation values of the circle? – rohanharikr Jul 11 '22 at 10:32
  • You need to get coordinates X-mark and get coordinates Circle , using onLayout() callback, after that move Circle to X mark coordinates, maybe you will need position: 'absolute' style for Circle – Ilya Ezy Jul 11 '22 at 12:57
  • I'm unsure of how to implement this - can you please give me an example code when free? – rohanharikr Jul 11 '22 at 13:10