【问题标题】:How to reset a Leaflet click event in Shiny如何在 Shiny 中重置传单点击事件
【发布时间】:2018-07-12 02:28:33
【问题描述】:

我正在 Shiny 中构建一个 Leaflet 应用程序,其想法是用户登录以查看可以点击的特定城市的概览。单击这些城市将放大到该特定城市。如下所示的代码可以实现这一点。

我想不通的是,我还想提供一个名为“返回以查看其他城市”的按钮(在选择城市后出现),单击该按钮时,会将地图“重置”回它的原始状态。

但是,当我点击按钮时,我收到以下错误:

警告:UseMethod 中的错误:“元数据”没有适用的方法应用于“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)

【问题讨论】:

    标签: r shiny leaflet


    【解决方案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)
    

    【讨论】:

    • 非常感谢您指路。将它包装在函数中的概念是我没有考虑过的,您的回答给了我很多学习机会。一项请求 - 您能否在 observeEvent(input$map_marker_click, {...} 中添加 show('controls') 以供将来参考?这将使按钮在下次选择城市时重新出现。
    【解决方案2】:

    我需要在最后一次addPulseMarkers() 通话中添加data = cities。

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

    【讨论】:

      猜你喜欢
      • 2017-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多