Creando marcadores animados con Leaflet (SVG, GIFs y Font Awesome)

Leaflet es una excelente librería JavaScript empleada para publicar mapas elegantes, con un “aire” moderno de forma rápida y eficaz. Pero además es capaz de integrar recursos para hacer los mapas más vistosos buscando llamar la atención del usuario. Por ejemplo con Leaflet podemos animar los marcadores.

En este blog ya tratamos anteriormente cómo insertar iconos de bootstrap en Leaflet, una de cuyas opciones es la de hacer girar al marcador. Ahora nos centraremos en crear animaciones utilizando imágenes SVG, GIF y con Font Awesome.

marcadores animados con Leaflet

Insertando SVG en Leaflet

SVG es un formato libre de gran implementación, desarrollado y mantenido por W3C. SVG (Gráficos Vectoriales Escalable) es un uno de los formatos GIS vectoriales para gráficos. Ya que estamos en el mundo GIS podemos decir que SVG es el formato vectorial frente al ráster de las imágenes jpg, png… Esto implica que una imagen SVG puede ser redimensionada (hacer zoom) sin que pierda calidad, lo que no ocurre con la imágenes pixeladas.

Utilizar un formato vectorial tiene además otras ventajas, como permitirnos crear efectos y animaciones. Las imágenes SVG se pueden editar con programas open source como INKSCAPE.

Disponemos también de muchas páginas web que nos proporcionan ejemplos y explicaciones sobre el uso de SVG. Por ejemplo un rectángulo se forma de la siguiente manera:

 <svg width="400" height="110">
  <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"/>
</svg>

Como vemos se compone de unas etiquetas html <svg> en cuyo interior definimos el rectángulo (rect) mediante sus dimensiones: largo y ancho y un estilo.

Pasos a seguir

El rectángulo que hemos definido antes podemos utilizarlo como un marcador en Leaflet.

Lo primero es crear un nuevo icono mediante una instancia a L.Icon

    var CustomIcon = L.Icon.extend({
		options: {
		iconSize:     [120, 90],
		iconAnchor:   [22, 94],
		popupAnchor:  [-3, -76]
		}
	});

A continuación creamos el marcador svg

    var svgrect = "<svg xmlns='https://www.w3.org/2000/svg'><rect x='0' y='0' width='50' height='50' fill='red'><animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='5s' repeatCount='indefinite' /></rect></svg>";

Como vemos, hemos introducido algunos cambios en la definición del rectángulo que son los que nos proporcionan la animación. Estamos modificando la transparencia del marcador en un periodo de 5 segundos. Esto hará que el marcador vaya «difuminándose» hasta desaparecer al cabo de 5 segundos, y a continuación se vuelve a hacer visible, en un bucle continuo.

var url = encodeURI("data:image/svg+xml," + svgrect).replace('#','%23');

La línea anterior es necesaria para codificar el recurso. En Firefox necesitamos que  # se cambie por %23 para que pueda funcionar en ese navegador.

Una vez completada la generación del icono SVG podemos crear el marcador e insertarlo en el mapa.

var rectIcon = new CustomIcon({iconUrl: url})
    
    L.marker([40.965, -5.664], {icon: rectIcon}).bindPopup("Soy un marcador SVG.").addTo(map);

El resultado es que en las coordenadas indicadas se dibuja un rectángulo que va desapareciendo progresivamente y luego se vuelve a hacer visible. Puedes ver el efecto creado en el siguiente mapa:

El código completo es:

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css" />
  <script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
  
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    #map {
      height: 100%;
    }
    .leaflet-marker-icon{
      width: 200px;
      height: 200px;
    }
  </style>
</head>

<body>


  <div id="map"></div>
  <script>
    var map = L.map('map').setView([40.965, -5.664], 14);

    L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    
    var CustomIcon = L.Icon.extend({
			options: {
				iconSize:     [120, 90],
				iconAnchor:   [22, 94],
				popupAnchor:  [-3, -76]
			}
		});
    

    var svgrect = "<svg xmlns='https://www.w3.org/2000/svg'><rect x='0' y='0' width='50' height='50' fill='red'><animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='5s' repeatCount='indefinite' /></rect></svg>";

    
		
    //Para Firefox y IE hay que rremplazar '#' por '%23'. 
    var url = encodeURI("data:image/svg+xml," + svgrect).replace('#','%23');
    console.log(url);
   
    var rectIcon = new CustomIcon({iconUrl: url})
    
    L.marker([40.965, -5.664], {icon: rectIcon}).bindPopup("Soy un marcador SVG.").addTo(map);


    
  </script>
