Blog del Máster
en Tecnologías de la Información Geográfica y Ciencia de Datos
Espaciales

Agrupación de marcadores (marker clustering) en Leaflet

La agrupación de marcadores o marker clustering es una práctica habitual usada en mapas web con alta densidad de puntos. Es un mecanismo mediante el cual, en lugar de mostrar todo un conjunto de puntos de forma independiente en un mapa, mostramos un indicador de la cantidad de puntos que hay en una zona.

El problema

Cuando cargamos una capa con muchos puntos puede que esos puntos o marcadores se sobrepongan unos a otros. Además, en determinados niveles de zoom la usabilidad del mapa se puede ver altamente mermada (no vemos cuántos puntos hay, nos cuesta discriminar sobre qué punto hacemos clic, …).

Marcadores sin agrupar. Fuente: elaboración propia.

Marcadores sin agrupar. Fuente: elaboración propia.

En la imagen anterior podemos detectar, al menos, dos problemas:

  1. De entrada lo primero que nos transmite el mapa es una sensación de complejidad y de dificultad. Que en este caso los marcadores se hayan distribuido al azar ayuda a incrementar esta sensación. Pero incluso cuando los marcadores muestran un patrón de distribución la sensación persiste.
  2. En segundo lugar, cuando superamos la primera impresión y queremos usar el mapa, nos resulta difícil en algunos casos determinar si hay muchos o pocos puntos en una zona. También hace más difícil saber sobre qué marcador hemos hecho clic.
    Clic sobre marcador sin agrupar. ¿Cuál es el marcador 59?. Fuente: elaboración propia.

    Clic sobre marcador sin agrupar. ¿Cuál es el marcador 59?. Fuente: elaboración propia.

Ambos problemas se hacen más graves cuando el usuario ve el mapa a una escala más pequeña.

Marcadores sin agrupar a escala pequeña

Marcadores sin agrupar a escala pequeña. Elaboración propia

Soluciones

Hay distintas soluciones para mejorar la legibilidad y usabilidad del mapa. La más común consiste en no mostrar los marcadores y, en su lugar, mostrar un indicador que refleje la cantidad de puntos que se sobreponen en las distintas zonas del mapa. Si un marcador no presenta conflictos con otros marcadores cercanos se muestra el marcador original.

Agrupación de marcadores en Leaflet. Fuente: elaboración propia.

Agrupación de marcadores en Leaflet. Fuente: elaboración propia.En estos casos, las agrupaciones de marcadores (o clusters) se suelen adaptar al nivel de zoom del mapa, de modo que si ampliamos o reducimos el nivel de zoom se vuelven a calcular y siempre vemos un mapa sin superposición de marcadores.

Agrupación de marcadores a pequeña escala

Agrupación de marcadores a pequeña escala. Fuente: Elaboración propia.

Implementaciones

Este mecanismo es ya muy habitual. Lo podemos encontrar en muchas de las API de mapas, aunque no siempre en el core de la API y debemos recorrer al uso de otros complementos o plugins.

Agrupación de marcadores en Leaflet

En Leaflet la funcionalidad de clustering no la tenemos en la API por defecto y debemos incorporarla mediante un plugin externo. La opción más habitual consiste en incorporar el plugin Leaflet.MarkerCluster, desarrollado por el mismo equipo que la API principal. Los ejemplos vistos hasta ahora usan este plugin.

El uso de este plugin es muy simple. Primero deberemos añadir el plugin y su hoja de estilos. Después lo incorporamos a nuestro código de la siguiente manera:

[html]
# Definimos una capa de tipo Cluster Group
var markers = L.markerClusterGroup();

# Añadimos a esta capa los distintos marcadores
markers.addLayer(L.marker(getRandomLatLng(map)));

# Añadimos la capa Cluster al mapa
map.addLayer(markers);
[/html]

Esto es suficiente para que nuestro mapa agrupe los marcadores que se encuentran muy cerca.

Configuración Básica de Leaflet.MarkerCluster

Este plugin permite modificar algunos de sus comportamientos, mediante parámetros en la llamada a sus distintas funciones. Algunos de los parámetros que podemos usar son:

showCoverageOnHover

Usado al definir la capa Cluster Group, este parámetro booleano indica si queremos que al pasar el ratón por encima de un cluster veamos la extensión real de sus marcadores. Si no indicamos nada, éste parámetro tiene el valor true y se mostrarán las extensiones.

Extensión de los clusters. Fuente: elaboración propia.

Extensión de los clusters. Fuente: elaboración propia.

Si no queremos mostrar las extensiones añadiremos este parámetro y le daremos el valor false.

[html]
var markers = L.markerClusterGroup({ showCoverageOnHover: false });
[/html]

zoomToBoundsOnClick

Usado también al definir la capa Cluster Group. Con este parámetro podemos decidir qué queremos que haga cuando el usuario pulsa sobre una agrupación de marcadores. Por defecto, este parámetro recibe el valor true, con lo que al hacer clic sobre un cluster automáticamente la vista se centra en la extensión ocupada por los marcadores pertenecientes a ese cluster. Una vez centrado en esa vista, el sistema vuelve a agrupar los marcadores para ajustarlos a ese nivel de zoom

