R Shiny中mapedit editMod加载Shapefile无法在地图显示的求助
问题描述
在R Shiny应用中使用editMod()实现手动绘制多边形或加载Shapefile功能时,面积计算功能正常,但加载的Shapefile无法在editMod绑定的Leaflet地图上显示,仅能参与后续面积计算。
解决方法
问题根源是加载的Shapefile未被添加到editMod对应的Leaflet地图实例中。需要通过以下步骤修复:
- 利用
editMod返回的地图引用,在Shapefile加载完成后动态添加到地图上 - 使用
leafem::addFeatures实现矢量要素的添加,并通过Shiny的session对象触发地图更新 - 优化文件保存逻辑,避免同名文件覆盖(可选)
修改后的完整代码
### 加载依赖包 library(dplyr) library(plyr) library(shiny) library(leaflet) library(mapedit) library(sf) library(leaflet.esri) library(leafem) library(DT) library(shinycssloaders) library(htmlwidgets) ################# ### 创建UI ### ################# ui <- shinyUI( fluidPage( sidebarLayout( # 地图面板 mainPanel( editModUI("map", height=600), fileInput("filemap", "上传Shapefile", accept=c('.shp','.dbf','.sbn','.sbx','.shx',".prj"), multiple=TRUE) ), # 结果面板 sidebarPanel( actionButton("calc_button", "计算面积", icon = icon("arrow-right")), conditionalPanel(condition = "input.calc_button >= 1", withSpinner(DT::DTOutput('TableIndex')) ) ) ) ) ) ##################### ### 创建server ### ##################### server <- function(input, output, session) { ### 响应式变量定义 shp_impact <- reactiveVal(data.frame()) LoadedShape <- reactiveVal(data.frame()) TableIndex <- reactiveVal() ### 初始化编辑地图 # 保存editMod返回的地图引用,用于后续更新 map_edit_result <- callModule( editMod, leafmap = leaflet() %>% addTiles(group="OpenStreetMap") %>% addDrawToolbar( polylineOptions = FALSE, circleOptions = FALSE, rectangleOptions = FALSE, markerOptions = FALSE, circleMarkerOptions = FALSE, editOptions=editToolbarOptions(edit=TRUE, remove=TRUE) ), id = "map", record = FALSE, sf = TRUE ) ### 加载并显示Shapefile observeEvent(input$filemap, { # 创建临时目录保存上传的文件,避免同名覆盖 temp_dir <- tempdir() for(i in 1:nrow(input$filemap)){ file.copy(input$filemap$datapath[i], file.path(temp_dir, input$filemap$name[i])) } # 检查Shapefile完整性 Names_comb <- paste(input$filemap$name, collapse="_") if(!all(c(".dbf", ".shp", ".prj", ".shx") %in% tools::file_ext(input$filemap$name))){ showNotification(ui=HTML("<b>无效的Shapefile:必须包含.shp, .shx, .prj, .dbf文件</b>"), type="error", duration=8) return(data.frame()) } # 读取并转换坐标系 ShapeName <- file.path(temp_dir, input$filemap$name[tools::file_ext(input$filemap$name)=="shp"]) Shape <- st_read(ShapeName) %>% st_transform(4326) LoadedShape(Shape) # 将加载的Shapefile添加到editMod的地图上 map_edit_result$map_proxy %>% addFeatures(Shape, color = "#ff0000", weight = 2, fillOpacity = 0.3) %>% updateMapedit(session, "map") }) ### 计算面积 observeEvent(input$calc_button, { # 合并绘制的要素和加载的Shapefile drawn_data <- map_edit_result$finished() loaded_data <- LoadedShape() if(nrow(drawn_data) > 0 && nrow(loaded_data) == 0){ shp_impact(drawn_data) print("数据来源:仅手动绘制") } else if(nrow(drawn_data) == 0 && nrow(loaded_data) > 0){ shp_impact(loaded_data) print("数据来源:仅上传的Shapefile") } else if(nrow(drawn_data) > 0 && nrow(loaded_data) > 0){ shp_impact(rbind(drawn_data[, "geometry"], loaded_data[, "geometry"])) print("数据来源:手动绘制+上传Shapefile") } # 生成结果表格 if(nrow(shp_impact()) > 0){ TableIndex(data.frame(Area = st_area(shp_impact()))) } }) ### 输出结果表格 output$TableIndex <- DT::renderDT({ req(TableIndex()) TableIndex() }) } ########### ### 运行应用 ### ########### shinyApp(ui = ui, server = server)
关键修改点说明
- 保存地图引用:将
editMod的返回值赋值给map_edit_result,通过map_edit_result$map_proxy获取地图代理对象,用于后续动态更新。 - 动态添加要素:在Shapefile加载完成后,调用
addFeatures将其添加到地图,再通过updateMapedit触发地图刷新。 - 临时目录优化:使用
tempdir()创建临时目录保存上传文件,避免同名文件覆盖导致读取错误。 - 文件检查优化:用
tools::file_ext替代字符串截取,更可靠地检查文件扩展名。
内容的提问来源于stack exchange,提问作者Victor Cz
相关产品推荐
相关产品推荐

