4

I'd like to customize appearance of clustered markers in Leaflet/Shiny application based on sum of an attribute of child markers.

It is similar to this problem, which makes icon color of clusters based on count of children. What if I want to customize icon based on the sum of magnitude of earthquakes?

With pure javascript application, seems like I should be able to set custom property to individual marker, then access it from iconCreateFunction, as done in this example.

But I am adding marker with addCircleMarkers and addMarkers from leaflet for R, and doesn't seem i can add arbitrary attribute to markers being generated. Code below works but it doesn't if i uncomment two lines (mag = ~mag and sum += markers[i].mag;)

leaflet(quakes) %>% addTiles() %>% addMarkers(
  # mag = ~mag,
  clusterOptions = markerClusterOptions(
  iconCreateFunction=JS("function (cluster) {    
    var markers = cluster.getAllChildMarkers();
    var sum = 0; 
    for (i = 0; i < markers.length; i++) {
    //  sum += markers[i].mag;
      sum += 1;
    }
    return new L.DivIcon({ html: '<div><span>' + sum + '</span></div>'});

  }")

  )
)

I thought about using label= option of addMarkers, and then parse it from Javascript. But the markers accessed with getAllChildMarkers() on marker cluster in JS does not seem to have label property.

I also thought about passing a dataframe from R to leaflet(JS), somehow, maybe like this example, or this ...?

yosukesabai
  • 6,184
  • 4
  • 30
  • 42

1 Answers1

6

Found my answer. Seems like I can put arbitrary property inside options= in addMarker:

leaflet(quakes) %>% addTiles() %>% addMarkers(
  options = markerOptions(mag = ~mag),
  clusterOptions = markerClusterOptions(
  iconCreateFunction=JS("function (cluster) {    
    var markers = cluster.getAllChildMarkers();
    var sum = 0; 
    for (i = 0; i < markers.length; i++) {
      sum += Number(markers[i].options.mag);
//      sum += 1;
    }
    return new L.DivIcon({ html: '<div><span>' + sum + '</span></div>'});
  }")
  )
)
yosukesabai
  • 6,184
  • 4
  • 30
  • 42
  • great, thanks much for sharing (+1 +1)! Could you indicate how to keep the default coloring and shape of the clusters? I tried adding back `,className: 'marker-cluster'` at the end of the JS function, but it seems we have to re-specify everything – Antoine Nov 24 '18 at 11:19
  • you have to pass thing like below, two words, seems like. `return new L.DivIcon({ html: '
    ' + sum + '
    ', className: 'marker-cluster marker-cluster-medium', iconSize: new L.Point(40,40)});` you need your logic to set if marker is large/small/medium, like the original code was doing
    – yosukesabai Nov 25 '18 at 04:18
  • By original code I meant class definition of MarkerClusterGroup, _defaultIconCreateFunction(), found in here or somewhere nearby: https://github.com/Leaflet/Leaflet.markercluster/blob/master/src/MarkerClusterGroup.js#L820-L833 – yosukesabai Nov 25 '18 at 04:22
  • Very nice solution, thanks! I have a Question similar to yours. It's about clustering connecting linestrings of clusters of markers. Maybe someone here is also interested: https://stackoverflow.com/questions/60436142/aggregate-weighted-linestrings-for-clustered-markers-in-leaflet-in-r – maxatSOflow Feb 27 '20 at 15:07