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

在Shiny模块中集成JavaScript:趋势线不显示问题排查

问题解决:Shiny应用中趋势线无法显示(已获取客户端时区)

问题背景

开发了一个可生成时间序列数据趋势线的Shiny应用,通过JavaScript代码获取客户端时区,用于将时序数据转换为本地时区。目前浏览器控制台能正常输出时区信息,但趋势线无法显示。

问题根源分析

  1. 未使用模块命名空间传递时区参数:模块内的JavaScript代码直接设置了client_timezone输入值,但模块的输入需要带有命名空间前缀,导致服务器端无法接收到时区数据,req(timezone)一直不满足,Plotly图表无法渲染。
  2. 重复执行时区获取逻辑:无触发条件的observe会反复执行JavaScript代码,造成不必要的资源消耗。
  3. 未实现时区转换逻辑:原代码没有将UTC时间转换为客户端本地时区,未完成核心需求。

修复方案

1. 为JS输入值添加模块命名空间

在模块服务器中获取命名空间前缀,传递给JavaScript,确保输入值能被模块正确接收。

2. 优化时区获取触发时机

使用session$onFlushed在应用初始化时仅执行一次时区获取,避免重复执行。

3. 实现UTC时间到本地时区的转换

利用lubridate包将UTC时间转换为客户端本地时区的时间,用于图表展示。

修复后的完整代码

library(shiny)
library(shinyjs)
library(plotly)
library(dplyr)
library(lubridate)

# JavaScript code(新增命名空间参数)
jsCode <- '
shinyjs.getClientTimezone = function(namespace) {
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  // 使用命名空间设置输入值
  Shiny.setInputValue(namespace + "client_timezone", timezone);
  console.log("Client Timezone", timezone);
}'

# Module UI
mod_trend_chart_ui <- function(id) {
  ns <- NS(id)
  tagList(
    shinyjs::useShinyjs(),
    shinyjs::extendShinyjs(text = jsCode, functions = "getClientTimezone"),
    plotlyOutput(ns("trend_chart"))
  )
}

# Module Server
mod_trend_chart_server <- function(id, raw_data, processed_data) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    
    # 初始化时执行一次时区获取
    session$onFlushed(function() {
      shinyjs::js$getClientTimezone(ns(""))  # 传递命名空间前缀
    }, once = TRUE)
    
    client_timezone <- reactive({
      req(input$client_timezone)
      print(paste("Received client timezone:", input$client_timezone))
      input$client_timezone
    })
    
    # 转换时间为客户端时区
    converted_data <- reactive({
      req(client_timezone())
      tz <- client_timezone()
      
      raw <- raw_data() %>%
        mutate(local_timestamp = with_tz(utc_timestamp, tzone = tz))
      
      processed <- processed_data() %>%
        mutate(local_timestamp = with_tz(utc_timestamp, tzone = tz))
      
      list(raw = raw, processed = processed)
    })
    
    output$trend_chart <- renderPlotly({
      req(converted_data())
      data <- converted_data()
      raw <- data$raw
      processed <- data$processed
      
      if (nrow(raw) == 0 && nrow(processed) == 0) {
        return(plot_ly() %>%
                 layout(title = "No data available."))
      } else {
        p <- plot_ly() %>%
          add_trace(
            data = raw, x = ~local_timestamp, y = ~value, name = "原始数据", type = "scatter", mode = "lines",
            line = list(color = "#f69a8e", shape = "hv"),
            hovertemplate = "时间:%{x}<br>数值:%{y:.2f}"
          ) %>%
          add_trace(
            data = processed, x = ~local_timestamp, y = ~value, name = "处理后数据", type = "scatter", mode = "lines",
            line = list(color = "#6bbcf3", shape = "hv"),
            hovertemplate = "时间:%{x}<br>数值:%{y:.2f}"
          ) %>%
          layout(xaxis = list(title = "时间"), yaxis = list(title = "数值"))
        
        return(p)
      }
    })
  })
}

# Sample data
raw_data_sample <- data.frame(
  utc_timestamp = as.POSIXct(c("2023-06-01 10:00:00", "2023-06-01 11:00:00", "2023-06-01 12:00:00"), tz = "UTC"),
  value = c(10, 20, 30)
)

processed_data_sample <- data.frame(
  utc_timestamp = as.POSIXct(c("2023-06-01 10:00:00", "2023-06-01 11:00:00", "2023-06-01 12:00:00"), tz = "UTC"),
  value = c(15, 25, 35)
)

# Main UI
ui <- fluidPage(
  mod_trend_chart_ui("trendChart")
)

# Main Server
server <- function(input, output, session) {
  raw_data <- reactiveVal(raw_data_sample)
  processed_data <- reactiveVal(processed_data_sample)
  
  mod_trend_chart_server("trendChart", raw_data, processed_data)
}

# Run the app
shinyApp(ui, server)

关键修复点说明

  • 命名空间处理:通过向JS函数传递模块命名空间前缀,确保client_timezone输入值能被模块正确捕获。
  • 初始化执行:使用session$onFlushed(once = TRUE)保证时区获取仅在应用初始化时执行一次,避免重复调用。
  • 时区转换:新增converted_data reactive,将UTC时间转换为客户端本地时区时间,满足原始需求并正确渲染图表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:14:51