31 Ago 2023 Web Mapping con MapLibre, Svelte y Google Sheet
En este post, vamos a mostrar como crear un proyecto de web mapping con MapLibre y Svelte, junto con datos contenidos en una hoja de Google Sheet. Continuando con el post Poblar una hoja de cálculo con Apps Script, utilizaremos estos datos para visualizar en un mapa web los micropueblos de Catalunya, es decir, aquellos municipios con menos de 500 habitantes.
Crear un proyecto con Svelte.js
Svelte.js es un framework frontend para el desarrollo de aplicaciones web reactivas, y que obviamente podemos también utilizar para nuestros proyectos de web mapping.
Para empezar un proyecto con Svelte, teclearemos en la terminal de nuestro sistema operativo la siguiente instrucción:
$ npx degit sveltejs/template micropueblos
Una vez creado, accedemos al directorio e instalamos las dependencias. Y finalmente, arrancamos el entorno local:
$ cd micropueblos $ npm install $ npm run dev
Accederemos a la aplicación a través de esta url: http://localhost:8080
Crear un mapa con MapLibre
MapLibre es una librería javascript, de código abierto, que permite la creación de mapas web interactivos.
Para instalar MapLibre en nuestro proyecto de Svelte, basta con utilizar esta instrucción:
$ npm i maplibre-gl
Una vez instalada la librería, crearemos un componente de Svelte en el que añadiremos el código que nos permitirá visualizar el mapa.
Al instalar Svelte, se han generado múltiples ficheros y directorios. Dentro del directorio src, crearemos un nuevo directorio con el nombre componentes. Y dentro de componentes, el archivo Map.svelte
El código del componente Map.svelte será el siguiente:
<script> import { onMount, onDestroy } from 'svelte' import { Map } from 'maplibre-gl'; import 'maplibre-gl/dist/maplibre-gl.css'; let mapa; let contendor; onMount(() => { const localizacion = { lng: 1.4, lat: 41.6, zoom: 7 }; mapa = new Map({ container: contendor, style: `https://demotiles.maplibre.org/style.json`, center: [localizacion.lng, localizacion.lat], zoom: localizacion.zoom }); }); onDestroy(() => { mapa.remove(); }); </script> <div class="map-wrap"> <div class="map" id="map" bind:this={contendor}></div> </div> <style> .map-wrap { position: relative; width: 100%; height: 100vh; } .map { position: absolute; width: 100%; height: 100%; } </style>
En este código, creamos un objeto Map de MapLibre, al que le pasamos como opciones el contendor, es decir, el elemento HTML en el que se renderizará el mapa, así como el estilo, las coordenadas (longitud y latitud) y el nivel de zoom inicial.
También definimos, con estilos CSS, la posición y tamaño del mapa.
En el archivo App.svelte se realizará la importación de este nuevo componente, y se añadirá el contenido en la página:
<script> import Map from './components/Map.svelte'; export let name; </script> <main> <Map/> <h1>Hello {name}!</h1> <p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p> </main>
Ahora, en el navegador (a través de la url http://localhost:8080) ya deberían visualizarse los cambios efectuados en la aplicación.
Añadir al mapa una capa VectorTile
Para representar los micropueblos de Catalunya, utilizaremos la cartografía de divisiones administrativas en formato VectorTile que ofrece el ICGC. En primer lugar, cargaremos la fuente de datos, y a continuación, añadiremos la capa. Por ello, en el componente Map.svelte, justo después de crear el objeto Map, añadiremos estas líneas de código:
mapa.on('load', function() { // añadir la fuente de datos 'municipalities' de tipo vector Tile mapa.addSource('municipalities', { type: 'vector', url: 'https://openicgc.github.io/divisions_administratives.json' }) // añadimos la capa boundary mapa.addLayer({ 'id': 'micropobles', 'type': 'fill', 'source': 'municipalities', 'source-layer': 'boundary', 'filter': [ "all", ["==", "escala", "1M"], ["==", "class", "municipi"] ], 'paint': { "fill-opacity": 0.9, "fill-color": "green", "fill-outline-color": "black" } }) })
Al añadir la capa, a partir de la fuente municipalities de la capa VectorTiles, aplicamos un filtro (filter) para utilizar los datos a escala 1M, así como las entidades de la clase municpi, Por otro lado, aplicamos también un estilo a esta capa, dejándolo, por ahora, con un relleno de color verde y un contorno negro.
El resultado es este:
Modificar el comportamiento del cursor
Podemos configurar el mapa para que el cursor cambie al pasar por encima las entidades vectoriales de la capa municipios. Para ello, basta con añadir estas líneas de código:
// modificar el estilo del cursor mapa.on('mouseenter', 'micropobles', function () { mapa.getCanvas().style.cursor = 'pointer'; }); mapa.on('mouseleave', 'micropobles', function () { mapa.getCanvas().style.cursor = ''; });
Este comportamiento hará que resulte mas intuitivo hacer click sobre las entidades vectoriales para mostrar un popup de información una vez implementemos esta funcionalidad.
Utilizar datos de un Google Sheet
En esta aplicación hemos utilizado diversas fuentes de datos disponibles en la red (cartografía OSM y VectorTiles del ICGC). Mostraremos ahora como utilizar datos de un Google Sheet. Y lo haremos de forma dinámica, de tal modo que, al modificarse los valores del Google Sheet, también se actualizará el mapa.
Utilizaremos el Google Sheet creado en el post Poblar una hoja de cálculo con Apps Script, y en el que figuran todos los municipios de Catalunya, indicándose si son micropueblos o no (en el campo Micropoble).
Dentro de la función onMount, añadiremos las siguientes líneas de código. Con ellas, construimos la url de acceso al documento, y realizamos un fetch para obtener los datos. En la lista MICROPUEBLOS guardamos el nombre de los municipios que, acorde a los datos del Google Sheet, corresponden a micropueblos.
Para que funcione correctamente, habrá que remplazar el texto your-sheet-id por el identificador (id) del Google Sheet.
// Cargar datos de Google Sheet const MICROPUEBLOS = ["in", "name"] // array con los micropueblos const sheetId = 'your-sheet-id'; // id del Google Sheet const base = `https://docs.google.com/spreadsheets/d/${sheetId}/gviz/tq?`; // url base const sheetName = 'Main'; // nombre del Sheet const query = encodeURIComponent('Select *'); // consulta const url = `${base}&sheet=${sheetName}&tq=${query}`; // url completa document.addEventListener('DOMContentLoaded', loadSheet); // ejecutamos la funcion una vez cargado el DOM /** * Función para obtener los datos del Google Sheet */ function loadSheet() { fetch(url) .then(res => res.text()) .then(rep => { // Eliminamos el texto y extraemos únicamente el JSON const jsonData = JSON.parse(rep.substring(47).slice(0, -2)); const columnas = []; // Extraemos el nombre de las columnas jsonData.table.cols.forEach((cabecera) => { if (cabecera.label) { let columna = cabecera.label; columnas.push(columna) } }) // Extraer datos de los filas jsonData.table.rows.forEach((rowData) => { const fila = {}; columnas.forEach((ele, ind) => { fila[ele] = (rowData.c[ind] != null) ? rowData.c[ind].v : ''; }) if (fila.Micropoble == true) MICROPUEBLOS.push(fila.Nom_Municipi) }) }) }
Finalmente, en el filtro de la capa micropueblos, añadiremos el array con los nombres correspondientes (MICROPUEBLOS).
mapa.addLayer({ 'id': 'micropobles', 'type': 'fill', 'source': 'municipalities', 'source-layer': 'boundary', 'filter': [ "all", ["==", "escala", "1M"], ["==", "class", "municipi"], MICROPUEBLOS ], 'paint': { "fill-opacity": 0.9, "fill-color": "green", "fill-outline-color": "black" } })
Y este será el resultado. De la capa VectorTile de l’ICGC con los municipios de Catalunya únicamente se muestran aquellos que son micropueblos, acorde a los datos del Google Sheet.
Popup de información
Para terminar la aplicación, podemos añadir un popup de información. De esta forma, al hacer click sobre un micropueblo, se mostrará su nombre.
Lo haremos utilizando el siguiente código:
mapa.on('click', 'micropobles', e => { const features = mapa.queryRenderedFeatures(e.point, { layers: ["micropobles"] }); new Popup() .setLngLat(e.lngLat) .setHTML('Nombre: ' + features[0].properties.name) .addTo(mapa); })
Conclusiones
En este post hemos mostrado como crear un mapa web utilizando Svelte y MapLibre, así como diferentes fuentes de datos.
También como usar datos de un Google Sheet para actualizar el mapa. De esta forma, sin necesidad de modificar el código de la aplicación ni mantener un backend con una base de datos, se puede llevar a cabo la actualización de la cartografía. Una opción a tener en cuenta para proyectos de webmapping relativamente simples y que deban implementarse con una infraestructura mínima.