能否在Shiny的renderRglwidget场景中用identify3d()捕获地标坐标?
好问题!首先得明确:identify3d()是针对桌面端rgl窗口设计的交互函数,没办法直接在Shiny的renderRglwidget()生成的WebGL场景里使用。不过我们可以利用rgl对Shiny的原生交互支持,实现点击捕获地标坐标的功能,具体方案如下:
解决方案:在Shiny WebGL场景中捕获地标坐标
1. 核心思路
rgl的WebGL组件会向Shiny发送点击事件数据,我们可以通过input$<widgetId>_click获取点击位置的屏幕坐标,再结合selectpoints3d()函数匹配场景中的地标点,最终提取目标点的精确3D坐标。
2. 修改后的完整代码
UI部分
ui <- fluidPage( selectInput("mspec3D", "选择3D规格", choices = unique(out2[[6]][,3])), # 适配你现有数据的选项 rglwidgetOutput('webgl3D', width = "1200px", height = "400px"), verbatimTextOutput("captured_coords") # 用于展示捕获的坐标 )
Server部分
server <- function(input, output, session) { observeEvent(input$mspec3D, { tt1 <- out2[[6]][out2[[6]][,3] == input$mspec3D, ][1] tt1 <- as.numeric(tt1) tt2 <- out2[[6]][out2[[6]][,3] == input$mspec3D, ][2] tt2 <- as.numeric(tt2) tt1 <- out2[[1]][[tt1]] tt2 <- out2[[1]][[tt2]] output$webgl3D <- renderRglwidget ({ try(rgl.close()) # 绘制地标点,保留可识别的属性 points3d(tt1, size=3, col="dimgray", box=FALSE) points3d(tt2, size=3, col="dodgerblue", box=FALSE) axes3d() # 绑定点击事件,将屏幕坐标传递给Shiny rglwidget() %>% onRender("function(el, x) { el.addEventListener('click', function(e) { Shiny.setInputValue('webgl3D_click', {x: e.clientX, y: e.clientY}); }); }") }) }) # 捕获点击并提取坐标 observeEvent(input$webgl3D_click, { # 匹配点击位置对应的3D点 selected_idx <- selectpoints3d(input$webgl3D_click) if (!is.null(selected_idx)) { # 获取选中点的坐标 all_points <- rgl::rgl.attrib("points", "vertices") target_coords <- all_points[selected_idx, ] # 在界面展示结果 output$captured_coords <- renderPrint({ cat("捕获的地标坐标:\n") cat(sprintf("X: %.4f\nY: %.4f\nZ: %.4f", target_coords[1], target_coords[2], target_coords[3])) }) } }) } shinyApp(ui, server)
3. 关键细节说明
selectpoints3d():根据点击的屏幕坐标,自动匹配场景中距离最近的3D点,返回该点的索引;可通过threshold参数调整点击灵敏度(默认10像素)。rgl.attrib("points", "vertices"):提取场景中所有点的坐标矩阵,通过索引即可拿到目标点的精确3D坐标。- 点击事件绑定:通过
onRender()给WebGL组件添加监听,将屏幕点击坐标发送到Shiny的输入对象,实现交互联动。
4. 注意事项
- 确保你的rgl版本≥0.107.14,较新版本对Shiny交互的支持更稳定。
- 如果场景中有大量重叠点,建议调整点的
size或col属性,提升点击识别的准确性。
内容的提问来源于stack exchange,提问作者JJL
相关产品推荐
相关产品推荐