Si añadimos este parámetro y le asignamos el valor false, entonces el mapa no hará nada cuando el usuario haga clic sobre un cluster. Si queremos que haga algo distinto de ampliar la vista tendremos que capturar el evento y asociarle una funcionalidad.

spiderfyOnMaxZoom

Este parámetro nos permite activar y desactivar una funcionalidad interesante que consiste en desplegar los marcadores alrededor de la ubicación del marcador. Este comportamiento, por defecto, ocurre siempre que estemos en el nivel más grande de zoom y tengamos marcadores sobre los que hacemos clic. Con este parámetro, y asignándole el valor false, podemos impedir que nuestro mapa tenga este comportamiento.

Spiderfy en Marker Cluster. Fuente: elaboración propia.

Spiderfy en Marker Cluster. Fuente: elaboración propia

animate

Otro de los parámetros booleanos que podemos usar en la llamada a L.markerClusterGroup() nos sirve para desactivar la animación por defecto que aparece entre clusters cuando modificamos el nivel de zoom o usamos la función spiderfy. Por defecto, este parámetro recibe el valor true, pero si lo definimos como false cancelaremos esa animación.

Animación de marcadores

Animación de marcadores. Fuente: elaboración propia.

Configuración avanzada de Leaflet.MarkerCluster

Además de los parámetros anteriores, podemos personalizar aún más nuestro mapa mediante el uso de muchos otros parámetros.

animateAddingMarkers

Si lo definimos como true muestra una animación cuando añadimos un marcador a un mapa que ya ha cargado la capa de clusters. Por defecto, esta animación está desactivada. Para activarla deberemos tener el parámetro animate también con valor true.

disableClusteringAtZoom

Con este parámetro podemos indicar que a partir de cierto nivel de zoom los marcadores no se agrupen nunca.

maxClusterRadius

Distancia máxima (en píxels) desde el centro del cluster hasta la posición real de sus marcadores. Un valor menor generará más (y más pequeños) clusters.

Indicamos el parámetro maxClusterRadius (valor por defecto: 80). Fuente: elaboración propia.

Indicamos el parámetro maxClusterRadius (valor por defecto: 80). Fuente: elaboración propia.

Clusters indicando el parámetro maxClusterRadius con valor 160. Fuente: elaboración propia.

Clusters indicando el parámetro maxClusterRadius con valor 160. Fuente: elaboración propia.

polygonOptions

Con este parámetro podemos modificar el estilo de los polígonos que indican la extensión de los marcadores de un cluster. Su valor será un objeto de tipo Path options.

[html]
var markers = L.markerClusterGroup({ polygonOptions: {color: 'red'} });
[/html]
Polígono de color rojo. Fuente: elaboración propia.

Polígono de color rojo. Fuente: elaboración propia.

spiderLegPolylineOptions

Con este parámetro podemos modificar el estilo de las líneas que aparecen en la función spiderfy.

[html]

var markers = L.markerClusterGroup({ spiderLegPolylineOptions: { color: ‘red’, weight: ’10’, opacity: 1 } });
[/html]

Cambiar el estilo de las patas de la araña con spiderLegPolylineOptions. Fuente: elaboración propia.

Cambiar el estilo de las patas de la araña con spiderLegPolylineOptions. Fuente: elaboración propia.

spiderfyDistanceMultiplier

Factor multiplicador para calcular la distancia usada en la función spiderfy al desplegar los marcadores.

[html]
var markers = L.markerClusterGroup({ spiderfyDistanceMultiplier: 5 });
[/html]
Multiplicamos la distancia de las patas de araña por 5. Fuente: elaboración propia.

Multiplicamos la distancia de las patas de araña por 5. Fuente: elaboración propia.

iconCreateFunction

Con este parámetro podemos personalizar el icono usado para representar las agrupaciones.

JavaScript

[html]
var markers = L.markerClusterGroup({
    iconCreateFunction: function (cluster) {
        var markers = cluster.getAllChildMarkers();
        return L.divIcon({ 
            html: markers.length, 
            className: 'mycluster', 
            iconSize: L.point(40, 40) 
        });
    }
});</pre>
CSS
<pre class="EnlighterJSRAW" data-enlighter-language="css">.mycluster {
    background: red;
    border-radius: 50%;
    color: white;
    font-weight: bold;
    font-size: 2em;
    text-align: center;
    padding-top: 5px;
    border: 10px solid #CC1122;
}</pre>
<pre>[/html]
Modificar el estilo de los clústers. Fuente: elaboración propia.

Modificar el estilo de los clústers. Fuente: elaboración propia.

Conclusión

Cuando desarrollamos una aplicación con un mapa web, la acumulación excesiva de marcadores puede llegar a ser contraproducente y hacer que el usuario termine descartando nuestro mapa web como herramienta útil.

Podemos evitar esta primera impresión y dotar a nuestro mapa de una mayor usabilidad si usamos un complemento para agrupar los marcadores en clusters.

En Leaflet, el complemento Leaflet.MarkerCluster nos permite añadir esta funcionalidad y personalizarla a nuestro gusto.

Marc Compte
Ambientólogo actualmente trabajando como programador de proyectos SIG web en el Servicio de SIG y Teledetección (SIGTE) de la Universitat de Girona. Tengo especial interés en Python y el desarrollo web. Colaboro como autónomo con empresas del sector de las bases de datos o del posicionamiento indoor.


Suscríbete a nuestra newsletter