Search code examples
javascriptrshinyr-leaflet

Add Latitude / Longitude search widget to a Shiny Leaflet map


I am looking to add a Lattitude / Longitude search widget to a Shiny leaflet map. I found a workable leaflet js solution here , and I would like to port the js function into my R Shiny application. Using the htmlwidgets onRender function with panTo, I can get the map to pan to specific coordinates; however,I want a user to be able to type in lat and long and zoom to that location on the map. Here is the code for a sample map that I have been using to test potential solutions. I have been unsuccessful in my attempts to apply the submitted coordinates to the map. The commented out code in the onRender is one of my attempts.

library(shiny)
library(leaflet)

ui <- fluidPage(leafletOutput("mymap"),

                tags$div(
                  HTML(
                    '
                    Latitude: <input type="text" name="lat" id="lat"/>
                    Longitude: <input type="text" name="lng" id="lng"/>
                    <input type="button" onclick="zoomTo()" value="zoomTo"/>
                    '
                  )
                  ))

server <- function(input, output, session) {
  output$mymap <- renderLeaflet({
    leaflet() %>%
      addProviderTiles(providers$Stamen.TonerLite,
                       options = providerTileOptions(noWrap = TRUE)) %>%
      setView(15, 47, 12) %>%
      htmlwidgets::onRender(
        'function(el, x) {                        
        this.panTo(new L.LatLng(26, -80));                        
        #var lat = document.getElementById("lat").value;
        #var lng = document.getElementById("lng").value;
        #this.panTo(new L.LatLng(lat, lng));
        
        
  }'
)
})
  }

shinyApp(ui, server)

Solution

  • By referring to input$zoomTo in the renderLeaflet statement, Shiny re-runs that function if you click the button. To make it work, I had to assign the button an id and the correct class.

    I am not sure why you use HTML and JavaScript to do all this instead of using the widgets provided by Shiny. Take a look at the Shiny Widget Gallery to see what's possible using just R functionality.

    library(shiny)
    library(leaflet)
    
    ui <- fluidPage(leafletOutput("mymap"),
    
                    tags$div(
                        HTML(
                            '
                                    Latitude: <input type="text" name="lat" id="lat"/>
                                    Longitude: <input type="text" name="lng" id="lng"/>
                                    <input id="zoomTo" type="button" value="zoomTo"  class="action-button"/>
                                    '
                        )
                    ))
    
    server <- function(input, output, session) {
        output$mymap <- renderLeaflet({
            input$zoomTo
    
            leaflet() %>%
                addProviderTiles(providers$Stamen.TonerLite,
                                 options = providerTileOptions(noWrap = TRUE)) %>%
                setView(15, 47, 12) %>%
                htmlwidgets::onRender(
                    'function(el, x) {                        
                        var lat = document.getElementById("lat").value;
                        var lng = document.getElementById("lng").value;
                        this.panTo(new L.LatLng(lat, lng));
                  }'
                )
        })
    }
    
    shinyApp(ui, server)