仅当使用 LayersControl 的缩放级别> 8 时,才在 Shiny 的传单地图中显示图层?

Posted

技术标签:

【中文标题】仅当使用 LayersControl 的缩放级别> 8 时,才在 Shiny 的传单地图中显示图层?【英文标题】:Show layer in leaflet map in Shiny only when zoom level > 8 with LayersControl? 【发布时间】:2017-05-30 17:06:06 【问题描述】:

我只想在图层控件中单击图层并且缩放级别大于某个数字时才显示图层,例如8. 原因之一是必须执行一些昂贵的计算才能获得层坐标。我想使用图层控件而不是额外的输入按钮(出于光学原因)。

如果在图层控件中单击图层按钮,有没有办法检索该值?

这是一个简单的例子(不工作):

library(leaflet) 
library(shiny)

ui <- fluidPage(
  leafletOutput("map", width = "100%", height = "700")
)

server <- function(input, output)
  output$map <- renderLeaflet(
    leaflet() %>% addTiles() %>% setView(10.4, 50.3, 7) %>%
      addLayersControl(overlayGroups = c("marker"),
                       options = layersControlOptions(collapsed = FALSE))
  )

  observe(
   # if (input$marker == TRUE) # how to get value if layercontrol is clicked?
      if (input$map_zoom > 8) 
        leafletProxy("map") %>% addMarkers(lng = 10.5, lat = 50, group = "marker")
      
  #  
  )


shinyApp(ui = ui, server = server)

【问题讨论】:

根据my comment to this question,我还没有遇到对“layerControl”点击做出反应的方法。 【参考方案1】:

这是第一个运行的版本。也许 smdy 想出了 sthg "cleaner" :)。

这里做个小解释:

挑战 1:input$marker 不作为闪亮的输入存在。 打开您的应用程序(在浏览器中),右键单击您感兴趣的标记输入,然后在浏览器中选择“检查元素”或等效标签。您将看到该输入的代码。 那为什么你不能访问它。要查看您从闪亮中知道的输入类型的差异,请创建textinput 或 sthg 并同时创建“检查元素”。您会看到闪亮的输入有一个 id,....标记输入没有

挑战 2:访问没有 id 的输入: (从这里开始你应该知道如何从 JS 向 R 发送消息并返回:一篇非常好的文章,你会在这里找到:https://ryouready.wordpress.com/2013/11/20/sending-data-from-client-to-server-and-back-using-shiny/) 如何访问输入:嗯,这基本上只是通过谷歌找到正确的 sn-p。最后是:document.getElementsByTagName("input")。 (注意:从这里开始我假设你只有一个输入) 并且知道这有点棘手。尝试访问 这个输入。通过console.log(),您可以打印到javascript控制台(并通过“F12”在正在运行的应用程序中打开它——>控制台(JS)。) 您可以将此输入打印为 htmlCollection,但不能访问它,这可能会非常混乱。

挑战 3:访问​​ HTMLCollection

您无法访问它的原因(简而言之)是在构建“DOM”之前调用了JS代码。如果在“&lt;body&gt;&lt;/body&gt;”之后调用脚本,它将完全正常工作。但这对于普通的香草光泽并不是那么容易。你可以试试window.onload()document.ready()。 到目前为止,对我来说最可靠的是使用: session$onFlushed() 并触发将该函数中的 JSCode 从 R 发送到“JS”。 (然后将值作为输入通过Shiny.onInputChange("marker", inputs[0].checked) 发送回R;)-> 这将产生所需的“input$marker”。 然而,这个函数只触发一次,这是完全正确的行为。但是当你点击按钮时你不会有更新。

挑战 4:更新 input$marker 那么漂亮的版本是有一个函数.onclicked()/ 一个输入的监听器。也许有人可以找到解决方案。我尝试了一个闪亮的解决方法,我告诉闪亮通过autoInvalidate()不断获取输入的值。

挑战 5: 好吧,没那么难,因为它只是有光泽,但为了完整性。鉴于问题中提供的代码,标记将在加载一次时保留。一旦不满足缩放标准,不确定是要保留还是删除它。 不管怎样,如果你想让它消失,%&gt;% clearMarkers() 就是你的朋友。

library(leaflet)
library(shiny)

getInputwithJS <- '
Shiny.addCustomMessageHandler("findInput",
  function(message) 
  var inputs = document.getElementsByTagName("input");
  Shiny.onInputChange("marker", inputs[0].checked);

);
'

ui <- fluidPage(

  leafletOutput("map", width = "100%", height = "700"),
  tags$head(tags$script(HTML(getInputwithJS)))
)

server <- function(input, output, session)
  global <- reactiveValues(DOMRdy = FALSE)
  output$map <- renderLeaflet(
    leaflet() %>% addTiles() %>% setView(10.4, 50.3, 7) %>%
      addLayersControl(overlayGroups = c("marker"),
                       options = layersControlOptions(collapsed = FALSE))
  )

  autoInvalidate <- reactiveTimer(1)

  observe(
    autoInvalidate()
    if(global$DOMRdy)
      session$sendCustomMessage(type = "findInput", message = "")      
    
  )

  session$onFlushed(function() 
    global$DOMRdy <- TRUE
  )

  observe(
    if (!is.null(input$marker))
      if (input$marker == TRUE) # how to get value if layercontrol is clicked?
        if (input$map_zoom > 8) 
          leafletProxy("map") %>% addMarkers(lng = 10.5, lat = 50, group = "marker")
        else
          leafletProxy("map") %>% clearMarkers()
        
      
    
  )


shinyApp(ui = ui, server = server)

【讨论】:

非常好的答案。如果您也添加关于它在做什么的解释将会很有帮助。 不错的解决方案!它适用于最小的例子。但是我无法将它用于具有其他命名输入(例如 checkboxInputs 等)的更复杂的应用程序中。那需要做哪些改变呢?重要的是,我将 tags$head 部分放在 UI 中的什么位置? 嗨@needRhelp。在上面的代码中添加:"var inputs = document.getElementsByTagName("input");"一行代码“console.log(inputs)”。然后在浏览器中运行应用程序并检查日志(F12 - 控制台 JS)并找到您的“标记输入”具有哪个索引并将该索引用于下一行代码:“Shiny.onInputChange("marker", inputs[ 0].检查);"您将 0 替换为 nex 索引的位置。希望对您有所帮助。 嗨@TonioLiebrand。工作正常。我还有一个问题:当应用程序启动时,默认情况下会在图层控件中检查标记。有没有一种简单的方法来改变它,以便在应用启动时不检查层控件中的条目? @needRhelp,在您的传单代码中使用hideGroup。所以它应该看起来像这样:addLayersControl(overlayGroups = ("marker")) %&gt;% hideGroup("marker")

以上是关于仅当使用 LayersControl 的缩放级别> 8 时,才在 Shiny 的传单地图中显示图层?的主要内容,如果未能解决你的问题,请参考以下文章

仅当缩放高于某个值时才显示markerOptions 的优化而非弃用方式

使用 javascript 检测浏览器缩放级别

百度地图怎么控制最大缩放级别

仅当存在警告或更严重级别的日志事件时记录所有级别

使用 MKUserTrackingBarButtonItem 时如何指定缩放级别?

Apache Tiles 失败并出现错误,但仅当日志级别设置大于 INFO 时?