Cómo crear perfiles longitudinales en un visor web con Leaflet

Es habitual que en las actividades al aire libre como rutas ciclistas o de senderismo se acompañen los mapas con el recorrido de un perfil longitudinal que muestre el relieve del trayecto. Los dispositivos GPS facilitan la captura de datos para elaborar los mapas.

Muchas son las opciones para crear estos mapas en la web y una de las mejores es utilizar software libre como Leaflet.

En el catálogo de plugins de esta librería podemos encontrar uno que nos permite crear el perfil longitudinal de una ruta. Se trata del plugin Leaflet.Elevation. En esta entrada vamos a ver cómo crear perfiles longitudinales en un visor web mapping, con la librería Leaflet.

Perfiles longitudinales en un visor web

El plugin Leaflet.Elevation

Este complemento de Leaflet crea un control con un perfil, de tal forma que cuando nos movemos sobre él nos muestra la ubicación sobre el recorrido del mapa. El plugin inicial se había quedado obsoleto y nuevas actualizaciones han permitido su renovación.

Tendremos que descargar los archivos del plugin e insertarlos en el código junto con la librería de leaflet.

Podemos utilizarlo tanto para rutas en formato gpx como para GeoJSON y veremos un ejemplo de cada. Tomaremos como dato la Ruta de la Reconquista que circula por el parque nacional de los Picos de Europa.

	<script src="https://d3js.org/d3.v5.min.js"></script>
	<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
   integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
   crossorigin=""/>
	
	<link rel="stylesheet" href="leaflet-elevation.css" />

	<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"
   integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
   crossorigin=""></script>
	<script type="text/javascript" src="leaflet-elevation.js"></script>

Como vemos en el párrafo anterior además de los archivos CSS y JS de leflet-elevation y Leaflet hemos incorporado la referencia  a D3. Con la libreria D3.js se pueden crear gráficos e infografías a partir de datos y es la herramienta que utiliza el complemento Leaflet.Elevation para crear el perfil longitudinal.

En caso de utilizar los datos a partir de un archivo de tipo gpx necesitamos también le complemento de Leaflet: Leaflet-gpx por lo que añadiremos a las referencias anteriores.

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.4.0/gpx.min.js"></script>

Para incorporar el perfil a nuestra página creamos un div para alojarlo.

<div id="map"></div>
<div id="elevation-div"></div>

Como puedes observar además del id habitual para Leaflet, creamos otro id que llamamos elevation-div.

Como mapa de fondo utilizamos opentopomap, por proporcionarnos un mapa topográfico que es acorde con la aplicación que estamos desarrollando.

L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
attribution: 'Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
}).addTo(map);

Ejemplo para archivo de datos gpx

Como hemos indicado vamos a utilizar una ruta para senderistas en formato gpx. Se trata de la ruta de la reconquista, que discurre por el corazón del Parque Nacional de los Picos de Europa.

var gpx="6-12-GR_202_Ruta_de_la_Reconquista.gpx";

El primer paso es crear una instancia al plugin y elegir sus opciones. El plugin Leaflet-Elevation nos crea un control de Leaflet que contendrá el perfil longitudinal.

	var el = L.control.elevation({
	    position: "bottomleft",
            theme: "magenta-theme", //default: lime-theme
            useHeightIndicator: true, 
            interpolation: d3.curveLinear, //see https://github.com/d3/d3/wiki/
            collapsed: false, 
            detachedView: false, //if false the chart is drawn within map container
            elevationDiv: "#elevation-div", 
		});

En el código precedente podemos vera algunas opciones del plugin. Podemos seleccionar la ubicación del control en el mapa con «position«. El color del perfil lo seleccionamos con la opción «theme«. Si en la opción «useHeightIndicator» utilizamos el valor false nos dibujará un marcador en el punto del recorrido en que nos encontremos. El perfil longitudinal puede estar  minimizado, mostrándose solo un icono, que al pasar el ratón sobre el se despliega. Eso se controla con la opción «collapsed«.

Al tratarse de un archivo en formato gpx tenemos que utilizar el plugin de Leaflet que lo maneja. Hacemos una instancia a L.GPX y le indicamos la url a las imágenes de los marcadores, si queremos que nos marque el inicio y el final de la ruta.

		var gpxRuta=new L.GPX(gpx, {
			async: true,
			 marker_options: {
			    startIconUrl: './images/pin-icon-start.png',
			    endIconUrl: './images/pin-icon-end.png',
			    shadowUrl: './images/pin-shadow.png'
			  }
		}).addTo(map);

Por ultimo añadimos el control y la ruta al mapa.

		el.loadGPX(map, gpx);
		
		gpxRuta.on('loaded', function(e) {
		  		map.fitBounds(e.target.getBounds());
		});

En las ultimas líneas del código estamos utilizando el método getBounds para que nos localice la situación del recorrido y nos realice una vista sobre el mismo.

El resultado lo vemos a continuación. Si recorres el perfil longitudinal con el cursor del ratón la posición se muestra automáticamente sobre la ruta y viceversa.

Ejemplo para geoJSON

Si los datos de la ruta los tenemos en geoJSON el código es todavía más sencillo que en el caso anterior. Lo primero es indicar la fuente de datos.

<script type="text/javascript" src="reconquista.js"></script>

Proporcionamos un centro y nivel de zoom al mapa.

        var map = new L.Map('map',{
		center: [43.20, -4.83],
          	zoom: 11,
      	});

Creamos el control con sus opciones igual que hicimos para el caso de los datos gpx.

var el = L.control.elevation({
  	position: "bottomleft",
        theme: "magenta-theme", 
        useHeightIndicator: true, 
        interpolation: d3.curveLinear,
        collapsed: false, 
        detachedView: true, 
        elevationDiv: "#elevation-div", 
	});
el.addTo(map);

Definimos el estilo que tendrá la capa geojson o lo que es lo mismo el color y propiedades de la línea que  marca la ruta sobre el mapa.

		var myStyle = {
		    "color": "#ff7800",
		    "weight": 5,
		};

Creamos la capa geojson y la incorporamos al mapa.

		var geojson = L.geoJson(geojson,{
			style:myStyle,
		    onEachFeature: el.addData.bind(el)
		}).addTo(map);

El elemento clave reside en onEachFeature, donde le estamos indicando que nos enlace el control con los datos del geojson y aplique las opciones que indicamos al crear el control con el perfil.

A continuación se incluye el mapa con la ruta en formato geojson.

Los ejemplos de este artículo para crear perfiles longitudinales en un visor web con la librería Leaflet, puedes encontrarlos al completo aquí.

Si quieres aprender a crear visores web con Leaflet, inscríbete ya a nuestro curso online de web mapping interactivo con Leaflet.