Search code examples
javascriptrshinyleaflet

Coordinates of current mouse position on leaflet map with shiny


I want to access the current mouse position in a leaflet map in shiny. When using shiny you can get the current coordinates of a click event using input$MAPID_click, which contains latitude and longitude of the click. Similarly I want to have input$MAPID_mouseover with a list of the current latitude and longitude of the mouse cursor.

mapview::addMouseCoordinates(map) displays the coordinates in the leaflet map. It uses map.latlng.lng and map.latlng.lat, but I couldn't figure out, how to adapt the code to return a list with the coordinates instead of displaying them.

Ideally this code should work:

library(shiny)
library(leaflet)

ui <- fluidPage(
  leafletOutput("map"),
  br(),
  verbatimTextOutput("out")
)

server <- function(input, output, session) {
  output$map <- renderLeaflet({
    leaflet() %>% addTiles()
  })

  output$out <- renderPrint({
    validate(need(input$map_mouseover, FALSE))
    str(input$map_mouseover)
  })
}

shinyApp(ui, server)

Solution

  • Using onRender from htmlwidgets, you can add some javascript to pass the coordinates from mousemove to a Shiny input, based on this article.

    library(shiny)
    library(leaflet)
    library(htmlwidgets)
    
    ui <- fluidPage(
        leafletOutput("map"),
        br(),
        verbatimTextOutput("out")
    )
    
    server <- function(input, output, session) {
        output$map <- renderLeaflet({
            leaflet()  %>%
                addProviderTiles("OpenStreetMap.Mapnik") %>%
                setView(-122.4105513,37.78250256, zoom = 12) %>%
                onRender(
                    "function(el,x){
                        this.on('mousemove', function(e) {
                            var lat = e.latlng.lat;
                            var lng = e.latlng.lng;
                            var coord = [lat, lng];
                            Shiny.onInputChange('hover_coordinates', coord)
                        });
                        this.on('mouseout', function(e) {
                            Shiny.onInputChange('hover_coordinates', null)
                        })
                    }"
                )
        })
    
        output$out <- renderText({
            if(is.null(input$hover_coordinates)) {
                "Mouse outside of map"
            } else {
                paste0("Lat: ", input$hover_coordinates[1], 
                       "\nLng: ", input$hover_coordinates[2])
            }
        })
    }
    
    shinyApp(ui, server)
    

    enter image description here