Search code examples
rshinymouseeventr-leaflet

R leaflet - How to wait for `map_shape_click` only


Using leaflet mouse-events, a click on a shapefile, also triggers a click on the map, so the green lines in the example are drawn immediately.

How can I wait for a click on one of the shapefiles, to remove the clicked Line and ignore map-clicks for that, but when I click on the map (and not a shapefile), the green lines show up?

Or how can I get a input$map_shape_click only?

library(shiny)
library(leaflet)
library(sp)

## DATA
x <- c(1,5,4,8); y <- c(1,3,4,7)
data = sp::SpatialLines(list(
  sp::Lines(sp::Line(cbind(x,y)), ID="a"),
  sp::Lines(sp::Line(cbind(rev(x)*1.1,y)), ID="b")), 
  CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

data = SpatialLinesDataFrame(data, data = data.frame(
  id = 1:length(data)), match.ID = F)
data1 = SpatialLinesDataFrame(data, data = data.frame(
  id = 1:length(data)), match.ID = F)

## UI
ui = fluidPage(
  leafletOutput("map")
)

## SERVER
server <- shinyServer(function(input, output, session) {

  output$map <- renderLeaflet({
    leaflet(options = leafletOptions(doubleClickZoom= FALSE)) %>% 
      addTiles() %>% 
      addPolylines(data = data, smoothFactor = 10, opacity = 1, color = "blue",
                   layerId = as.character(data$id),
                   highlightOptions = highlightOptions(color = "white",
                                                       weight = 5, bringToFront = F, opacity = 1)
      )
  })

  observeEvent(input$map_shape_click, {
    cat("Shape is Clicked \n")   
    proxy <- leafletProxy("map")
    proxy %>% removeShape("1")
  })

  observeEvent({ input$map_click }, {
    cat("Map Clicked \n")
    proxy <- leafletProxy("map")
    proxy %>%       addPolylines(data = data, smoothFactor = 10, opacity = 1, color = "green",
                                 layerId = as.character(data$id))

  })

})

shinyApp(ui, server)

Solution

  • You can check click coordinates and run code in input$map_click observer depending on found overlaps. Code below:

    library(shiny)
    library(leaflet)
    library(sp)
    library(rgeos)
    
    ## DATA
    x <- c(1,5,4,8); y <- c(1,3,4,7)
    data = sp::SpatialLines(list(
      sp::Lines(sp::Line(cbind(x,y)), ID="a"),
      sp::Lines(sp::Line(cbind(rev(x)*1.1,y)), ID="b")), 
      sp::CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))
    
    data = sp::SpatialLinesDataFrame(data, data = data.frame(
      id = 1:length(data)), match.ID = F)
    data1 = sp::SpatialLinesDataFrame(data, data = data.frame(
      id = 1:length(data)), match.ID = F)
    
    ## UI
    ui = fluidPage(
      leafletOutput("map")
    )
    
    ## SERVER
    server <- shinyServer(function(input, output, session) {
    
      output$map <- renderLeaflet({
        leaflet(options = leafletOptions(doubleClickZoom= FALSE)) %>% 
          addTiles() %>% 
          addPolylines(data = data, smoothFactor = 10, opacity = 1, color = "blue",
                       layerId = as.character(data$id),
                       highlightOptions = highlightOptions(color = "white",
                                                           weight = 5, bringToFront = F, opacity = 1)
          )
      })
    
      observeEvent({ input$map_click }, {
    
        coords <- input$map_click
        clicked <- sp::SpatialPoints(
          matrix(
            c(coords$lng, coords$lat),
            nrow = 1
          )
        )
        sp::proj4string(clicked) <- sp::CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
        compare <- rgeos::gIntersects(
          # verify if width parameter works for you
          rgeos::gBuffer(clicked, width = 0.5), 
          data, 
          byid = TRUE
        )
    
        if(any(compare)){
          cat("Shape is Clicked \n")  
          proxy <- leafletProxy("map")
    
          if(compare[1] == TRUE){
            proxy %>% removeShape("1")
          }
          if(compare[2] == TRUE){
            proxy %>% removeShape("2")
          }
    
        }else{
          cat("Map Clicked \n")
          proxy <- leafletProxy("map")
          proxy %>%       addPolylines(data = data, smoothFactor = 10, opacity = 1, color = "green",
                                       layerId = as.character(data$id))
        }
    
      })
    
    })
    
    shinyApp(ui, server)