提问人:Faustin Gashakamba 提问时间:11/16/2023 更新时间:11/16/2023 访问量:19
如何防止传单地图在 R/shiny 中发生双击事件时放大
How to prevent a leaflet map from zooming in when a double-click event occurs in R/shiny
问:
我正在 UI 的此输出小部件中以 R/shiny 渲染地图。
在服务器中,我使用创建地图对象,然后在我使用中显示地图。leafletOutput("map")
tmap
renderLeaflet()
tmap_leaflet(tmap_object)
我想单击地图上的要素,捕获单击的坐标,以便选择单击的要素。我会使用此信息在另一个小部件中显示表格。 这是我的完整服务器功能:
server <- function(input, output, session) {
# get user input
my_season <- reactive(input$my_season)
statistic <- reactive(input$statistic)
# filter the data using user input
my_data <- reactive({
data_filtered <- data %>% filter(season == my_season())
return(data_filtered)
})
# display map
output$map <- renderLeaflet({
# create the tmap object
tmap_object <- tm_shape(my_data()) + tm_borders() +
tm_fill(col = statistic(),
title = str_to_sentence(str_replace_all(statistic(), "_", " ")),
style = "jenks",
palette = viridis(7),
id = "sector",
alpha = .6) +
tm_shape(country) + tm_borders(lwd = 2) +
tm_view(bbox = st_bbox(country)) # Set the initial extent to fit the "country" layer
# convert the tmap object to a leaflet map
tmap_leaflet(tmap_object)
})
# Create a reactive value to store the clicked coordinates
clicked_coords <- reactiveValues(lon = NA, lat = NA)
# Observe the map_click event and get coordinates of the clicked spot
observeEvent(input$map_click, {
clicked_coords$lon <- input$map_click$lng
clicked_coords$lat <- input$map_click$lat
})
# display the summary of the clicked territory in a table
output$details <- renderTable({
# Filter the data given the area clicked
longitude <- as.numeric(clicked_coords$lon)
latitude <- as.numeric(clicked_coords$lat)
clicked_spot <- st_sfc(st_point(c(longitude, latitude)), crs=4326) # Create an sf point
clicked_spot <- st_transform(clicked_spot, crs = st_crs(my_data())) # Re-project the point appropriately
clicked_district <- my_data() %>% st_filter(clicked_spot, .predicate = st_contains) %>%
st_drop_geometry() %>% pull(district)
my_table <- my_data() %>% st_drop_geometry() %>%
filter(district == clicked_district)
})
}
挑战如下:
- 当我在地图上单击一次时,只显示弹出窗口,我的表没有更新。
- 当我双击地图时,我的表格会更新,但地图会同时放大。
我能否至少阻止 1 或 2(即跳过弹出窗口并将单击注册为将更新我的表的正确鼠标单击事件;或阻止双击放大我的地图)。
答:
0赞
sonshine
12/15/2023
#1
我不完全确定这是否是你所追求的,但只需单击一下即可为我工作。我认为有更好的方法可以实现这一目标(和检查),但它在我的脑海中有效且有意义。reactive()
NULL
我还建议使用可能不是您想要的,因为它会在每次单击时切换表格,而不管单击是否与数据相交。 即,我可以单击同一位置两次,它会显示表格,然后隐藏它,我不确定这是用户所期望的。您也许可以使用显示/隐藏按钮来代替?shinyjs::toggle()
此代码还添加了一个标记,用户单击该标记,我发现这很有用。无论如何,希望这会有所帮助!
library(dplyr)
library(sf)
library(leaflet)
library(shiny)
# data gen ----
# outline
outline <- system.file("gpkg/nc.gpkg", package = "sf") |>
sf::st_read() |>
sf::st_geometry() |>
sf::st_union() |>
sf::st_as_sf() |>
sf::st_transform("+proj=longlat +datum=WGS84")
# gen some polygons
poly <- outline |>
sf::st_sample(40) |>
sf::st_buffer(units::as_units(10, "mi")) |>
sf::st_as_sf() |>
dplyr::mutate(id = seq_len(dplyr::n())) |>
dplyr::mutate(color = viridisLite::viridis(dplyr::n())) |>
dplyr::rowwise() |>
dplyr::mutate(label = htmltools::HTML(
paste0(
"<b>ID:</b> ", id, " <br/>",
"<b>Color:</b> ", color
)
)) |>
dplyr::ungroup() |>
sf::st_set_agr("constant")
# ui ----
ui <- shiny::fluidPage(
leaflet::leafletOutput("map"),
shiny::tableOutput("tab")
)
# server ----
server <- function(input, output, session) {
# initial map
output$map <- leaflet::renderLeaflet({
leaflet::leaflet() |>
leaflet::addTiles(group = "OpenStreetMap") |>
leaflet::addPolygons(
data = outline,
fillOpacity = .15,
fillColor = "black",
color = "black", weight = 2
) |>
leaflet::addPolygons(
data = poly,
fillColor = ~color,
fillOpacity = .75,
stroke = FALSE,
label = ~label
)
})
# 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)
}) |>
shiny::bindEvent(input$map_click)
# pt
pt <- shiny::reactive({
if (!is.null(input$map_click$lat)) {
pt <- sf::st_point(
c(
input$map_click$lng,
input$map_click$lat
)
) |>
sf::st_sfc(crs = 4326) |>
sf::st_as_sf()
return(pt)
} else {
NULL
}
})
# intersects
intersects <- shiny::reactive({
if (!is.null(pt())) {
sf::st_intersection(pt(), poly) |>
sf::st_drop_geometry() |>
dplyr::select(-label)
} else {
NULL
}
})
# table
output$tab <- shiny::renderTable({
if (is.null(intersects())) {
return(NULL)
}
if (nrow(intersects()) > 0) {
intersects()
} else {
NULL
}
})
}
评论
0赞
Faustin Gashakamba
12/15/2023
我很欣赏在用户单击的地方添加一个标记。但是,我最初的问题都没有得到解决。我仍然必须单击一次以显示弹出窗口,然后单击第二次以显示表格。真的不是完全禁用弹出窗口的方法吗?
0赞
sonshine
12/16/2023
@FaustinGashakamba啊,我想我明白你在说什么。我建议使用基础传单而不是 tmap 来渲染地图,这样您就可以控制这些行为。我已经编辑了解决方案以包含一个标签(当您将鼠标悬停在标签上时,它会显示信息,而不必单击该点)。然后,您仍然可以单击一次并在应用中呈现表格。有关传单中的弹出窗口与标签的更多信息,请参阅 https://rstudio.github.io/leaflet/popups.html
评论