rocktheartsm4l
rocktheartsm4l

Reputation: 2187

How to persist locations from getCurrentPositionAsync on user's device accurately?

I'm trying to build some functionality similar to what you see on Strava. While the user is recording i want to track their route and save it for them to do things with later.

I'm using latest compatible versions for expo, react native, etc.. I'm using expo-location and then react-native-maps to display the data. Also using turf to format as geojson.

The issue i'm running into is that on some routes the points seem to be getting mixed up, half the route will be great then there will be a bunch of super crazy zig zag sections. I'm going to add a photo with street names and such marked out for privacy reasons.enter image description here

Struggling to debug this, i'm unsure if the issue is with how i'm tracking the data using expo-location, the global-scope cache object, how i'm displaying it, or what?

Idea is that i want to keep it on device till they finish recording and decide to save or not, then persist it.

Here is my code for route tracking:

const LOCATION_TRACKING = "background-location-tracking";
export const TRACKING_STATE_QUERY_KEY = ["route-tracking-state"];
const COORDS_STORAGE_KEY = "@route_tracking/coordinates";

const coordsCache: { coords: [number, number][] } = { coords: [] };

TaskManager.defineTask<{ locations: Location.LocationObject[] } | undefined>(
  LOCATION_TRACKING,
  async ({ data, error }) => {
    if (error) {
      console.error(error);
      return;
    }
    if (data) {
      const { locations } = data;
      for (const location of locations) {
        const coord: [number, number] = [
          location.coords.longitude,
          location.coords.latitude,
        ];
        coordsCache.coords.push(coord);
        if (coordsCache.coords.length % 10 === 0) {
          await AsyncStorage.setItem(
            COORDS_STORAGE_KEY,
            JSON.stringify(coordsCache.coords),
          );
        }
      }
    }
  },
);

this is how i am starting that task:

await Location.startLocationUpdatesAsync(LOCATION_TRACKING, {
  accuracy: Location.Accuracy.BestForNavigation,
  timeInterval: 1000,
  distanceInterval: 1,
  showsBackgroundLocationIndicator: true,
  foregroundService: {
    notificationTitle: "Route Tracking",
    notificationBody: "Recording your sesh",
  },
});

and here is the code for displaying the map

<MapView
  style={{ height: "100%", width: "100%" }}
  initialRegion={{
    /* eslint-disable @typescript-eslint/no-non-null-assertion */
    latitude:
      routeGeoJson.features[0]!.geometry.coordinates[0]![1]!,
    longitude:
      routeGeoJson.features[0]!.geometry.coordinates[0]![0]!,
    /* eslint-enable @typescript-eslint/no-non-null-assertion */
    latitudeDelta: 0.01,
    longitudeDelta: 0.01,
  }}
  zoomEnabled={false}
  rotateEnabled={false}
  scrollEnabled={false}
  pitchEnabled={false}
>
  <Geojson
    geojson={routeGeoJson}
    strokeColor="#22c55e"
    strokeWidth={3}
  />
</MapView>

routeGeoJson is a geojson lineString generated like this:

      getRouteGeoJson: async () => {
        const stored = await AsyncStorage.getItem(COORDS_STORAGE_KEY);
        if (!stored) return null;
        const coordinates = JSON.parse(stored) as [number, number][];
        const lineString = turf.lineString(coordinates);
        return turf.featureCollection([lineString]);
      },

Upvotes: 0

Views: 17

Answers (0)

Related Questions