如何在Shiny中重置Leaflet单击事件

时间:2018-02-01 17:12:12

标签: r shiny leaflet

我在Shiny中构建了一个Leaflet应用程序,其想法是用户登录以查看可以点击的特定城市的概述。点击这些城市将放大到该特定城市。下面的代码可以帮助您实现这一目标。

我无法弄清楚的是,我还想提供一个按钮(在选择城市后出现),名为"返回查看其他城市"点击后,将重置"地图回到原来的状态。

但是,当我点击按钮时,出现以下错误:

  

警告:UseMethod中出错:没有适用于' metaData'的方法应用于类" NULL"

的对象

我在这里使用input$map_marker_click来确定应用应该放大哪个城市,我认为问题的一部分是我无法将其设置回其初始状态单击后为NULL。我还有另一种方法吗?

library(shiny)
library(leaflet)
library(leaflet.extras)
library(dplyr)

cities <- data.frame(cities = c("London", "Chicago", "New York", "Philadelphia", "Los Angeles"),
                 lng = c(-0.118092, -87.6298, -74.0060, -75.1642, -118.2477),
                 lat = c(51.509865, 41.848, 40.7128, 39.9586, 34.0522),
                 zoom = c(11, 11, 12, 12, 10))

ui <- bootstrapPage(
  tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
  leafletOutput("map", width = "100%", height = "100%"),
  conditionalPanel("isNaN(input.map_marker_click)", uiOutput("controls"))
)

server <- function(input, output, session) {

  output$map <- renderLeaflet({
    leaflet(cities, width = "100%", height = "100%") %>%
      addProviderTiles("CartoDB.DarkMatter") %>%
      setView(lng = -56, lat = 49.2402, zoom = 4) %>% 
      addPulseMarkers(lng = ~lng, lat = ~lat,
                      label = ~cities,
                      icon = makePulseIcon())
  })

  output$controls <- renderUI({
    req(input$map_marker_click)
    absolutePanel(id = "controls", top = 100, left = 50, 
                    right = "auto", bottom = "auto", width = "auto", height = "auto",
                    actionButton(inputId = "reset", label = "Return to see other cities", class = "btn-primary")
    )
  })

  observeEvent(input$map_marker_click, {
    city_selected <- filter(cities, lat == input$map_marker_click$lat[1])

    leafletProxy("map") %>%
      clearMarkers() %>%
      clearControls() %>%
      setView(lng = city_selected$lng[1], lat = city_selected$lat[1], zoom = city_selected$zoom[1])
  })

#I know the below is wrong, but I don't know what I'm supposed to do to "reset" the map.
  observeEvent(input$reset, {

    leafletProxy("map") %>%
      setView(lng = -56, lat = 49.2402, zoom = 4) %>%
      addPulseMarkers(lng = ~lng, lat = ~lat,
                      label = ~cities,
                      icon = makePulseIcon())
  })
}

shinyApp(ui, server)

2 个答案:

答案 0 :(得分:1)

我需要在上次data = cities来电中添加addPulseMarkers()

observeEvent(input$reset, {

leafletProxy("map") %>%
  setView(lng = -56, lat = 49.2402, zoom = 4) %>%
  addPulseMarkers(data = cities, lng = ~lng, lat = ~lat,
                  label = ~cities,
                  icon = makePulseIcon())
})

答案 1 :(得分:1)

替代的基于反应的输出

将地图创建封装在一个函数中,这样只需一个没有代码重复的函数调用就可以更轻松地重置:

library(shiny)
library(leaflet)
library(leaflet.extras)
library(dplyr)
library(shinyjs) #for hide function

cities <- data.frame(cities = c("London", "Chicago", "New York", "Philadelphia", "Los Angeles"),
                     lng = c(-0.118092, -87.6298, -74.0060, -75.1642, -118.2477),
                     lat = c(51.509865, 41.848, 40.7128, 39.9586, 34.0522),
                     zoom = c(11, 11, 12, 12, 10))

ui <- bootstrapPage(
  useShinyjs(),
  tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
  leafletOutput("map", width = "100%", height = "100%"),
  conditionalPanel("isNaN(input.map_marker_click)", uiOutput("controls"))
)

server <- function(input, output, session) {

  #creating the first map within a function so that reset becomes easy

  base_map <- function(){
    leaflet(cities, width = "100%", height = "100%") %>%
      addProviderTiles("CartoDB.DarkMatter") %>%
      setView(lng = -56, lat = 49.2402, zoom = 4) %>% 
      addPulseMarkers(lng = ~lng, lat = ~lat,
                      label = ~cities,
                      icon = makePulseIcon())
  }

  # reactiveVal for the map object, and corresponding output object.
  react_map <- reactiveVal(base_map())
  output$map <- renderLeaflet({
    react_map()
  }) 

  output$controls <- renderUI({
    req(input$map_marker_click)
    absolutePanel(id = "controls", top = 100, left = 50, 
                  right = "auto", bottom = "auto", width = "auto", height = "auto",
                  actionButton(inputId = "reset", label = "Return to see other cities", class = "btn-primary")
    )
  })

  observeEvent(input$map_marker_click, {
    city_selected <- filter(cities, lat == input$map_marker_click$lat[1])

    show('controls')

    leafletProxy("map") %>%
      clearMarkers() %>%
      clearControls() %>%
      setView(lng = city_selected$lng[1], lat = city_selected$lat[1], zoom = city_selected$zoom[1])
  })

  # Making the entire map creation inside reactive function makes it easier to reset
  observeEvent(input$reset, {

    #hiding the control button
    hide('controls')

    # resetting the map

    react_map(base_map()) 

  })
}

shinyApp(ui, server)