Shiny嵌入Leaflet地图点击按钮替换起止点标记异常问题求助
问题根因
- 核心错误是嵌套注册监听器:每点击一次起点/终点按钮,就会新增一个独立的地图点击监听器,多次操作后多个监听器同时生效,触发一次地图点击就会同时执行所有已注册的更新逻辑,导致两个标记被同时修改。
- 自动读取历史点击的问题源于
observeEvent默认ignoreInit = FALSE,新监听器注册时如果已经有历史地图点击记录,会直接触发一次执行。
修复方案
新增一个全局响应式变量存储当前编辑状态,仅注册一次地图点击监听器,根据状态判断要更新的标记类型即可,完整修改代码如下:
library(shiny) library(shinyWidgets) library(leaflet) library(RColorBrewer) library(osrm) ui <- bootstrapPage( tags$style(type = "text/css", "html, body {width:100%;height:100%}"), leafletOutput("map", width = "100%", height = "100%"), absolutePanel(top = 10, right = 10, actionButton("change_orig", "Origine"), actionButton("change_dest", "Destination"), ) ) server <- function(input, output, session) { origin_icon = makeIcon("https://static.thenounproject.com/png/1477944-200.png", iconWidth=24, iconHeight=30) destination_icon = makeIcon("https://static.thenounproject.com/png/924206-200.png", iconWidth=24, iconHeight=30) output$map <- renderLeaflet({ leaflet() %>% addTiles(providers$OpenStreetMap) %>% addProviderTiles(providers$OpenStreetMap, group="Open Street Map") %>% addProviderTiles(providers$OpenTopoMap, group="Open Topo Map") %>% fitBounds(2.907730, 45.856550, 3.310954, 45.714034) %>% addLayersControl( baseGroups = c("Open Street Map", "Open Topo Map") ) }) # 存储当前编辑模式:可选值为 NULL/"origin"/"destination" edit_mode <- reactiveVal(NULL) # 点击起点按钮切换编辑模式为修改起点 observeEvent(input$change_orig, { edit_mode("origin") }) # 点击终点按钮切换编辑模式为修改终点 observeEvent(input$change_dest, { edit_mode("destination") }) # 全局监听地图点击事件,ignoreInit = TRUE 忽略历史点击记录 observeEvent(input$map_click, { current_mode <- edit_mode() # 未选中编辑模式时不执行操作 if (is.null(current_mode)) return() click <- input$map_click proxy <- leafletProxy('map') if (current_mode == "origin") { proxy %>% clearGroup("origin") %>% addMarkers(lng=click$lng, lat=click$lat, icon=origin_icon, group="origin") } else if (current_mode == "destination") { proxy %>% clearGroup("destination") %>% addMarkers(lng=click$lng, lat=click$lat, icon=destination_icon, group="destination") } # 可选配置:修改完成后自动退出编辑模式,下次修改需重新点击对应按钮 # edit_mode(NULL) }, ignoreInit = TRUE) } shinyApp(ui, server)
修改后点击起点按钮后,后续地图点击只会更新起点标记;点击终点按钮后地图点击只会更新终点标记,两个标记互不干扰,也不会自动读取历史点击记录。如果需要支持连续多次更新同类型标记,注释掉最后edit_mode(NULL)的代码即可。
内容的提问来源于stack exchange,提问作者Laurent
相关产品推荐
相关产品推荐

