Search code examples
rshinyr-leaflet

How to make a polygon clickable from underneath a marker overlay


I have a leaflet map that contains a polygon and a point layer. I would like to have the polygon layer be clickable so I can gather information from it, and I would also like the point layer to have a hover so I can see what it is even if I'm not clicking on it. My problem is that I need to be able to click the polygon layer at all places, including underneath the points that are overlayed.

library(leaflet)
library(dplyr)
library(sf)

# NC counties - a shapefile shipped with the sf package
shape <- st_read(system.file("shape/nc.shp", package ="sf")) %>% 
  st_transform(shape, crs = 4326)


# three cities with coordinates
points <- data.frame(name = c("Raleigh", "Greensboro", "Wilmington"),
                     x = c(-78.633333, -79.819444, -77.912222),
                     y = c(35.766667, 36.08, 34.223333)) %>% 
  st_as_sf(coords = c("x", "y"), crs = 4326)

leaflet() %>% 
  addProviderTiles("Stamen.Toner") %>% 
  addPolygons(data = shape, 
              fillColor = "aliceblue", 
              color = "grey",
              popup = ~NAME, # Popup correctly shows name, even when clicking on a point
              options = pathOptions(clickable = TRUE)) %>%  
  addCircleMarkers(data = points, 
                   fillColor = "red", 
                   color = NA,
                   radius = 10,
                   fillOpacity = 1,
                   label = ~name, # Hovering over should show label...
                   options = pathOptions(clickable = FALSE)) # ...but not be clickable

So far, I've tried to change the pathOptions of each layer to make sure that I can only click on the polygon layer - this has worked, but the labels that I want to see when hovering over one of the points are not showing up. I don't think this is a zIndex issue because the points are correctly drawing over the polygons. In my full application, I have several point layers (manifested as icons using addMarkers()) that need to be identified by hovering but I still need to be able to click the polygon underneath to access the information - when the map is too small, the limited area of clickable polygon makes the map hard to use.


Solution

  • Use addCircles with a defined layerId to display the hover text. I have made your code work in shiny. Try this

    # NC counties - a shapefile shipped with the sf package
    shape <- st_read(system.file("shape/nc.shp", package ="sf")) %>% 
      st_transform(shape, crs = 4326)
    
    
    # three cities with coordinates
    point <- data.frame(name = c("Raleigh", "Greensboro", "Wilmington"),
                        lng = c(-78.633333, -79.819444, -77.912222),
                        lat = c(35.766667, 36.08, 34.223333)) 
    points <- point %>% 
      st_as_sf(coords = c("lat", "lng"), crs = 4326)
    
    ui <- fluidPage(
      leafletOutput("mymap")
    )
    
    server <- function(input, output, session) {
      output$mymap <- renderLeaflet({
        leaflet() %>% 
          addProviderTiles("Stamen.Toner") %>% 
          addPolygons(data = shape, 
                      fillColor = "aliceblue", 
                      color = "grey",
                      popup = ~NAME, # Popup correctly shows name, even when clicking on a point
                      options = pathOptions(clickable = TRUE)) %>%  
          addCircles(data = point, lat = point$lat, lng = point$lng, 
                           fillColor = "red", 
                           color = NA,
                           radius = 5000,
                           layerId = point$name, # Hovering over should show label...
                           fillOpacity = 0.7,
                           # label = ~name, # Hovering over should show label...
                           # options = pathOptions(clickable = FALSE)
                           ) # ...but not be clickable
        
      })
      
      # When circle is hovered over...show a popup
      observeEvent(input$mymap_shape_mouseover$id, {
        pointId <- input$mymap_shape_mouseover$id
        print(input$mymap_shape_mouseover$id)
        lat = point[point$name == pointId, "lat"]
        lng = point[point$name == pointId, "lng"]
        leafletProxy("mymap") %>% addPopups(lat = lat, lng = lng, as.character(pointId), layerId = "hoverPopup")
      })
    }
    
    shinyApp(ui, server)