Cómo escuchar el movimiento del usuario y contar su distancia en React Expo

Si eres nuevo en React Expo y deseas rastrear la distancia recorrida por un usuario, este artículo te proporcionará una guía y soluciones a algunos problemas comunes que podrías enfrentar.

Funcionalidades a Implementar

  1. Permiso de Localización: Solicitar permiso al usuario para acceder a su ubicación.
  2. Rastreo de Distancia: Iniciar el seguimiento de la distancia que el usuario ha caminado/corrido al hacer clic en un botón y detenerlo al presionar otro botón.

Problemas Comunes

Al implementar esta funcionalidad, es posible que te encuentres con problemas, como:

  • Inexactitud en la distancia calculada: A veces, la distancia que se muestra puede no ser precisa.
  • Incremento de la distancia mientras se está detenido: El sistema podría seguir sumando distancia aunque el usuario no se esté moviendo.

Solución Propuesta

A continuación, se detalla el código que puedes utilizar para implementar el rastreo de distancia y algunas mejoras que se pueden realizar:

const MIN_MOVEMENT_THRESHOLD = 1; // Ignorar movimientos menores de 1 metro

// Fórmula de Haversine para calcular distancia en metros
const getDistance = (lat1, lon1, lat2, lon2) => {
  const R = 6371000; // Radio de la Tierra en metros
  const toRad = angle => (angle * Math.PI) / 180;

  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);

  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2);

  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

  return R * c;
};

export function RouteMapScreen({ route }) {
  const mapInView = route.params.chosenMap;
  const [isTracking, setIsTracking] = useState(false);
  const [totalDistance, setTotalDistance] = useState(0);
  const lastLocationRef = useRef(null); // Persistir ubicación previa

  useEffect(() => {
    let locationSubscription = null;

    const startTracking = async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== "granted") {
        console.log("Permiso para acceder a la ubicación denegado");
        return;
      }

      locationSubscription = await Location.watchPositionAsync(
        { 
          accuracy: Location.Accuracy.Highest, 
          distanceInterval: 1, 
          timeInterval: 1000  
        },
        (location) => {
          // Ignorar actualizaciones cuando está detenido o moviéndose lentamente
          if (location.coords.speed !== null && location.coords.speed < 0.5) {
            return;
          }

          if (lastLocationRef.current) {
            const distance = getDistance(
              lastLocationRef.current.coords.latitude,
              lastLocationRef.current.coords.longitude,
              location.coords.latitude,
              location.coords.longitude
            );

            // Solo añadir la distancia si es mayor que el umbral
            if (distance > MIN_MOVEMENT_THRESHOLD) {
              setTotalDistance((prev) => prev + distance);
            }
          }

          lastLocationRef.current = location;
        }
      );
    };

    if (isTracking) {
      startTracking();
    }

    return () => {
      if (locationSubscription) {
        locationSubscription.remove();
      }
    };
  }, [isTracking]);

  return (
    <>
      <View style={styles.mapActions}>
        <Text>Run</Text>
        <Pressable android_ripple={{ color: "darkred" }} onPress={() => setIsTracking(false)}>
          <Text>END</Text>
        </Pressable>
      </View>
      <Text>Distance: {totalDistance.toFixed(2)} meters</Text>
      <View style={styles.mapArea}></View>
      <Pressable android_ripple={{ color: "darkred" }} onPress={() => setIsTracking(true)}>
        <Text>START</Text>
      </Pressable>
    </>
  );
}

Mejoras Clave

  1. Métrica de Movimiento: Se utiliza un umbral mínimo (MIN_MOVEMENT_THRESHOLD) para ignorar movimientos que no son significativos.
  2. Control de Velocidad: Asegúrate de que el cálculo de la distancia se realice solo si el usuario está en movimiento significativo.

Aplicando estos conceptos y el código proporcionado, podrás rastrear de manera efectiva la distancia recorrida por un usuario en una aplicación de React Expo. Asegúrate de probar en diferentes entornos para validar la precisión del seguimiento.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *