Developing Geonotes — Maps and the PostGIS extension — Ep. 2
Tags: javascript, react, graphql, coding
Published: 2021-08-03 05:36:23

With the local infrastructure completed in [Episode 1](https://dev.to/emilioschepis/developing-geonotes-adding-authentication-and-connecting-to-graphql-ep-1-48ep), 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](https://docs.expo.dev/versions/latest/sdk/map-view/).

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](https://docs.expo.dev/versions/latest/sdk/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](https://www.movable-type.co.uk/scripts/latlong.html#equirectangular)" that should have plenty of precision over relatively small distances.

The implementation is as follows [Source](https://github.com/emilioschepis/geonotes-app/blob/cf86d2272e5d81e14027158646e667af05116eea/src/utils/locationUtils.ts#L3-L30):
```typescript
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;
```

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](https://postgis.net/) 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](https://github.com/emilioschepis/geonotes-app/blob/2331ef3a678c88e8924c36c6c2ab5b30c08c1913/src/graphql/queries.graphql#L1-L16):

```graphql
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
  }
}
```

## ⭐️ 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1627890454908/ftw3ugSLh.png) | ![Screen Shot 2021-08-02 at 09.46.11.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627890466494/IU9IKGYjG.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

- [Follow me on Twitter @emilioschepis](https://twitter.com/emilioschepis)
- Checkout the public GitHub [app repository](https://github.com/emilioschepis/geonotes-app/tree/develop) and [backend repository](https://github.com/emilioschepis/geonotes-backend/tree/develop)