Leaflet en React Apps

leafletjs-card

Leaflet es una librería de JavaScript de código abierto para mapas interactivos. La librería contiene varias funciones para generar un mapa y mostrar diferentes componentes en él como por ejemplo capas, marcadores, polilíneas, ventanas emergentes, animaciones del mapa  y de los objetos en él, controles del mapa, y características de personalización por mencionar algunas características, así como funciones para manejar diferentes eventos en el mapa.

Para el caso de react, existe una librería llamada react-leaflet, que provee a React con componentes para Leaflet.  En este post realizaremos un breve tutorial para empezar a utilizar dichas librerías.

Para descargar la librería ‘react-leaflet’ utilizamos el siguiente comando:

npm install react-leaflet

React, ReactDOM y Leaflet son dependencias requeridas, si no han sido instaladas, se pueden agregar a la app a través de:

npm install leaflet react react-dom

Agregamos el siguiente link en el archivo index.html para que nuestro mapa se visualice correctamente :

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"  integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin=""/>

La librería contiene elementos de Leaflet para React  los cuales requieren una instancia del mapa y, por lo tanto, deben incluirse en un componente <Map> de nivel superior. Para poder utilizarlo importamos el componente de ‘react-leaflet’ agregando la dependencia en la parte superior del archivo:

import { Map } from 'react-leaflet';

Es importante asegurarnos de que el contenedor del mapa tiene un alto definido. Esto se puede realizar a través de CSS, por ejemplo:

#mapid { height: 450px; }

El código para mostrar nuestro mapa quedaría de la siguiente manera:

import React, { Component } from 'react';

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

import './App.css';


let position;

let zoomMap;



class App extends Component {

constructor() {

   super();

   this.state = {

     lat: 29.0667,

     lng: -110.9667,

     zoom: 11,

   };

 }



render() {

   const { lat, lng, zoom } = this.state;


   position = [lat, lng];

   zoomMap = zoom;

   return (

     <Map center={position} zoom={zoomMap} id="mapid" ref={e => { this.mapInstance = e }}>

       <TileLayer

         attribution="&amp;copy <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"

         url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"

       />

     </Map>

   );

 }

}

export default App;

Como podemos observar, en el ejemplo definimos un zoom y punto que marcamos como el centro de nuestro mapa además de la referencia al mapa. Al ejecutar la app, podemos ver el mapa inicializado.

Para agregar un marcador, con su ventana emergente y una pequeña descripción importamos Marker, Popup y Tooltip y nuestra dependencia queda de la siguiente manera:

import { Map, TileLayer, Marker, Popup, Tooltip } from 'react-leaflet';

Y dentro de nuestro componente <Map> agregamos <Marker> y le indicamos mediante ‘position’ la latitud y la longitud donde deseamos que se visualice el icono. En este caso utilizamos el centro que definimos con anterioridad. Nuestro código queda de la siguiente manera:

<Map center={position} zoom={zoomMap} id="mapid" ref={e => { this.mapInstance = e }}>

       <TileLayer

         attribution="&amp;copy <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"

         url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"

       />

       <Marker position={position} >

          </Marker>

     </Map>

Para agregar los otros componentes (Tooltip y Popup), los definimos dentro del componente <Marker> de la siguiente forma:

<Marker position={position} >

         <Tooltip direction='top' opacity={1} >

           <span> Tooltip del marcador de ejemplo </span>

         </Tooltip>

         <Popup>

           <span> Popup del marcador de ejemplo </span>

         </Popup>

       </Marker>

Al pasar el mouse sobre el marcador podemos observar el tooltip que declaramos

Y al dar click en el marcador se visualiza la información que definimos dentro del componente de ‘Popup’


El marcador tiene el icono predefinido, si deseamos cambiar de marcador  declaramos un objeto de la librería de ‘leaflet’ y creamos una constante de tipo icono con la url de la imagen que deseamos utilizar como marcador, así como el tamaño del icono, y la relación del popup y del tooltip con respecto a la imagen utilizada.

import L from 'leaflet';

const iconVerde = new L.Icon({

   iconUrl: require('./pinVerde.png'),

   iconSize:     [40, 45], // tamaño del icono

   shadowSize:   [50, 64], // tamaño de la sombra

   iconAnchor:   [20, 40], // punto del icono que corresponde a la posición del marcador

   popupAnchor:  [0, -40] // punto relativo al marcador desde donde se deberá abrir el popup

});

Para indicarle al mapa que deberá utilizar el icono que se ha definido en el componente <Marker> se agrega la propiedad icon’ y se iguala a la constante declarada. En este caso:

<Marker position={position}  icon={iconVerde} >

         <Tooltip direction='top' opacity={1} >

           <span> Tooltip del marcador de ejemplo </span>

         </Tooltip>

         <Popup>

           <span> Popup del marcador de ejemplo </span>

         </Popup>

       </Marker>

     </Map>

Guardamos los cambios y podemos observar el marcador con el icono que seleccionamos:

Tanto React como Leaflet están diseñados para manejar sus propios estados. React monitorea el estado de su DOM virtual, actualizando el árbol según sea necesario, mientras que los mapas de Leaflet mantienen su propio estado y permiten cambios al DOM mediante DomUtil (funciones internas de Leaflet que le permiten comunicarse con el DOM) . Por lo tanto, para actualizar el estado del mapa a través de eventos y estados en React, se puede utilizar el atributo ‘ref ‘de React, el cual nos permite acceder al DOM del elemento que contiene la etiqueta ‘ref’. En nuestro caso declaramos la propiedad en el componente <Map> de la siguiente forma:

ref={e => { this.mapInstance = e }}

Para poder modificar el nivel de zoom del mapa o el centro del mismo cuando hemos estado explorando la pantalla, agregamos un ‘event listener’ en el método componentDidMount de la siguiente forma:

componentDidMount() {

   this.map = this.mapInstance.leafletElement;

 }

Leaflet cuenta con diferentes métodos que modifican el estado del mapa. Entre ellos se encuentran setView, setZoom, fitBounds, flyTo y flyToBounds, por mencionar algunos. Para hacer uso de ellos, utilizamos el event listener previamente declarado, en este caso utilizaremos flyTo, método que requiere de la posición (latitud y longitud) hacia la cual se desea que se mueva el mapa, el zoom que tendrá el mapa (puede o no ir indicado) y opciones del zoom/pan (puede o no ir indicado) y utilizaremos como valores, las opciones definidas inicialmente.

resetCenter() {

   const { lat, lng, zoom } = this.state;

   position = [lat, lng];

   this.map.flyTo(position, zoom)

 }

Agregamos un botón que llame a la función declarada y cuando navegamos en el mapa o modificamos el zoom y deseamos volver a la posición en el mapa, hacemos click en el botón y la vista del mapa se modifica hacia el punto que hemos definido.

Los métodos y propiedades de Leaflet se pueden consultar en la documentación oficial. React-Leaflet cuenta también con página, en ella podemos encontrar ejemplos, información y algunas guías para la utilización y creación de componentes de Leaflet para React.

1 Comment

Deja un comentario

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