SymbolixAU / googleway

R Package for accessing and plotting Google Maps
http://symbolixau.github.io/googleway/
Other
234 stars 46 forks source link

Update map not working with shiny modal #237

Closed noamanemobidata closed 3 years ago

noamanemobidata commented 3 years ago

Hi! I'm try to add a maker to the google map, the coordinates are calculated from geocoded address string provided by the user inside a modal:

this is the app code

library(shiny)
library(googleway)

map_key<- "***" 

# Define UI for application that draws a histogram
ui <- fluidPage(
  tags$style(".pac-container {
    z-index: 12000;
}"),

  # Application title

  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(

      actionButton(inputId = 'show_modal',label = 'Show Modal'), 

    ),

    # Show a plot of the generated distribution
    mainPanel(

        div(

            tags$style(type = "text/css", "#map {height: calc(100vh - 5px) !important;}"),
            google_mapOutput("map"))
      )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output, session) {

  output$map <- renderGoogle_map({

    google_map(key = map_key,geolocation = T,

               search_box = F,
               scale_control=T,
               street_view_control=F,
               map_type_control = F,
               update_map_view = T,
               rotate_control=T,
               fullscreen_control = F,
               location = c(47.6062442,2.1148086),
               zoom = 10)

  })

  observeEvent(input$show_modal,{

    showModal(
    modalDialog(footer = NULL, easyClose = T,
                fluidPage(

                HTML('<div class="form-group">
                    <input id="AdressNew" type="text" class="form-control" placeholder="Enter some adress">
                  </div>  '),
                HTML(paste0(" <script>
                function initAutocomplete() {
                 var autocomplete =   new google.maps.places.Autocomplete(document.getElementById('AdressNew'));
                 autocomplete.addListener('place_changed', function() {
                 var place = autocomplete.getPlace();
                 Shiny.setInputValue('jsName', place.name);
                 Shiny.setInputValue('jsAddress', place.formatted_address);
                 });
                 } </script>
                <script src='https://maps.googleapis.com/maps/api/js?key=", map_key, "&libraries=places&callback=initAutocomplete' async defer ></script>"))

                ),

      actionButton(inputId = 'go',label = 'submit')

    )
    )

  })

  observeEvent(input$go,{

    x= google_geocode(address = input$jsAddress %>% as.character(),
                   key = map_key,
                   simplify = TRUE,) %>%geocode_coordinates() 
    print(x)

    google_map_update(map_id = "map") %>%
      googleway::add_markers(data = x %>% as.data.frame(), lat = "lat", lon = "lng", update_map_view = T)

  })

}

# Run the application 
shinyApp(ui = ui, server = server)

ps: works fine without using modal ( with address input in sidebar)

Thank you

dcooley commented 3 years ago

Adding this script

<script src='https://maps.googleapis.com/maps/api/js?key=", map_key, "&libraries=places&callback=initAutocomplete' async defer ></script>"))

is giving you a conflict, because that script is already loaded when you call google_map() in the libraries argument

The solution:

Remove that script, and the surrounding function it uses as the callback

showModal(
      modalDialog(footer = NULL, easyClose = T,
                  fluidPage(
                    HTML('<div class="form-group">
                    <input id="AdressNew" type="text" class="form-control" placeholder="Enter some adress">
                  </div>  '),
                    HTML(paste0(" <script>
                 var autocomplete = new google.maps.places.Autocomplete(document.getElementById('AdressNew'));
                 autocomplete.addListener('place_changed', function() {
                 autocomplete.setFields(['place_id', 'geometry', 'name']);
                 var place = autocomplete.getPlace();
                 Shiny.setInputValue('jsGeometry', place.geometry);
                 });
                 </script>"

                    ))
                  ),

                  actionButton(inputId = 'go',label = 'submit')
      )
    )

I've also added the geometry field to the list of objects returned from the Auto-complete field, so you get the lon & lat directly, without having to geocode:

  observeEvent(input$go,{

    df <- data.frame(
      lat = input$jsGeometry$location$lat,
      lng = input$jsGeometry$location$lng
    )

    google_map_update(map_id = "map") %>%
      googleway::add_markers(data = df, lat = "lat", lon = "lng", update_map_view = T)

  })
dcooley commented 3 years ago

Thank you for this question; It made me finally understand how to properly use the auto-complete within a shiny :)

noamanemobidata commented 3 years ago

Hi Dave! wonderful solution! works fine thank you very mush :)