Search code examples
javascriptgoogle-mapsmarkerclusterer

google maps MarkerClusterer how to personalize the renderer


I'm using MarkerClusterer with google maps api, I'm trying to change the behavior of the markers with the renderer inerface, as they explain in the doc : https://googlemaps.github.io/js-markerclusterer

problem is, I don't understand the doc... it says that the MarkerClusterer class can accept parameters :

{
    algorithm?: Algorithm;
    map?: google.maps.Map;
    markers?: google.maps.Marker[];
    renderer?: Renderer;
    onClusterClick?: onClusterClickHandler;
}

and indeed I can see it in the source code : https://github.com/googlemaps/js-markerclusterer/blob/1ee6469fa3c62a30c39cf509b379847741a7ebb9/src/markerclusterer.ts

and I can see here the implementation of DefaultRenderer, the default value for the renderer parameter : https://github.com/googlemaps/js-markerclusterer/blob/1ee6469fa3c62a30c39cf509b379847741a7ebb9/src/renderer.ts

so in my code, I thought I should create an object with a method called render that returns a new google.maps.Marker. I tried lots of different variations, I show you one there, in which I took the source code with few modifications (colors of markerclusters), I don't know what I should actually do to make it works :

function init_map() {
  let map = new google.maps.Map(document.getElementById("ljdp_map"), { zoom: 2, center: {lat:46.227638, lng:2.213749} });
  let markers = [];
  for (ev of events)   // events is defined outside this function
    markers.push( new google.maps.Marker({ position: ev.coordinates, map: map }) );

  // so, this is where I try to modify the cluster appearance, without luck
  // maybe "my_renderer" need to be a class inheriting from DefaultRenderer ?
  //   class my_renderer extends markerClusterer.DefaultRenderer {
  // it didn't work
  let my_renderer = {
    render({ count, position }, stats) {
      const svg = window.btoa(`
        <svg fill="#00ff00" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
          <circle cx="120" cy="120" opacity=".6" r="70" /></svg>`);
      return new google.maps.Marker({
        position,
        icon: {
          url: `data:image/svg+xml;base64,${svg}`,
          scaledSize: new google.maps.Size(45, 45),
        },
        title: `Cluster of ${count} markers`,
        zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
      });
    }
  }
  // since the render argument is the fourth, after an algorithm argument, in the constructor,
  // maybe I need to create an algorithm object to place the renderer at the right position ?
  //   let algorithm = new markerClusterer.SuperClusterAlgorithm({});
  //   new markerClusterer.MarkerClusterer({ map, markers, algorithm, my_renderer });
  // it didn't work

  new markerClusterer.MarkerClusterer({ map, markers, my_renderer });
}

the init function is called with :

<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=ini_map"></script>

and the marker clustering library is added by this script :

<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>

and the output is as if I didn't add my_renderer, cluster are not personalized. I don't know if I'm on the right way but making mistakes, or if it's not the way intended to modify the clusters ?


Solution

  • The solution is this line:

    new markerClusterer.MarkerClusterer({ map, markers, renderer });
    

    What this line actually is:

    new markerClusterer.MarkerClusterer({ map:map, markers:markers, renderer:renderer });
    

    But the deconstruction is hidden.

    If you want to call your renderer my_renderer then you should modify the line to be:

    new markerClusterer.MarkerClusterer({ map, markers, renderer:my_renderer });
    

    and it should work as expected.