javascriptrleaflethtmlwidgetshtmltools

Clicking a leaflet marker takes you to URL


Within the leaflet package for R, is there a way to click on a marker, and be directed to a URL?*

Here's the JS solution.


In R, to add a Popup with a URL:

library(leaflet)
content <- paste(sep = "<br/>",
                 "<b><a href='http://www.samurainoodle.com'>Samurai Noodle</a></b>"
)

leaflet() %>% addTiles() %>%
  addPopups(-122.327298, 47.597131,  content,
             options = popupOptions(closeButton = FALSE)
  )

It's also straightforward to add a Marker that, when clicked, provides a URL in the popup:

leaflet() %>% addTiles() %>%
  addMarkers(-122.327298, 47.597131, popup =  content,
            options = popupOptions(closeButton = FALSE)
  )

Perhaps something custom passed to leaflet in ...?


Lastly, how could a custom JS function display different URLs for each map marker? Consider the example data.frame:

df <- data.frame(url = c("https://stackoverflow.com/questions/tagged/python",
                         "https://stackoverflow.com/questions/tagged/r")),
                 lng = c(-122.327298, -122.337298),
                 lat = c(47.597131,47.587131))

*This was previously asked, but I'm asking the question again here and making a minimal, reproducible example.


Solution

  • You could use htmltools or htmlwidgets to add an onclick event with javascript:

    Solution 1) with htmltools:

    library(leaflet)
    map <- leaflet() %>% 
      addTiles() %>%
      addMarkers(-122.327298, 47.597131, popup =  'LINK',
                 options = popupOptions(closeButton = FALSE)
      )
    
    library(htmltools)
    browsable(
      tagList(
        list(
          tags$head(
            tags$script(
              '
             document.addEventListener("DOMContentLoaded", function(){
               var marker = document.getElementsByClassName("leaflet-pane leaflet-marker-pane");
               var openLink = function() {
                 window.open("https://www.stackoverflow.com")
               };
               marker[0].addEventListener("click", openLink, false);
             })
              '
            )
          ),
          map
        )
      )
    )
    

    Solution 2 - with htmlwidgets:

    library(leaflet)
    library(htmlwidgets)
    leaflet() %>% 
      addTiles() %>%
      addMarkers(-122.327298, 47.597131, popup =  'LINK',
                 options = popupOptions(closeButton = FALSE)
      ) %>%
      onRender('
        function(el, x) {
          var marker = document.getElementsByClassName("leaflet-pane leaflet-marker-pane");
          var openLink = function() {
            window.open("https://www.stackoverflow.com")
          };
          marker[0].addEventListener("click", openLink, false);
        }
      ')
    

    Different url for each marker:

    This is a dirty approach and shows the general way. I lack time to get comfortable with closures in JS again to add a loop.

    One could look here: addEventListener using for loop and passing values. And data can be passed from R to JS with the onRender function.

     jsCode <- paste0('
     function(el, x) {
      var marker = document.getElementsByClassName("leaflet-marker-icon leaflet-zoom-animated leaflet-interactive");
      marker[0].onclick=function(){window.open("https://stackoverflow.com/questions/tagged/python");};
      marker[1].onclick=function(){window.open("https://stackoverflow.com/questions/tagged/r");};
    }
     ')
     
     
     library(leaflet)
     library(htmlwidgets)
     leaflet() %>% 
       addTiles() %>%
       addMarkers(lng = df$lng, lat = df$lat, popup =  'LINK',
                  options = popupOptions(closeButton = FALSE)
       ) %>%
       onRender(jsCode)
     
    

    Using the approach from addEventListener using for loop and passing values, you can loop through the data to get different a url for each marker:

    library(leaflet)
    library(htmlwidgets)
    df <- data.frame(url = c("https://stackoverflow.com/questions/tagged/python",
                             "https://stackoverflow.com/questions/tagged/r"),
                     lng = c(-122.327298, -122.337298),
                     lat = c(47.597131,47.587131))
    
    jsCode <- '
     function(el, x, data) {
      var marker = document.getElementsByClassName("leaflet-marker-icon leaflet-zoom-animated leaflet-interactive");  
      for(var i=0; i < marker.length; i++){
        (function(){
          var v = data.url[i];
          marker[i].addEventListener("click", function() { window.open(v);}, false);
         }()
         ); 
       }
      }'
    
    leaflet() %>% 
     addTiles() %>%
     addMarkers(lng = df$lng, lat = df$lat, popup =  'LINK',
                options = popupOptions(closeButton = FALSE)
     ) %>%
     onRender(jsCode, data=df)