Mapas interactivos con leaflet.js

7
27198

En este artículo veremos cómo integrar los mapas de OpenStreetMap utilizando la librería Javascript Leaflet.js

Índice de contenidos

1. Introducción

Leaflet es una librería javascript para la creación de mapas interactivos. Nos permite utilizar los tiles del servicio que prefiramos para pintar el mapa. Para este tutorial utilizaremos los tiles de OpenStreetMap.

Crearemos un pequeño proyecto con el que podremos probar la librería. Puedes clonar el repositorio https://github.com/DaniOtero/leaflet-demo

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15’ (2.5 GHz Intel Core i7, 16 GB 1600 MHz DDR3).
  • Sistema Operativo: Mac OS X El Capitán 10.11.2
  • Google Chrome 50.0.2661.102

3. Añadir leaflet a nuestro proyecto

Para añadir leaflet a nuestro proyecto basta con incluir la librería javascript y el css que nos proporciona leaflet. Por comodidad, añadiremos ambas desde el CDN.

<html>
	<head>
	    <title>Tutorial leaflet.js</title>
	    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
	</head>
	<body>
		<h1>Leaflet.js Demo</h1>
	    <div id="map" style="height: 100%"></div>
	    <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
	</body>
</html>

4. Carga del del mapa

Para poder cargar el mapa, necesitamos indicarle a leaflet el identificador un elemento div cargado en el DOM de nuestra página. Le indicaremos a leaflet que utilice el elemento con id «map».

	var demoMap = L.map('map').setView([40.453191, -3.509236], 6);

La llamada a la función «setView» nos centrará el mapa en las coordenadas que le indiquemos (lat, lng) y con el nivel de zoom que deseemos.

A continuación, tenemos que añadirle un «tileLayer» a nuestro mapa. Un «tile» es una imagen que representa un área determinada. Cada nivel de zoom cargará los «tiles» asociados a ese nivel de zoom, los cuales tendrán más o menos detalle en función de la escala del nivel de zoom.

Para cargar los tiles de OpenStreetMap, utilizaremos el siguiente código

	var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
	var osmAttrib = 'Map data © OpenStreetMap contributors';
	var osm = new L.TileLayer(osmUrl, {
	    minZoom: 5,
	    maxZoom: 16,
	    attribution: osmAttrib
	});

En cuanto a este codigo comentar un par de detalles:

  • En cuanto a la URL, el párametro «s» representa subdominios (para cargar de distintos subdominios si el servicio dispone de ellos y aligerar la carga), el parámetro «z» el nivel de zoom, y los parámetros «x» e «y» las coordenadas del «tile».
  • La atribución añadirá una nota al pie del mapa indicando el origen de los mismos.
  • Para crear la capa, se debe indicar la URL del servicio de mapas, y entre las opciones podemos indicar los niveles de zoom máximo y mínimo que queremos permitir.

Con esto ya tendríamos nuestro mapa centrado en el punto que deseemos

Leaflet vacio

5. Añadir marcadores a nuestro mapa

Leaflet nos permite añadir marcadores de forma sencilla:

	L.marker([39.190878, -5.7806939999999996]).addTo(demoMap);

Podemos añadir tantos marcadores como queramos a nuestro mapa.

Leaflet Marcadores

6. Mostrar un popup con información de un marcador

