Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Leaflet legend for addAwesomeMarkers function with icons

Tags:

r

leaflet

shiny

Is there any way to create a leaflet legend for addAwesomeMarkers function with right colors and icons. For example, in the following map, I would like to create a legend given under the code.

library(leaflet)

IconSet <- awesomeIconList(
  ship   = makeAwesomeIcon(icon= 'ship', markerColor = 'green', iconColor = 'white', library = "fa"),
  pirate = makeAwesomeIcon(icon= 'fire', markerColor = 'blue', iconColor = 'white', library = "fa")
)

# Some fake data
df <- sp::SpatialPointsDataFrame(
  cbind(
    (runif(20) - .5) * 10 - 90.620130,  # lng
    (runif(20) - .5) * 3.8 + 25.638077  # lat
  ),
  data.frame(type = factor(
    ifelse(runif(20) > 0.75, "pirate", "ship"),
    c("ship", "pirate")
  ))
)

leaflet(df) %>% addTiles() %>%
  # Select from oceanIcons based on df$type
  addAwesomeMarkers(icon = ~IconSet[type])

enter image description here

You time and effort to answer is cordially appreciated.

like image 280
M.Qasim Avatar asked Nov 01 '17 22:11

M.Qasim


1 Answers

There is a way you can do this, referenced in this answer, and that is by inserting a map control and define the control with html. Unlike the other answer, the icons use css styling to create the image (one element creates the marker shape, the other contains the icon, a div and a span). The images come from the css classes assigned to each element:

  • the div sets the background color of the marker
  • the span (or for font-awesome, the <i>), sets the icon and the icons color (though for font-awesome, it doesn't seem that color changes of the icon)

Each icon library uses different classes and slightly different conventions.

Given the method referenced in the other answer, and the properties of the icons, I built a basic function that displays an icon legend.

I did manage to build a function that positions icons from each of the three supported leaflet icon libraries (ion, font-awesome, glyphicon), but each one has slightly different positioning attributes which is still resulting in minor positioning issues for me. In the interest of shorter example code, I've included only positioning for font-awesome, positioning of others follows similar methods. If desired, I can post the version of the function with support for all three.

The function only creates the html, you'll need to place it in a control still (it is basic, a few parameters could easily be added to customize it):

# legend html generator:
markerLegendHTML <- function(IconSet) {

    # container div:
    legendHtml <- "<div style='padding: 10px; padding-bottom: 10px;'><h4 style='padding-top:0; padding-bottom:10px; margin: 0;'> Marker Legend </h4>"

    n <- 1
    # add each icon for font-awesome icons icons:
    for (Icon in IconSet) {
        if (Icon[["library"]] == "fa") {
        legendHtml<- paste0(legendHtml, "<div style='width: auto; height: 45px'>",
                             "<div style='position: relative; display: inline-block; width: 36px; height: 45px' class='awesome-marker-icon-",Icon[["markerColor"]]," awesome-marker'>",
                               "<i style='margin-left: 8px; margin-top: 11px; 'class= 'fa fa-",Icon[["icon"]]," fa-inverse'></i>",
                             "</div>",
                             "<p style='position: relative; top: -20px; display: inline-block; ' >", names(IconSet)[n] ,"</p>",
                           "</div>")    
        }
        n<- n + 1
    }
    paste0(legendHtml, "</div>")
}

And, all together with adding the control (note that it takes the names for the legend from the icon list, so I've modified these from your original, but everything else should be the same):

library(leaflet)

# legend html generator:
markerLegendHTML <- function(IconSet) {
    # container div:
    legendHtml <- "<div style='padding: 10px; padding-bottom: 10px;'><h4 style='padding-top:0; padding-bottom:10px; margin: 0;'> Marker Legend </h4>"

    n <- 1
    # add each icon for font-awesome icons icons:
    for (Icon in IconSet) {
        if (Icon[["library"]] == "fa") {
        legendHtml<- paste0(legendHtml, "<div style='width: auto; height: 45px'>",
                             "<div style='position: relative; display: inline-block; width: 36px; height: 45px' class='awesome-marker-icon-",Icon[["markerColor"]]," awesome-marker'>",
                               "<i style='margin-left: 8px; margin-top: 11px; 'class= 'fa fa-",Icon[["icon"]]," fa-inverse'></i>",
                             "</div>",
                             "<p style='position: relative; top: -20px; display: inline-block; ' >", names(IconSet)[n] ,"</p>",
                           "</div>")    
        }
        n<- n + 1
    }
    paste0(legendHtml, "</div>")
}

IconSet <- awesomeIconList(
  "Regular Ship"   = makeAwesomeIcon(icon= 'ship', markerColor = 'green', iconColor = 'white', library = "fa"),
  "Pirate Ship" = makeAwesomeIcon(icon= 'fire', markerColor = 'blue', iconColor = 'white', library = "fa")
)

# Some fake data
df <- sp::SpatialPointsDataFrame(
  cbind(
    (runif(20) - .5) * 10 - 90.620130,  # lng
    (runif(20) - .5) * 3.8 + 25.638077  # lat
  ),
  data.frame(type = factor(
    ifelse(runif(20) > 0.75, "Pirate Ship", "Regular Ship"),
    c("Regular Ship", "Pirate Ship")
  ))
)


leaflet(df) %>% addTiles() %>% 
  addAwesomeMarkers(icon = ~IconSet[type]) %>% 
  addControl(html = markerLegendHTML(IconSet = IconSet), position = "bottomleft")
like image 128
Andrew Reid Avatar answered Nov 03 '22 02:11

Andrew Reid