26 Jun 2019 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, …).
En la imagen anterior podemos detectar, al menos, dos problemas:
- 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.
- 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.
Ambos problemas se hacen más graves cuando el usuario ve el mapa a una escala más pequeña.
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.
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.
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.
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.
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.
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]
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]
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]
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]
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.