Si además de mostrar el marcador, queremos que nos muestre alguna información adicional, podemos emplear un popup para representar esta información en forma de HTML. Para ello podemos refactorizar el código anterior ligeramente

	var location = [39.190878, -5.7806939999999996];
	var marker = L.marker(location)
	marker.bindPopup('

Latitud:'+location[0]+'

Longitud:'+location[1]+'

'); marker.addTo(demoMap);

Si ahora hacemos click sobre algún de los marcadores podremos ver la latitud y longitud de dicho marcador

Leaflet Popup

7. Optimización

En el caso de que necesitemos una mayor fluidez para nuestro mapa (por ejemplo, si es una aplicación web que va a ejecutarse en smartphones con algún año a sus espaldas…), podemos mejorar la experiencia de usuario desactivando las animaciones. Para ello podemos pasarle un objeto con opciones a la llamada de creación del mapa:

	var demoMap = L.map('map', {
                fadeAnimation: false,
                zoomAnimation: false,
                markerZoomAnimation: false
            }).setView([40.453191, -3.509236], 6);

También podemos indicarle al «TileLayer» que reutilice tiles, de forma que no tenga que crear nuevos objetos y reservar memoria por cada tile creado, y que se actualice cuando esté en estado «idle» para evitar que se congele la pantalla mientras carga.

    var osm = new L.TileLayer(osmUrl, {
        minZoom: 5, maxZoom: 16,
        attribution: osmAttrib,
        updateWhenIdle: true,
        reuseTiles: true
    });

8. Clustering

Si necesitamos representar una gran cantidad de marcadores en nuestro mapa, es posible que a un nivel de zoom bajo nuestro mapa se vea sobrecargado. Además el renderizar una gran cantidad de marcadores también es bastante costoso (en nuestro navegador de escritorio probablemente no tendremos problemas, pero en el caso de smartphones la cosa se complica…).

Para ello podemos agrupar los marcadores en clusters, de forma que los marcadores que se aglutinan en un área determinada se representarán como un único marcadores, y se separarán cuando se alcance un nivel de zoom determinado (o al hacer click, se cambiará el nivel de zoom). Para ello leaflet cuenta con un plugin llamado Leaflet.markercluster. Para instalarlo podemos utilizar npm (en este caso no existe CDN):

	npm install --save leaflet.markercluster

Y lo cargaremos en nuestro html:

<html>
	<head>
	    <title>Demo leaflet.js</title>
	    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
	    <link rel="stylesheet" href="node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css" />
	</head>
	<body>
	    <h1>Leaflet.js Demo</h1>
	    <div id="map" style="height: 100%"></div>
	    <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
	    <script type="text/javascript" src="node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.js"></script>
	</body>
</html>

Refactorizaremos el código para añadir nuestros marcadores a un cluster. En vez de añadir un marcador directamente al mapa, se debe añadir a una nueva capa:

	var markerCluster = L.markerClusterGroup();

	var location = [39.190878, -5.7806939999999996];
	var marker = L.marker(location)
	marker.bindPopup('

Latitud:'+location[0]+'

Longitud:'+location[1]+'

'); markerCluster.addLayer(marker); demoMap.addLayer(markerCluster);

Leaflet cluster

9. Conclusiones

Leaflet.js es una librería bastante completa. Es bastante intuitiva y su API es bastante simple. Además, nos permite personalizar muchos aspectos, como el icono de los marcadores o el comportamiento de los mismos. También dispone de bastantes plugins como en el caso de los clusters.

El hecho de que podamos utilizar cualquier servicio de mapas que queramos también es un punto a favor, ya que no nos «casamos» con un servicio determinado.

También está preparada para funcionar en smartphones, reconociendo los gestos típicos como pan o pinch sin tener que programar nada adicional.

Como desventaja, en smartphones con algún año a sus espaldas, o cuyo motor javascript del webview nativo sea algo lento (cof, cof windows phone…), la experiencia de usuario puede ser no todo lo agradable que desearíamos, especialmente cuando cargamos una cantidad elevada de marcadores.

10. Referencias

http://leafletjs.com/reference.html
https://github.com/Leaflet/Leaflet.markercluster

7 COMENTARIOS

  1. Hola, buenos dias.. estoy analizando el ejemplo del post, y tengo una duda. Suponiendo que yo hago esto en un servidor web compartido como prueba.. como hago para instalar marketcluster?

    npm install –save leaflet.markercluster

    entiendo como hacerlo en mi pc, pero suponiendo que deseo ponerlo online como se hace?

  2. Hola, buenas gran tutorial… una pregunta te agradecería mucho si me la pudieras resolver. En caso de tener ya la interfaz web creada, existe una funcion o plugin que permitan al cliente subir archivos scv o layer desde la misma interfaz, además de que esta se almacene? gracias.

    • Buenas, no se exactamente a que te refieres, si lo que quieres es a añadir marcadores mediante un formulario, al igual que en el código de ejemplo de github se añaden desde un simple array mediante un bucle for (map.js linea 14) uno a uno, los podrías añadir igualmente desde el evento submit de un formulario por ejemplo

  3. Hola que tal mi consulta es la siguiente:.
    Como puedo hacer una interracion por ejemplo con un ComboBox, digamos tengo el combobox con Paises y al seleccionar algun pais me acerque a dicho pais.
    Puedo obtener el value de cada pais pero no se como hacerlo interactuar con el mapa ya que no me actualiza ya sea con un change o condicional no se como hacer.
    Gracias.

  4. hola gracias por el articulo. Queria consulta si existe alguna manera de identficar los marcadores de manera de manipular uno en particular como para cambiar un estado y cambiar el icono. La mayoria de los ejemplos que he visto te obliga a recorrer un arreglo de markers … existe algo asi? quedo atento gracias.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad