DEV Community

Cover image for Developing Geonotes — Maps and the PostGIS extension — Ep. 2
Emilio Schepis
Emilio Schepis

Posted on

Developing Geonotes — Maps and the PostGIS extension — Ep. 2

With the local infrastructure completed in Episode 1, it is time to add the main map to Geonotes.

 📱 Adding a map to the main screen

On the client, the first step was to add a map to the main screen. Fortunately, Expo supports a library out of the box: React Native Maps.

With this library, a MapKit instance is created on iOS, while Android uses Google Maps. The props interface is the same across both platforms.

One thing I really like about RNM is that it has built-in support for requesting permissions. Originally I thought I'd do it with Expo Location but so far I haven't felt the need to switch to a dedicated location library.

RNM is able to request the current location of the user, and then display it directly on the map. Adding the followsUserLocation prop and blocking the various movements, I was able to center the map on the user and update the visible region when they move.

This also allows me to listen to the onRegionChangeComplete event and extract the current location.

In order not to perform too many queries against the database, the current location is only updated when the user moves more than a given distance from the last location.

🌍 Measuring the distance client-side and in queries

To measure the distance between the last and the current location of the user, I decided to use the "Equirectangular approximation" that should have plenty of precision over relatively small distances.

The implementation is as follows Source:

const R = 6371e3; // Earth's radius
const lat1 = (location1.latitude * Math.PI) / 180;
const lat2 = (location2.latitude * Math.PI) / 180;
const lon1 = (location1.longitude * Math.PI) / 180;
const lon2 = (location2.longitude * Math.PI) / 180;

const deltaLat = lat2 - lat1;
const deltaLon = lon2 - lon1;

const x = deltaLon * Math.cos((lat1 + lat2) / 2);
const y = deltaLat;

return Math.sqrt(x * x + y * y) * R;
Enter fullscreen mode Exit fullscreen mode

On the server, however, I needed something more battle-tested and performant.

Since Hasura uses PostgreSQL as a database, I decided to use the PostGIS extension. Another option I have considered is the GeoHash algorithm, but PostGIS has a much better integration with the current stack.

With PostGIS enabled, I set the "location" column in the "note" table as geography, which allows me to perform queries like this Source:

query Notes($latitude: Float!, $longitude: Float!, $distance: Float! = 100) {
  notes: note(
    where: {
      location: {
        _st_d_within: {
          distance: $distance
          from: { type: "Point", coordinates: [$longitude, $latitude] }
        }
      }
    }
  ) {
    id
    content
    location
  }
}
Enter fullscreen mode Exit fullscreen mode

⭐️ The result

Ultimately, I was able to query notes in a range around the user, and have those notes update as the user moved.

First location Second location
Screen Shot 2021-08-02 at 09.46.22.png Screen Shot 2021-08-02 at 09.46.11.png

🚧 Next steps

Now it is time to work a bit on the presentation of the various notes. My current plan is to show a small callout when a note is tapped, and then display a bottom sheet with the full information / actions.

🎙 How to follow the project

I'll be posting updates throughout the development process and as I learn new thing regarding development, design, and marketing.

If you'd like to have even more real-time updates you can

Discussion (0)