如何从timevis中的可拖动垂直条中获取日期?

时间:2016-12-01 21:01:40

标签: r charts shinyjs

我发现timevis包对于显示时间段非常有用,并且它按预期工作以显示我的数据。

我已经使用addCustomTime()函数添加一个可拖动的垂直线,这也很好用,但是,我发现我无法获得该线的当前值。

底层的js小部件公开了与元素交互的函数,但我还没有能够成功访问它们。我曾尝试使用shinyjs来捕捉时间轴发出的事件,但我也无法使用它。

我对R很有吸引力,但是对于js来说非常陌生,所以我怀疑我只是错过了一个技巧。

在我的ui.R中,我创建了一个timevisOutput对象:

fluidPage(
  timevisOutput("timeline")
)

我正在努力倾听" timechanged"事件:http://visjs.org/docs/timeline/#Events

当我在server.R中添加带有shinyjs的监听器时,我能够看到" mouseenter"事件,但" timechanged"处理程序似乎没有解雇:

onevent("mouseenter", "timeline", print("timeline: mouseenter"))
onevent("timechanged", "timeline", print("Saw timechanged!"))

visjs文档上有这个片段"如何监听选择事件":

timeline.on('select', function (properties) {
  alert('selected items: ' + properties.items);
});

我尝试在shinyjs :: extendShinyjs()调用中添加它,但这也不起作用。我添加了一个示例来监听有效的keydown事件:

$(document).keypress(function(e) { alert('Key pressed: ' + e.which); });

这让我觉得我没有正确引用时间轴对象。那里的$(文档)让我觉得我不知道如何正确地获取时间轴元素。

由于我可以看到时间轴上的mouseenter事件,但看不到它的时间变化事件,我想我需要.on()调用,但是,我不认为我引用了时间轴元素正确/.

在@afterportfolio的第一个回复之后:

这是一篇很棒的文章,谢谢!我能够确认事件的样子;我已经能够听到_selected事件,但很高兴看到。

我正在尝试获取自定义时间值,该值使用图表中的可拖动线条,它是这样添加的:

addCustomTime("mytimevis", Sys.Date(), "CustomTimeId")

底层javascript小部件(http://visjs.org/docs/timeline)的文档显示了一个事件(" timechanged"),以及一个方法(" getCustomTime()")来获取访问它的价值,但我没有在跟踪中看到事件,也无法弄清楚如何使方法调用工作。

" timechanged"事件没有显示在跟踪中,这使我认为我需要从小部件的doc发出.on()调用才能启用该事件:

timeline.on('select', function (properties) {
  alert('selected items: ' + properties.items);
});

我一直在努力让这个方法调用工作,因为理想情况下我想捕获它的变化,而且如果我可以使它工作,我应该能够使getCustomTime()方法工作井!

2 个答案:

答案 0 :(得分:4)

假设

我会回答假设您想要获取R中的数据。如果我认为不正确,请告诉我,我会调整。

带有shiny.trace 的

消息

如果您不知道,我经常使用的一个技巧是options(shiny.trace=TRUE),它会在屏幕上显示通过websocket发送的所有消息。以下是我在运行以下代码时看到的内容。

library(timevis)

data <- data.frame(
  id      = 1:4,
  content = c("Item one"  , "Item two"  ,"Ranged item", "Item four"),
  start   = c("2016-01-10", "2016-01-11", "2016-01-20", "2016-02-14 15:00:00"),
  end     = c(NA          ,           NA, "2016-02-04", NA)
)

tv <- timevis(data)

# now let's see what messages we get in Shiny
library(shiny)
options(shiny.trace=TRUE)

ui <- timevisOutput("mytimevis")
server <- function(input,output,session) {
  output$mytimevis <- renderTimevis({tv})
}

shinyApp(ui,server)

screenshot of messsage from timevis on select

我突出显示了与select相关的消息。这告诉我们,我们可以观察或回应mytimevis_selected

观察选择事件

现在,让我们关闭options(shiny.trace=FALSE)并在收到所选邮件时在R控制台中打印。

options(shiny.trace=FALSE)

ui <- timevisOutput("mytimevis")
server <- function(input,output,session) {
  output$mytimevis <- renderTimevis({tv})

  observeEvent(
    input$mytimevis_selected,
    {
      print(input$mytimevis_selected)
    }
  )
}

shinyApp(ui,server)

添加timechanged handler

根据评论并重新阅读您的问题,我现在明白您要为timechanged添加事件处理程序。我认为这段代码可以帮助你克服困难。

library(timevis)
library(shiny)
library(htmltools)
library(htmlwidgets)
library(magrittr)

tv <- timevis() %>%
  addCustomTime(Sys.Date() - 1, "yesterday") %>%
  # add an event handler since this is not one
  #   timevis provides
  htmlwidgets::onRender(
"
function(el,x) {
  // this will be our instance
  var tv = this.timeline;

  tv.on('timechanged', function(id, time) {
    //uncomment debugger if you want to stop here
    //debugger;
    Shiny.onInputChange(el.id + '_timechanged', {id:id, time:time})
  });
}
"
  )


shinyApp(
  ui = fluidPage(
    timevisOutput("timeline"),
    actionButton("btn", "Add time bar 24 hours ago")
  ),
  server = function(input, output) {
    output$timeline <- renderTimevis(
      tv
    )
    observeEvent(input$timeline_timechanged, {
      str(input$timeline_timechanged)
    })
  }
)

跟进

如果我走错了路,或者这一切都没有任何意义,请告诉我。我感觉到你的痛苦,并且排除这种技术混合可能非常棘手。

答案 1 :(得分:2)

(免责声明:我写了timevis包)

首先:Kenton的答案很棒,OP的尝试也很棒。

这更像是一篇信息性文章。

为什么你尝试的不起作用

onevent("timechanged", ...)无效的原因是因为onevent()函数适用于任何标准的javascript事件,但它不适用于不同插件提供的特定事件。

要绑定自定义事件(例如该事件),您必须编写一些简短的自定义JavaScript代码。所以查看visjs文档并找到timeline.on('select', ...)代码是正确的路径,但是(正如您所怀疑的)您没有正确引用时间轴对象。

由于这个原因,我确保导出实际的底层对象,以便像你这样的人可以以原始格式操作它。要从timevis访问时间轴对象,请使用$(id)[0].widget.timeline。由于您的时间轴的ID为timeline而您想调用on()函数,因此您可以执行类似$("#timeline")[0].widget.timeline.on('select', ...)的操作。

为什么此功能不存在

当我查看visjs的文档时,我决定让窗口小部件在发生更改时自动导出4个事件:数据,所选项目,所有项目的ID以及当前可见的时间窗口。我决定不使用on('timechanged')事件,因为它与其他事件的行为不同:它一次只返回一个项目。

我的意思是什么?例如,input$timeline_data总是在此时返回整个数据; input$timeline_select始终会告诉您此时所有选定项目的内容;每次拖动一个不同的垂直条时,input$timeline_timechanged会被触发,因此只会包含最后拖动的条形图,而不是所有竖条条形图,并且它不会为您提供一种方法来询问时间特定的酒吧。这有意义吗?

当然可以编写一些跟踪所有条形码的代码,但这很快就会非常混乱(例如,它必须确保在条形码时更新添加/移除)。所以我选择不去那个rabbithole。