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

Shiny中实现可滚动盒子内绘图的X轴刷选与滚动同步

解决Shiny中可滚动绘图的X轴刷选异常问题

当把宽幅plotOutput放入设置了style='width:600px;overflow-x:scroll;'的box后,Shiny的X轴刷选功能会出现坐标偏移问题,且无法实现刷选时滚动条同步移动的效果。可以通过自定义JavaScript代码修正坐标并同步滚动,以下是完整解决方案:

完整可运行代码

library(shiny)
library(ggplot2)
library(shinydashboard)

test_ui <- function(id){
  ns <- NS(id)
  
  brush_options <- brushOpts(id = ns("brush"), fill = "#99CCFF", stroke = "#003366", opacity = 0.25,
                             delay = 1, delayType = "debounce", clip = TRUE,
                             direction = "x", resetOnNew = TRUE)
  
  tagList(
    tags$script(HTML(sprintf("
      // 监听brush事件,修正坐标并同步滚动
      $(document).on('shiny:brush', '#%s', function(e) {
        const plotContainer = $('#%s').closest('.box');
        const scrollLeft = plotContainer.scrollLeft();
        const brush = e.brush;
        
        // 修正brush的x坐标,补上滚动偏移量
        brush.x1 += scrollLeft;
        brush.x2 += scrollLeft;
        
        // 计算刷选区域中心,同步滚动条位置
        const brushCenter = (brush.x1 + brush.x2) / 2;
        const containerWidth = plotContainer.width();
        const targetScroll = brushCenter - containerWidth / 2;
        
        // 平滑滚动到目标位置
        plotContainer.animate({
          scrollLeft: targetScroll
        }, 100);
      });
      
      // 监听滚动事件,修正已存在的brush坐标
      $(document).on('scroll', '.box', function() {
        const plotId = '%s';
        const brush = Shiny.getInputValue(plotId + '_brush');
        if(brush) {
          const scrollLeft = $(this).scrollLeft();
          // 反向修正坐标,确保服务器端拿到正确的绘图坐标
          Shiny.setInputValue(plotId + '_brush', {
            ...brush,
            x1: brush.x1 - scrollLeft,
            x2: brush.x2 - scrollLeft
          }, {priority: 'event'});
        }
      });
    ", ns("plot"), ns("plot"), ns("plot")))),
    box(style='width:600px;overflow-x:scroll;',
        plotOutput(outputId = ns("plot"), brush = brush_options, height=600, width=1600)
    )
  )
}

test_server <- function(id){
  moduleServer(id, function(input, output, session){
    ns <- session$ns
    
    output$plot <- renderPlot({
      ggplot(mtcars, aes(x = mpg, y = drat)) + geom_point()
    })
    
    # 可选:打印刷选的X范围,验证坐标正确性
    observe({
      if(!is.null(input$brush)){
        cat("刷选X范围:", input$brush$x1, "到", input$brush$x2, "\n")
      }
    })
  })
}

demoApp <- function() {
  ui <- fluidPage(
    test_ui("demo")
  )
  server <- function(input, output, session) {
    test_server("demo")
  }
  shinyApp(ui, server)  
}

demoApp()

关键逻辑说明

  • brush事件修正:触发shiny:brush事件时,获取容器的滚动偏移量,修正brush的X坐标(默认brush坐标仅相对于可见容器,而非完整绘图),同时计算刷选区域中心,让滚动条平滑滚动到对应位置,实现刷选与滚动同步。
  • 滚动事件修正:用户手动滚动容器时,反向修正已存在的brush坐标,确保服务器端获取的是相对于完整绘图的正确X范围,避免后续处理偏差。
  • 平滑滚动:使用jQuery的animate方法实现滚动条的平滑移动,提升交互体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:14:58