You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何关闭Shiny应用中Leaflet地图的双击缩放功能?

解决Shiny Leaflet应用的点击交互问题

问题概述

开发包含Leaflet地图的Shiny应用时遇到以下问题:

  • 单击地图仅显示工具提示,无法触发数据过滤与表格展示
  • 双击地图时功能生效,但地图会自动放大
  • 需要先单击显示工具提示,再点击一次才能展示过滤后的表格

解决方案

1. 禁用地图的单击工具提示

工具提示由tmap的tm_fill参数id = "sector"自动生成,移除该参数即可关闭默认工具提示:

tmap_object <- tm_shape(sectors) +
  tm_borders() +
  tm_fill(col = "number_of_clients",
          title = "number of clients",
          style = "jenks", 
          palette = cividis(6),
          alpha = .6) + # 移除id参数关闭默认tooltip
  tm_view(bbox = st_bbox(district))

2. 阻止双击地图放大行为

通过leafletOptions禁用Leaflet的双击缩放功能,在tmap转Leaflet对象后添加配置:

tmap_leaflet(tmap_object) %>%
  leaflet::setOptions(doubleClickZoom = FALSE)

3. 优化点击响应逻辑

使用req()简化响应式依赖判断,确保单次点击立即触发表格更新,避免延迟:

pt <- shiny::reactive({
  req(input$map_click) # 确保点击事件存在才执行
  sf::st_point(c(input$map_click$lng, input$map_click$lat)) %>%
    sf::st_sfc(crs = 4326) %>%
    sf::st_as_sf() %>%
    sf::st_transform(st_crs(district))
})

完整修改后的代码

整合所有修改后的完整应用代码:

# install required packages in they are not already installed
if(!"remotes" %in% installed.packages()){
  install.packages("remotes")
}
# list my required packages
required_pkgs = c("magrittr", "dplyr", "shiny", "bslib", "leaflet", "sf", "tmap", "viridis")

# Get the missing required packages and install them
missing_pkgs <- setdiff(required_pkgs, installed.packages()[, "Package"])
if(length(missing_pkgs) != 0){
  remotes::install_cran(missing_pkgs)
}

# load the libraries of my required packages
lapply(required_pkgs, require, character.only = T)

# Load data
district <- readRDS("district.RDS")
sectors <- readRDS("sectors.RDS")
locations <- readRDS("locations.RDS")

# Create the map with shiny
#=========================
ui <- fluidPage(
  titlePanel("My test map title"),
  fluidRow(
    column(4,
           card(
             id = "detailsCard",
             style = "height: 60vh;",
             full_screen = FALSE,
             card_header("Details at click point"),
             card_body(
               tableOutput("details")
             )
           )
    ),
    column(8,
           card(
             id = "mapCard",
             style = "height: 100vh;",
             full_screen = TRUE,
             card_header("Map"),
             card_body(
               leafletOutput("map")
             )
           )
    )
  )
)

server <- function(input, output, session) {
  output$map <- renderLeaflet({
    # create the tmap object
    tmap_object <- tm_shape(sectors) +
      tm_borders() +
      tm_fill(col = "number_of_clients",
              title = "number of clients",
              style = "jenks", 
              palette = cividis(6),
              alpha = .6) + # 移除id参数关闭tooltip
      tm_view(bbox = st_bbox(district))  # Set the initial extent to fit the AoI layer
    
    # convert the tmap object to a leaflet map 并禁用双击缩放
    tmap_leaflet(tmap_object) %>%
      leaflet::setOptions(doubleClickZoom = FALSE)
  })
  
  
  # Map click logic
  observe({
    # clear previous click
    leaflet::leafletProxy("map") %>%
      leaflet::clearMarkers()
    
    # get new click
    click <- input$map_click
    
    # add click to map
    leaflet::leafletProxy("map") %>%
      leaflet::addMarkers(lng = click$lng, lat = click$lat)
  }, priority = 100) %>%
    shiny::bindEvent(input$map_click)
  
  # pt
  pt <- shiny::reactive({
    req(input$map_click) # 确保点击事件存在
    sf::st_point(
      c(
        input$map_click$lng,
        input$map_click$lat
      )
    ) %>%
      sf::st_sfc(crs = 4326) %>%
      sf::st_as_sf() %>%
      sf::st_transform(st_crs(district))
  })
  
  # intersects
  intersects <- shiny::reactive({
    req(pt())
    sectors %>% st_filter(pt(), .predicate = st_intersects) 
  })
  
  # table
  output$details <- shiny::renderTable({
    req(intersects())
    if (nrow(intersects()) > 0) {
      locations %>% st_filter(intersects(), .predicate = st_intersects) %>% st_drop_geometry()
    } else {
      NULL
    }
  })
  
}

shinyApp(ui, server)

效果说明

  • 移除id参数后,单击地图直接触发点击事件处理,不再显示工具提示
  • 禁用doubleClickZoom后,双击地图仅执行数据过滤逻辑,不会放大地图
  • 使用req()简化代码,确保点击事件触发后立即更新表格,无需二次点击

内容的提问来源于stack exchange,提问作者Faustin Gashakamba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:35:55