Cuando en determinadas zonas de nuestro mapa se aglutinan varios marcadores, un buen recurso suele ser agruparlos en clusters, de forma que el número de elementos en el mapa disminuya mejorando así la usabilidad y visibilidad.
Esta funcionalidad no viene integrada directamente en la API de OpenStreetMap (LeafletJS) y tenemos que implementarla mediante un sencillo plugin, Leaflet MarkerCluster.
Para el ejemplo vamos a crear un mapa en OpenStreetMap como lo haríamos normalmente y como vimos en artículos anteriores: Integra OpenStreetMap en tus aplicaciones web con LeafLet y MapBox.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
<title>Mapa con OpenStreetMap</title>
<style>
#mimapa {height: 600px;}
</style>
</head>
<body>
<div id="mimapa"></div>
<script>
var mymap = L.map('mimapa').setView([37.1698, -3.965], 18);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 25,
attribution: 'Datos del mapa de © <a href="https://www.openstreetmap.org/">OpenStreetMap</a>, ' + '<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' + 'Imágenes © <a href="https://www.mapbox.com/">Mapbox</a>',
id: 'mapbox/streets-v11'
}).addTo(mymap);
</script>
</body>
</html>
Ejecutando este código ya deberíamos poder visualizar un mapa vacío. Si no carga, revisa el código. Puedes modificar las coordenadas por las de tu zona, si lo prefieres.
Ahora vamos a añadir unos cuantos marcadores en un espacio reducido:
/*MARCADORES*/
var marker1 = L.marker([37.1698, -3.965]).addTo(mymap);
var marker2 = L.marker([37.1698, -3.966]).addTo(mymap);
var marker3 = L.marker([37.1700, -3.966]).addTo(mymap);
var marker4 = L.marker([37.1700, -3.967]).addTo(mymap);
var marker5 = L.marker([37.1696, -3.964]).addTo(mymap);
var marker6 = L.marker([37.1694, -3.964]).addTo(mymap);
Hasta aquí bien, tenemos 6 marcadores agrupados en una zona reducida, lo que a simple vista dificulta un poco la visibilidad. Para poder agrupar estor marcadores en clusters vamos a añadir los scripts del plugin MarkerCluster en el <head> de nuestra página a continuación de los scripts de Leaflet:
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.1.0/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.1.0/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet.markercluster@1.1.0/dist/leaflet.markercluster.js"></script>
Bien, lo primero que vamos a hacer es volver al código de marcadores y quitarles el método addTo(mymap), ya que no vamos a añadirlos de forma indepeniente y dejar este método puede crear repeticiones y comportamientos extraños.
/*MARCADORES*/
var marker1 = L.marker([37.1698, -3.965]);
var marker2 = L.marker([37.1698, -3.966]);
var marker3 = L.marker([37.1700, -3.966]);
var marker4 = L.marker([37.1700, -3.967]);
var marker5 = L.marker([37.1696, -3.964]);
var marker6 = L.marker([37.1694, -3.964]);
A continuación de los marcadores, vamos a declarar un grupo de clusters:
var grupos = L.markerClusterGroup();
Y lo único que tenemos que hacer es añadir cada marcador a este grupo:
grupos.addLayer(marker1);
grupos.addLayer(marker2);
grupos.addLayer(marker3);
grupos.addLayer(marker4);
grupos.addLayer(marker5);
grupos.addLayer(marker6);
Huelga decir que si tienes cientos de marcadores no es necesario escribir todo manualmente, usa un bucle que para eso están!
/*POR EJEMPLO:*/
for(var i=1; i <= 6; i++){
grupos.addLayer(marker+i);
}
Por último agregamos el grupo al mapa:
mymap.addLayer(grupos);
Los marcadores se irán agrupando dinámicamente según el zoom que apliquemos al mapa.
Os dejo el código del archivo html final comentado:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- API LEAFLET -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
<!--PLUGIN MARKERCLUSTER -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.1.0/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.1.0/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet.markercluster@1.1.0/dist/leaflet.markercluster.js"></script>
<title>Mapa con Open Street Map</title>
<style>
#mimapa {height: 600px;}
</style>
</head>
<body>
<div id="mimapa"></div>
<script>
/*DECLARAR EL MAPA*/
var mymap = L.map('mimapa').setView([37.1698, -3.965], 16);
/*DIBUJAR EL MAPA*/
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 25,
attribution: 'Datos del mapa de © <a href="https://www.openstreetmap.org/">OpenStreetMap</a>, ' + '<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' + 'Imágenes © <a href="https://www.mapbox.com/">Mapbox</a>',
id: 'mapbox/streets-v11'
}).addTo(mymap);
/*DEFINIR MARCADORES*/
var marker1 = L.marker([37.1698, -3.965]);
var marker2 = L.marker([37.1698, -3.966]);
var marker3 = L.marker([37.1700, -3.966]);
var marker4 = L.marker([37.1700, -3.967]);
var marker5 = L.marker([37.1696, -3.964]);
var marker6 = L.marker([37.1694, -3.964]);
/*CREAR GRUPO DE CLUSTERS*/
var grupos = L.markerClusterGroup();
/*AÑADIR CADA MARCADOR AL CLUSTER*/
grupos.addLayer(marker1);
grupos.addLayer(marker2);
grupos.addLayer(marker3);
grupos.addLayer(marker4);
grupos.addLayer(marker5);
grupos.addLayer(marker6);
//AÑADIR CLUSTER AL MAPA
mymap.addLayer(grupos);
</script>
</body>
</html>