Mapeando tus movimientos con React y Leaflet
Tags: react, javascript, mapping, leaflet
Published: 2020-02-24 12:12:45

Hoy en día usamos mapas para todo… para buscar direcciones, consultar cuál es el mejor camino a tomar para llegar a un punto en concreto, para promocionar un local, o simplemente viajar desde casa (_asi es, he visto a youtubers que se pasan horas dando vueltas por paises gracias a los mapas… y hacen visitas!_)

Pues por ese motivo vamos a ver cómo podemos hacer un mapa con nuestros movimientos.

![Moves](https://dev-to-uploads.s3.amazonaws.com/i/3qhcajjuwqmr6k6y6g1q.png)
<figcaption>Moves app</figcaption>

# Moves
Para registrar los movimientos, aunque hay otras, he usado la aplicación [moves](https://moves-app.com/).

Moves se ejecuta en segundo plano y nos permite importar tus movimientos en diferentes formatos, y uno de ellos es geojson.

Para empezar nos vamos a la página web de moves. Allí nos permitirá importar lo registrado desde nuestro dispositivo.

# Configuración

Lo primero será instalar los paquetes de **leaflet** y **react-leaflet**:

```bash
$ npm -i S leaflet react-leaflet
```

[React-leaflet](https://react-leaflet.js.org/) lo que hace es cargar componentes pero sin renderizar nada, simplemente usa los métodos de _leaflet_ en el _lifecycle_ del componente.

Podríamos conseguir nuestro mapa sin react-leaflet pero lo he usado anteriormente y ayuda mucho.

# El mapa

Ya estamos listos para empezar así que lo primero será importar los paquetes que vamos a necesitar.

```js
import { Map, TileLayer } from 'react-leaflet';
import L from 'leaflet';
```

De momento solo he importado dos componentes de react-leaflet: Map y TileLayer. Esto es lo básico que necesitarás para mostrar un mapa.

También he importado leaflet porque vamos a usar el método circleMarker para poder tratar los puntos de los geojsons de nuestros datos.

## Map

Capa principal del mapa que controla el zoom, bordes y el centro. Lo que vayamos a representar en el mapa, lo pasaremos como hijos.

## TileLayer

Componente que se encargará de mostrar los tiles correspondientes en base al zoom y al centro.

Este componente necesita la propiedad url que será al montarse.

Para este ejemplo, voy a usar un mapa en blanco y negro, pero puedes encontrar mas urls [aquí](https://leaflet-extras.github.io/leaflet-providers/preview/).

```
https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}{r}.png
```

Ah! Antes de poder usar nuestro mapa, necesitaremos importar el css de leaflet, que puedes encontrar en su apartado de [descargas](https://leafletjs.com/download.html).

Configurados estos dos componentes, deberíamos de tener algo muy parecido a esto:

{% gist https://gist.github.com/ayozebarrera/f62bcab8e0d61e6f25ec2d647d3d96d4.js %}

![Map](https://dev-to-uploads.s3.amazonaws.com/i/oc1lg5bknvrnjualxo41.png)

Tanto rollo para tener un mapa vacío?

Calma… ahora viene lo bueno 😁


# Nuestros movimientos

Moves, aparte de ofrecerte muchos formatos, también te separa los datos en movimientos diarios, semanales, mensuales, anuales y por último, todos en un mismo fichero. Yo voy a utilizar mis lugares visitados separados por años. En concreto los de 2016, 2017 y 2018.

Para ello voy a usar una capa de GeoJSON de leaflet, que como no, también lo tenemos como componente en react-leaflet:

```js
import { Map, TileLayer, GeoJSON } from 'react-leaflet';
```

El siguiente paso sería importar los datos de nuestros movimientos:

```js
import places2016 from './data/places_2016.js';
import places2017 from './data/places_2017.js';
import places2018 from './data/places_2018.js';
```

Después, tenemos que usar el componente GeoJSON como un **children** más en nuestro component Map:

```html
<Map style={styles.map} center={props.center} zoom={props.zoom}>
  <TileLayer url={props.url} />
  <GeoJSON
    data={places2016}
  />
</Map>
```

Además de pasarle los datos a la capa GeoJSON, el componente necesita la propiedad style, que es una función que usará internamente para aplicar el style que queramos a cada elemento de nuestro geojson:

```js
function getStyle(feature, layer) {
  return {
    weight: 1,
    opacity: 1,
    color: '#000'
  }
}
```

**Cuidado!** La función anterior solo te servirá para elementos que NO sean de tipo Point.

Dentro de mis geojsons, solo tengo elementos de tipo Point, asi necesitaré utilizar una propiedad extra: **pointToLayer**.

```js
const geojsonMarkerOptions = {
  radius: 4,
  fillColor: "#EE4266",
  color: "#000",
  weight: 0,
  opacity: 1,
  fillOpacity: 0.4
}

function pointToLayer(feature, latlng) {
  return L.circleMarker(latlng, geojsonMarkerOptions);
}
```

En mi caso, el componente GeoJSON se queda de la siguiente manera:

```html
<GeoJSON
  data={places2016}
  pointToLayer={pointToLayer}
/>
```

Ya casi terminamos!

Como voy a representar tres geojsons diferentes, y quiero representarlos con diferentes colores, tengo que crear tres funciones diferentes de pointToLayer

```html
<Map style={styles.map} center={props.center} zoom={props.zoom}>
  <TileLayer url={props.url} />
  <GeoJSON
    data={places2016}
    pointToLayer={pointToLayer2016}
  />
  <GeoJSON
    data={places2017}
    pointToLayer={pointToLayer2017}
  />
  <GeoJSON
    data={places2018}
    pointToLayer={pointToLayer2018}
  />
</Map>
```

Este es el resultado final del componente:


{% gist https://gist.github.com/ayozebarrera/0d67218a47fd367a4e8bde3d34e6b251 %}

_Voilá_, nuestro mapa estaría listo:

![Finished map](https://dev-to-uploads.s3.amazonaws.com/i/1ru87n8qkj0rsnf6si4l.png)

Nos vemos en la próxima batalla!

🖖🏼