Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 511
hugogogo Avatar asked Oct 21 '25 01:10

hugogogo


1 Answers

so, looking at this other SO post : Google Maps markerClusterer: how to combine Interface Renderer and GridOptions gridSize in configuration object?

I found what didn't work : the parameter name has to be exactly renderer and not my_renderer (that explains why the order in parameters didn't matters)

but I don't know why, maybe it's a typescript thing (I don't know typescript yet) ? I don't see it when I look at the source code, but there are lots of things I don't understand there anyway

the working code is the same, except for the object name :

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 }) );

  // this is where the error was : the object has to be named exactly 'renderer'
  let 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,
      });
    }
  }

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

I don't know why :/

(I'll mark my answer as the solution for the moment, since it works, even though I don't have the explanation why)

like image 64
hugogogo Avatar answered Oct 22 '25 14:10

hugogogo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!