Clicking a leaflet marker takes you to URL
Asked Answered
V

1

8

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.

Varese answered 3/10, 2019 at 0:4 Comment(1)
I think you're going to have inject an event handler in javascript, using rstudio.github.io/leaflet/… . I would webshot or build a simple leaflet example to get the javascript worked out outside of R. Then bring that code in.Abbate
S
9

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)
Spontaneity answered 7/10, 2019 at 20:56 Comment(3)
This works! Thanks for the answer. This is beyond the scope of the OP, but say you had a data.frame df with a column of URLs, one for each marker (df$urls). How would you modify this function to open a different URL for each marker. I updated my question with a simple C&P. Thanks for considering!Varese
I've accepted your answer @BigDataScientist. Thanks for the help! If you ever get around to generalizing it to a dataframe of URLs passed to JS, I would be thrilled since JS is outside of my wheelhouse. Thanks!Varese
I am also looking for a generalization of this code. Did you find an answer? ThanksVillain

© 2022 - 2024 — McMap. All rights reserved.