R Shiny map search input box

痴心易碎 提交于 2020-06-24 10:24:27

问题


In google maps, the search input box auto completes addresses as a user types. Is there a way to do this in R Shiny with access to the autocomplete value in order to use with a mapping package?

There is a javascript method here. I've tried to use this method in R Shiny in the code below. SymbolixAU pointed out using google_map( search_box = TRUE ) which is a simple solution. Unfortunately it doesn't work in my code and also because I would like the search box to be separate from the map.

The attempt below has a text input my_address, text output copy_of_address and a googleway map my_map in this order on the page.

The intended behaviour is for a user to enter text into text input my_address, have it autocomplete with an address (this works), the address will be copied into text output copy_of_address (this only shows what was typed, not the autocompleted version) and finally the map is to be centred on this address.

See that the input box has the autocomplete address, however the copy of the address and map is using only the user input text.

In the code below, replace MyKey with your google api key (sometimes an empty string works).

library(shiny)
library(googleway)

key <- "MyKey"
set_key(key = key)
google_keys()

ui <- shiny::basicPage(

  div(
    textInput(inputId = "my_address", label = "")    
    ,textOutput(outputId = "copy_of_address")
    ,HTML(paste0("
          <script>
            function initAutocomplete() {
            new google.maps.places.Autocomplete(
            (document.getElementById('my_address')),
            {types: ['geocode']}
            );
            }
            </script>
            <script src='https://maps.googleapis.com/maps/api/js?key=", key,"&libraries=places&callback=initAutocomplete'
            async defer></script>
    "))
    ,google_mapOutput(outputId = "my_map")
  )

)

server <- function(input, output) {

  my_address <- reactive({
    input$my_address
  })

  output$copy_of_address <- renderText({
    my_address()
  })

  output$my_map <- renderGoogle_map({
    my_address <- my_address()
    validate(
      need(my_address, "Address not available")
    )

    df <- google_geocode(address = my_address)
    my_coords <- geocode_coordinates(df)
    my_coords <- c(my_coords$lat[1], my_coords$lng[1])

    google_map(
      location = my_coords,
      zoom = 12,
      map_type_control = FALSE,
      zoom_control = FALSE,
      street_view_control = FALSE
    )
  })

}

shinyApp(ui, server)

回答1:


This wasn't easy for me to figure out, but I think I have a reasonable solution. It ultimately came down to copying and pasting the example from Google very carefully, reading about sending messages from Javascript to Shiny, putting the ideas together, and getting lucky on the 200th attempt...

To Give Credit Where It's Due:

Google's link: https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete

RStudio's Link: https://shiny.rstudio.com/articles/js-send-message.html

My potential solution:

library(shiny)
library(googleway)

key <- "MyKey"
set_key(key = key)
#google_keys()

ui <- shiny::basicPage(

  div(
    textInput(inputId = "my_address", label = "Type An Address")    
    ,textOutput(outputId = "full_address")
    ,HTML(paste0(" <script> 
                function initAutocomplete() {

                 var autocomplete =   new google.maps.places.Autocomplete(document.getElementById('my_address'),{types: ['geocode']});
                 autocomplete.setFields(['address_components', 'formatted_address',  'geometry', 'icon', 'name']);
                 autocomplete.addListener('place_changed', function() {
                 var place = autocomplete.getPlace();
                 if (!place.geometry) {
                 return;
                 }

                 var addressPretty = place.formatted_address;
                 var address = '';
                 if (place.address_components) {
                 address = [
                 (place.address_components[0] && place.address_components[0].short_name || ''),
                 (place.address_components[1] && place.address_components[1].short_name || ''),
                 (place.address_components[2] && place.address_components[2].short_name || ''),
                 (place.address_components[3] && place.address_components[3].short_name || ''),
                 (place.address_components[4] && place.address_components[4].short_name || ''),
                 (place.address_components[5] && place.address_components[5].short_name || ''),
                 (place.address_components[6] && place.address_components[6].short_name || ''),
                 (place.address_components[7] && place.address_components[7].short_name || '')
                 ].join(' ');
                 }
                 var address_number =''
                 address_number = [(place.address_components[0] && place.address_components[0].short_name || '')]
                 var coords = place.geometry.location;
                 //console.log(address);
                 Shiny.onInputChange('jsValue', address);
                 Shiny.onInputChange('jsValueAddressNumber', address_number);
                 Shiny.onInputChange('jsValuePretty', addressPretty);
                 Shiny.onInputChange('jsValueCoords', coords);});}
                 </script> 
                 <script src='https://maps.googleapis.com/maps/api/js?key=", key,"&libraries=places&callback=initAutocomplete' async defer></script>"))
    ,google_mapOutput(outputId = "my_map")
    )

    )

server <- function(input, output) {

  my_address <- reactive({
    if(!is.null(input$jsValueAddressNumber)){
      if(length(grep(pattern = input$jsValueAddressNumber, x = input$jsValuePretty ))==0){
        final_address<- c(input$jsValueAddressNumber, input$jsValuePretty)
      } else{
        final_address<- input$jsValuePretty
      }
      final_address
    }
  })


  output$full_address <- renderText({
    if(!is.null(my_address())){
      my_address()
    }
  })

  output$my_map <- renderGoogle_map({
    my_address <- my_address()
    shiny::validate(
      need(my_address, "Address not available")
    )

    not_a_df <- google_geocode(address = my_address)
    my_coords <- geocode_coordinates(not_a_df)
    my_coords <- c(my_coords$lat[1], my_coords$lng[1])

    google_map(
      location = my_coords,
      zoom = 12,
      map_type_control = FALSE,
      zoom_control = FALSE,
      street_view_control = FALSE
    )
  })

}

shinyApp(ui, server)

I hope this helps. Cheers! --nate



来源:https://stackoverflow.com/questions/53347495/r-shiny-map-search-input-box

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!