TLDR:如何创建一个计时器对象来刷新闪亮应用程序中的部分,这应该是我可以跨应用程序导入的模块,以使所有内容与暂停/编辑间隔的能力保持同步。
我正在编写一个闪亮的应用程序。在此应用程序中,我有多个部分想要定期更新。
我正在寻找一种创建计时器对象的方法,我可以用它来按给定的时间间隔刷新不同的部分,以及一种暂停/更改reactiveTimer的时间间隔的方法。
我想出了在模块中使用通用计时器对象 (
setInterval
) 的想法(使用 rhino
和 box
),我将其导入到其他模块中并与 shiny$observeEvent(timer()...
一起使用。
这是一个简单的计时器,它所做的只是每 500 毫秒触发一次。现在我想添加暂停和编辑间隔的功能。
# Set up a common reactive timer to trigger every 500 ms
common_timer <- shiny$reactiveTimer(interval = 1500)
#' @export
timer <- function() {
return(common_timer())
}
我尝试了一些不同的事情,例如创建一个
R6
类来处理计时器的状态(活动/非活动);返回计时器对象或 NULL
。但我无法让任何东西正常工作。我的 R6
类可以工作,但是当我暂停计时器时,我无法让它再次重新启动。
这是我的一些代码。这是我如何使用计时器将一些数据输入我的应用程序的示例。
box::use(shiny)
#' @export
live_data <- shiny$reactiveVal(NULL)
#' @export
date_interval <- shiny$reactiveValues(
start_date = lubridate::as_datetime("2019-01-01"),
end_date = lubridate::as_datetime("2019-01-28")
)
box::use(lubridate)
box::use(./common_timer[ timer ])
box::use(./modules/helpers)
box::use(./modules/cpp)
#' @export
call_data <- function(session, side_bar_options) {
shiny$observeEvent(timer$get_timer, {
currency <- shiny$isolate(side_bar_options$currency())
dt <- helpers$read_market_data(
file = "./data/kucoin_btc-usdt-hourly.csv",
symbols = currency,
from = date_interval$start_date,
to = date_interval$end_date
)
live_data(dt)
# bump the dates by 10 days
date_interval$start_date <- date_interval$start_date + lubridate$days(1)
date_interval$end_date <- date_interval$end_date + lubridate$days(1)
})
}
这是我想要暂停的地方,然后添加编辑计时器间隔的功能。
box::use(shiny)
#' @export
ui <- function(id, width = 2) {
ns <- shiny$NS(id)
shiny$sidebarPanel(
shiny$tags$h4("Side bar"),
shiny$selectInput(
inputId = ns("select_currency"),
label = "Currency:",
choices = c("BTC/USDT", "XMR/BTC"),
selected = "BTC/USDT"
),
shiny$selectInput(
inputId = ns("supplementary_plot"),
label = "Supplementary Plot:",
choices = c("RSI", "MACD", "Volume")
),
shiny$actionButton(
inputId = ns("toggle_timer"),
label = "Start/Pause"
),
width = width
)
}
box::use(../logic/common_timer[ timer ])
#' @export
server <- function(id, live_data) {
shiny$moduleServer(id, \(input, output, session) {
ns <- session$ns
shiny$observeEvent(input$toggle_timer, {
timer$toggle_timer()
})
supplementary_plot <- shiny$reactive({
input$supplementary_plot
})
currency <- shiny$reactive({
input$select_currency
})
return(list(
currency = currency,
supplementary_plot = supplementary_plot
))
})
}
如有任何帮助,我们将不胜感激。非常感谢。
我对原始示例进行了尽可能少的修改来演示这一点;并将解决方案交叉发布到社区。
library(shiny)
usesTimerModUI <- function(id) {
ns <- NS(id)
tagList(
div(style="border:1px solid black;",
h4(ns("")),
verbatimTextOutput(ns("display"))
))
}
usesTimerModServer <- function(id,source_timer) {
moduleServer(
id,
function(input, output, session) {
stopifnot(is.reactive(source_timer))
output$display <- renderText({
capture.output(req(source_timer()))
})
}
)
}
ui <- fluidPage(
numericInput("ms","millisec",
value=1000,
min=100,
max=2000,
step=100),
checkboxInput("chk","on/off",value=TRUE),
hr(),
usesTimerModUI("m1"),
br(),
usesTimerModUI("m2")
)
# to see more decimal points
op <- options(digits.secs = 6)
server <- function(input, output, session) {
mytimer <- reactive({
if(!isTruthy(input$chk)){
return(NULL)
} else{
invalidateLater(millis=req(input$ms))
}
Sys.time()
})
last_timer_value <- reactiveVal(NULL)
observeEvent(mytimer(),
{if(!identical(last_timer_value,
mytimer())){
if(isTruthy(mytimer()))
last_timer_value(mytimer())
}})
usesTimerModServer(id="m1",
source_timer = last_timer_value)
usesTimerModServer(id="m2",
source_timer = last_timer_value)
}
shinyApp(ui, server)