</body>
</html>

Insertar GIFs en Leaflet

Estamos habituados a recibir multitud de GIF’s en los mensajes de las redes sociales. Este abuso de las imágenes en movimiento que puede llegar a resultar molesto, bien utilizado es una excelente herramienta para publicidad y para captar la atención del usuario. Graphics Interchange Format (GIF) es un formato para el intercambio de imágenes en movimiento ampliamente utilizado en la web y que permite realizar y animaciones.

Utilizar GIF en Leaflet no tiene nada de particular, podemos utilizarlo igual que cualquier otro formato de imagen. Un ejemplo es el siguiente:

<!DOCTYPE html>
<html>
<head><title>GeoJson y Leaflet</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>


<style> 

 	#map {
  	width: 700px;
   	height: 600px; }
		
	#div1 {
  	font-size:48px;
	}  

</style> 
</head>
	<body>
	
	<div id="map"></div>
		<script>
		var map = L.map('map',{center: [36.8021480 , -5.1393441],zoom: 7});

		L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map);

		var geojson = [{
		"type": "Feature",
		"geometry": {
		"type": "Point",
		"coordinates": [-5.9731700, 37.3828300]
		  			},
		 "properties": {
		       "name": "Sevilla",
			   "title": "Andalucía"
		    		  }
		},{
		"type": "Feature",
		 	"geometry": {
		   		"type": "Point",
		   		 "coordinates": [ -4.4203400 ,36.7201600]
			       },
		"properties": {
		 		 "name": "Málaga",
		 		 "title": "Andalucia"
				  }
			      }];

		var LeafIcon = L.Icon.extend({
		options: {
			iconSize:     [50, 50],
			iconAnchor:   [15, 30],
			popupAnchor:  [0, -30]
			}
		});

		var bandera = new LeafIcon({iconUrl: 'andalucia.gif'});

		var monumentos = L.geoJSON(geojson, {
			pointToLayer: function (feature, latlng) {
				return L.marker(latlng, {icon: bandera});
			},		
		});
		map.addLayer(monumentos);

		</script>
	</body>
</html>

El código anterior utiliza un geoJSON para crear y asignar propiedades a dos marcadores. La creación del icono, como vemos, es igual que en el ejemplo que pusimos para SVG, es decir: realizamos una instancia a L.Icon y luego definimos la ruta (URL) de la imagen. En esta ocasión se trata de una bandera de Andalucía flameada por el viento.

Este es el resultado.

Font Awesome – el conjunto de iconos y herramientas más populares de la web

De entre la gran cantidad de recursos web que nos proporcionan iconos, uno de los más importantes es sin duda Font Awesome.

Podemos utilizar un marcador para crear una función con JavaScript que defina una animación, de la siguiente forma:

	function chargebattery() {  
		var a;
		a = document.getElementById("div1");
		a.innerHTML = "&#xf244;";
		setTimeout(function () {
		a.innerHTML = "&#xf243;";
		}, 200);
		setTimeout(function () {
		a.innerHTML = "&#xf242;";
		}, 400);
		setTimeout(function () {
		a.innerHTML = "&#xf241;";
		}, 600);
		setTimeout(function () {
		a.innerHTML = "&#xf240;";
		}, 800);	  
			};

Mediante setTimeout hacemos que se ejecute una función en un tiempo determinado medido en milisegundos. De esta forma podemos modificar un div en el tiempo de tal forma que se crea una animación. En el ejemplo que estamos utilizando sería la carga de una batería. Como paso previo hemos definido un div utilizando la clase de leaflet L.divIcon.

	var myIcon = L.divIcon({ 
		iconSize: new L.Point(0,0),
			html: '<div id="div1" class="fa"></div>' 
		});

Ejecutamos la función chargebattery:

		setInterval(chargebattery, 1000);

Y creamos el marcador:

		var nmarker = new L.marker([40.965,-5.664], {icon: myIcon}).addTo(map).bindPopup("bateria");

El resultado es un mapa con un marcador que muestra una batería cargándose:

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

Let’s connect!

Date de alta en nuestra newsletter y te enviaremos GRATIS el ebook que te ayudará a impulsar tu perfil GIS:
Vitaminas MappingGIS

Tan solo una vez al mes recibirás las últimas novedades del sector GIS y de nuestros cursos