Leaflet + React: publicando mapas interactivos en la web

React es una biblioteca de código abierto desarrollada por Facebook que se utiliza para construir interfaces de usuario. Por su parte, Leaflet es una biblioteca JavaScript que se utiliza para publicar mapas en la web. La combinación de ambas herramientas es sencilla, permitiendo crear mapas web dinámicos. En este artículo veremos algunas características de esta combinación y algunos ejemplos sencillos que nos sirvan de introducción al uso conjunto de Leaflet y React.

Características de React y Leaflet

React permite construir interfaces de usuario a partir de piezas individuales llamadas componentes. Los componentes de React son funciones de JavaScript, que utilizan una sintaxis de marcado llamada JSX. Es una extensión de la sintaxis de JavaScript popularizada por React. Al poner marcado JSX cerca de la lógica de renderizado relacionada hace que los componentes de React sean fáciles de crear, mantener y eliminar. Algunas características de React son:

  • Los componentes de React reciben datos y devuelven lo que debe aparecer en la pantalla lo que permite añadir interactividad a una página.
  • React utiliza un sistema de estado y props que facilita la gestión de datos y la comunicación entre componentes. Esto es útil cuando se trabaja con mapas y necesitamos actualizar dinámicamente la interfaz de usuario.
  •  React utiliza un Virtual DOM para optimizar las actualizaciones del DOM, mejorando el rendimiento de la aplicación y proporcionando una experiencia de usuario más fluida.

Leaflet es una biblioteca JavaScript de código abierto ampliamente utilizada para publicar mapas en la web. Leaflet está diseñado teniendo en cuenta la simplicidad, el rendimiento y la usabilidad. Leaflet es ligera, pero dispone de muchos complementos que permiten añadir nuevas funciones de forma rápida y además tiene una API fácil de usar y bien documentada.

Primeros pasos con React y Leaflet

Para utilizar React necesitamos tener instalado Node y npm. Lo primero es crear un nuevo proyecto en React:

npx create-react-app react-leaflet-example
cd react-leaflet-example

Se nos crea una nueva carpeta con el proyecto, nos dirigimos a ella e instalamos las librerías que necesitamos:

npm install leaflet react-leaflet

Como resultado de esta operación tendremos un conjunto de archivos y carpetas que contienen una aplicación básica. Sobre ese «modelo» podemos empezara a trabajar para crear nuestra pagina web. Abrimos  src/App.js y editamos su contenido:

import React, { useState } from 'react';
import { MapContainer, TileLayer, Polygon, Popup } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';

Aquí hemos importado los módulos que vamos a necesitar para el mapa. Según el contenido del mapa utilizaremos los módulos que correspondan. En este ejemplo vamos a añadir una capa de fondo (Tilelayer), una capa vectorial que se compone de un polígono (Polygon) y añadiremos un popup o ventana emergente que se abrirá al hacer clic sobre el polígono que vamos a crear (Popup). Además necesitamos importar la hoja de estilos de Leaflet (leaflet.css).

Añadir una capa vectorial

Una vez que tenemos todos los módulos disponibles, empezamos a crear la página web y el mapa. Continuamos editando el archivo App.js para añadir lo siguiente:

const App = () => {
  const [polygonCoords] = useState([
    [40.96548, -5.66443], [40.96527, -5.66338], [40.96451, -5.66373], [40.9647, -5.66468]
  ]);

 
  return (
    <MapContainer center={[40.965, -5.664]} zoom={15} style={{ height: '400px', width: '100%' }}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      />

      <Polygon
        positions={polygonCoords}
        pathOptions={{ color: 'blue' }}
      >
        <Popup>
          <p>Plaza mayor de Salamanca</p>
        </Popup>
      </Polygon>
    </MapContainer>
  );
};

export default App;

Como puedes observar lo primero que hemos hecho ha sido indicar unas coordenadas para el polígono que vamos a dibujar.

A continuación definimos el elemento MapContainer que contiene los parámetros del mapa, como son el centro, el nivel de zoom inicial y las dimensiones del mapa. Estos son los datos requeridos por Leaflet para poder construir el mapa. Con el contenedor creado podemos empezar a incorporar los elementos al mapa:

  • <TileLayer> añade la capa de OpenStreetMap al mapa.
  • <Polygon> crea una capa vectorial, que está formada por el polígono con las coordenadas que definimos antes.
  • <Popup> abre un popup con el texto indicado al hacer clic sobre el polígono.

Cuando termines de editar el archivo App.js podemos ver el resultado en el navegador. Para ello lanzamos el navegador mediante: npm start

Abrimos el navegador en http://localhost:3000/ para ver el resultado.

Crear un control de capas

Un elemento básico que suelen tener los mapas web es un control de capas para poder activar/desactivar las capas del mapa. Leaflet dispone de un control de capas.

En esta ocasión, además de los módulos que utilizamos en el ejemplo anterior tenemos que añadir otros dos más.

import { MapContainer, TileLayer, Polygon, Popup, LayerGroup, LayersControl } from 'react-leaflet';

En la línea anterior puedes ver que hemos añadido los módulos LayerGroup y LayersControl que se encargan de crear los grupos de capas y el control de capas respectivamente. Para crear el control de capas utilizamos el siguiente código:

import React, { useState } from 'react';
import { MapContainer, TileLayer, Polygon, Popup, LayerGroup, LayersControl } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';

const { BaseLayer, Overlay } = LayersControl;

const App = () => {
  const center = [40.965, -5.664]; // Coordenadas del centro del mapa
  const [polygonCoords] = useState([
    [40.96548, -5.66443], [40.96527, -5.66338], [40.96451, -5.66373], [40.9647, -5.66468]
  ]);
  return (
    <MapContainer center={center} zoom={16} style={{ height: '400px', width: '100%' }}>
      
      <LayersControl position="topright">
        <BaseLayer checked name="OpenStreetMap">
          <TileLayer
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          />
        </BaseLayer>

        
        <BaseLayer name="OpenTopoMap">
          <TileLayer
            url= "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
          />
        </BaseLayer>

        <Overlay checked name="Marcadores">
          <LayerGroup>
            <Polygon
              positions={polygonCoords}
              pathOptions={{ color: 'blue' , fillColor: 'red'}}
             >
        <Popup>
          <p>Plaza mayor de Salamanca</p>
        </Popup>
      </Polygon>
          </LayerGroup>
        </Overlay>
      </LayersControl>
    </MapContainer>
  );
};

export default App;

El control de capas en Leaflet se compone de las capas base o BaseLayer y de las capas superpuestas u Overlay. En este ejemplo hay dos capas base: la capa de OpenStreetmap y la capa de OpenTopoMap. Los enlaces y atribuciones de estas capas las puedes obtener de la lista de proveedores de Leaflet.  En Overlay incluye la capa con el polígono y su Popup.

El control de capas además de la ubicación en el mapa (position=»topright») admite otras opciones. Podemos hacer que el control de capas se muestre desplegado desde el inicio con la opción collapsed.

<LayersControl position="topright" collapsed={false}>

En este caso cuando guardemos las modificaciones que hemos hecho en App.js se actualizar la vista del mapa mostrando el control de capas que hemos creado.

Conclusión

Integrar Leaflet con React permite crear páginas web dinámicas, ya que React se encarga de actualizar eficientemente la interfaz de usuario en respuesta a cambios en el estado de la aplicación. Además React facilita la gestión del estado de la aplicación, lo que es importante cuando trabajamos con mapas interactivos. Y permite manejar la posición del mapa, marcadores y otros datos relacionados con el mapa utilizando el estado de React.

Deja un comentario