Récemment nous avons eu une demande spécifique pour afficher les marqueurs sur une Google map : les points devaient être groupés par pays.
Notre cas était encore plus spécifique car il fallait que certains points restent en dehors du cluster des pays : nous devions pouvoir regrouper toutes les villes de France mais laisser les points de Paris dans un cluster à part. Pour le reste, il fallait regrouper les marqueurs par pays.
Par défaut les clusters regroupent les points par rapport à un rayon sur la carte, en cercle, suivant un certain algorithme. Il n’y a pas de notion de pays, régions ou de frontières qui est prise en compte. J’ai trouvé un cas en leaflet où les développeurs ont modifié l’algorithme suivant leurs besoins – consistant à modifier directement une librairie, ce qui est rarement conseillé – afin de regrouper les points par région.
Mais jusque là personne ne savait comment faire un regroupement des clusters par pays, mais nous avons trouvé une solution ! Celle-ci consiste à renseigner par avance à quel pays appartient un marqueur. Ce n’est pas une solution miracle pour toutes les situations, mais pour tous les sites qui souhaitent regrouper leurs magasins ou lieux d’implantation par pays, les informations sont disponibles en base de données.
L’idée a été de créer plusieurs marker clusters sur la carte : lors de l’initialisation d’un marqueur, on l’ajoute à un cluster ou un autre, suivant ce qu’on souhaite. Cela permet de laisser l’algo de clustering fonctionner tout seul, sans le modifier, et de faire en sorte que les points se regroupent suivant le pays/cluster prédéfini. Un peu de code sera plus clair.
Exemple de cluster par pays
var data = [ {cluster: 'Paris', name: 'Paris', lat: 48.8589507, lng: 2.2775175}, {cluster: 'France', name: 'Melun', lat: 48.5421645, lng: 2.6377199}, {cluster: 'France', name: 'Lyon', lat: 45.7580101, lng: 4.8001017}, {cluster: 'Germany', name: 'Berlin', lat: 52.5076682, lng: 13.2860632}, {cluster: 'Germany', name: 'Baden Baden', lat: 48.7574219, lng: 8.1443686}, {cluster: 'United Kingdom', name: 'Londres', lat: 51.5287718, lng: -0.2416803}, {cluster: 'United Kingdom', name: 'Bristol', lat: 51.468575, lng: -2.6607488}, {cluster: 'United Kingdom', name: 'Plymouth', lat: 50.3888309, lng: -4.1824949}, ]; function initMap() { var map = new google.maps.Map(document.getElementById('cnim-google-map'), { center: {lat: 46.52863469527167, lng: 2.43896484375}, zoom: 5 }); // Inits marker list by "place" for multiple clusters var placeMarkerList = {}; // Checks every place for (var index = 0; index < data.length; ++index) { var place = data[i]; var latLng = new google.maps.LatLng(place.lat, place.lng); // Sets the cluster is not already set if(!placeMarkerList.hasOwnProperty(place.cluster)) { placeMarkerList[place.cluster] = []; } // Adds the marker var marker = new google.maps.Marker({ position: latLng }); placeMarkerList[place.cluster].push(marker); } // Parse every cluster to display a marker cluster for each one for (var markerName in placeMarkerList) { if (placeMarkerList.hasOwnProperty(markerName)) { var markerCluster = new MarkerClusterer(map, placeMarkerList[markerName]); } } }
Un exemple est disponible sur codepen: http://codepen.io/jvallet/pen/BLpQWV
Le résultat du code ci-dessus (un peu plus stylisé) :
Nous avons bien un cluster par pays, et Paris hors du cluster.
Notre carte finale ne contient qu’une centaine de points. Je pense que sur des gros volumes cette solution doit être assez peu performante, à vérifier. Cette alternative a l’avantage d’être flexible, mais impose de connaitre la localisation des différents points à l’avance et de les renseigner ; cela reste tout de même idéal pour les sociétés qui veulent afficher leurs magasins sur une carte.
Dans notre cas, les clusters changent à chaque niveau de zoom (par continent, par pays – sauf les capitales, puis chaque ville est séparée en gardant le cluster pour les capitales…). On supprime et recréé les clusters à chaque changement de zoom sans soucis de performance pour notre volume de données, et le résultat est là : un contrôle plus fin et plus propre des regroupements de marqueurs de la carte.