【问题标题】:Make div appear on click in R plotly让 div 在点击 R 时出现
【发布时间】:2021-01-10 08:56:29
【问题描述】:

我对将 Javascript 与 R 相结合的世界很陌生,而且我的 Javascript 知识非常有限。我正在尝试制作一个plotly 国际象棋开局图,当您单击开局时,它会显示一个带有开局初始移动的棋盘。

library(plotly)
library(htmlwidgets)
library(data.table)
library(rchess)

data("chessopenings")
setDT(chessopenings)
mychess = chessopenings[1:10]
mychess[, Pop := sample(c(1,2,4), nrow(mychess), replace = T)]
mychess[, fens := sapply(pgn, function(x) {chsspgn <- Chess$new(); chsspgn$load_pgn(x); chsspgn$fen()})]

上面的代码只是创建了一个包含 10 个开口的示例数据集。然后,我根据我在https://plotly-r.com/supplying-custom-data.html#fig:hover-annotate 找到的指导,使用 plotly 绘制它们,我尝试创建一个新函数,当您单击点时显示棋盘。 棋盘函数是此处指定的函数https://chessboardjs.com/examples#1002,如果我理解正确(如果我错了,请纠正我)它会返回一个“div”元素,这是我必须显示的元素。

q = plot_ly(mychess, x = ~eco, y = ~Pop) %>% 
  add_markers(text = ~name,
              customdata = ~fens)  
    
onRender(
  q, "
     function(el) {
      el.on('plotly_click', function(d) {
      var pt = d.points[0]; 
      var fen =  d.points[0].customdata
      var newboard = Chessboard('myBoard', fen);
      newboard.style.visibility = 'visible';
      newboard.style.display = 'block';
      })}")

不幸的是,没有任何显示。我使用了这里提供的信息Show/hide 'div' using JavaScript,但似乎我遗漏了一些东西。

更新:我尝试了@Bas 的建议,使用以下代码转换图像:

png(pic1 <- tempfile(fileext = ".png"));chessboardjs(fen = mychess$fens[1]); dev.off() 
text = knitr::image_uri(pic1) 
text = sub(".*?,", "", text) 
html <- sprintf('<html><body><img src="data:image/png;base64,%s"></body></html>', text) 
cat(html, file = tf2 <- tempfile(fileext = ".html")) 
browseURL(tf2)

但这也不起作用。

【问题讨论】:

    标签: javascript r plotly r-plotly


    【解决方案1】:

    您必须包含 Chessboard JavaScript 和 CSS 文件才能使用 Chessboard 函数。该函数不会创建div,而是将棋盘可视化附加到给定的 CSS 选择器。所以div必须事先创建。


    闪亮版:

    library(plotly)
    library(htmlwidgets)
    library(data.table)
    library(rchess)
    library(shiny)
    
    data("chessopenings")
    setDT(chessopenings)
    mychess = chessopenings[1:10]
    mychess[, Pop := sample(c(1,2,4), nrow(mychess), replace = T)]
    mychess[, fens := sapply(pgn, function(x) {chsspgn <- Chess$new();
    chsspgn$load_pgn(x); chsspgn$fen()})]
    
    ui <- fluidPage(
      tags$head(tags$link(href = "https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.css", rel = "stylesheet", type = "text/css")),
      tags$head(tags$script(src = "https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.js")),
      plotlyOutput("plt"),
      div(id = "myBoard", style="width: 400px")
    )
    
    server <- function(input, output, session) {
      output$plt <- renderPlotly({
        q = plot_ly(mychess, x = ~eco, y = ~Pop) %>% 
          add_markers(text = ~name,
                      customdata = ~fens)  
        onRender(
          q, "
         function(el) {
          el.on('plotly_click', function(d) {
          var pt = d.points[0];
          var fen =  d.points[0].customdata;
          var newboard = Chessboard('myBoard', fen);
          })}")
      })
    }
    
    shinyApp(ui, server)
    

    要查看 chess pieces 的图像,您可以将它们包含在 Shiny 应用程序的 www/img/chesspieces/wikipedia/ 文件夹中。否则你会在浏览器控制台看到一些错误。

    GET http://127.0.0.1:5247/img/chesspieces/wikipedia/wK.png HTTP/1.1 404 未找到 11 毫秒


    Markdown 版本:

    要查看国际象棋位置,您必须下载 png files 并根据 .Rmd 文档的位置将它们放入此文件夹结构 /img/chesspieces/wikipedia/

    ---
      title: "Chess Openings"
      output: html_document
    ---
    
    <style type="text/css">
    @import url("https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.css");
    </style>
    
      <script src="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.js"></script>
    
    ```{r setup, include=FALSE}
    library(plotly)
    library(htmlwidgets)
    library(data.table)
    library(rchess)
    library(shiny)
    data("chessopenings")
    setDT(chessopenings)
    mychess = chessopenings[1:10]
    mychess[, Pop := sample(c(1,2,4), nrow(mychess), replace = T)]
    mychess[, fens := sapply(pgn, function(x) {chsspgn <- Chess$new();
    chsspgn$load_pgn(x); chsspgn$fen()})]
    ```
    
    ```{r out.width='100%', echo=FALSE, warning = FALSE}
    q = plot_ly(mychess, x = ~eco, y = ~Pop) %>%
      add_markers(text = ~name,
                  customdata = ~fens)
    onRender(
      q, "
     function(el) {
      el.on('plotly_click', function(d) {
      var pt = d.points[0];
      var fen =  d.points[0].customdata;
      var newboard = Chessboard('myBoard', fen);
      })}")
    ```
    
      <div id="myBoard" style="width: 400px"></div>
    

    【讨论】:

    • 谢谢!我有一个非常基本的问题:不使用shiny 是否可以拥有这个?这可以通过使用htmlwidgets 来实现吗?我尽量避免需要服务器...
    • 你想要的是 Markdown 还是交互式 R 脚本?
    • 作为 html Markdown。 (或其他 Markdown 如果更合适,但我认为 html 是要走的路)
    • 我用降价版本更新了我的答案。那会为你解决吗?
    • 这太棒了!是的,这是完美的!我是否可以要求您澄清一下您是如何知道存储文件所需的位置以及整个过程的?只是为了我的好奇心,如果它不是很麻烦的话。非常非常感谢!
    【解决方案2】:

    如果您像下面这样应用Plotly.relayout(...) 函数,它就会起作用。请注意,由于我没有 Chessboard(...) 函数,因此我用一些自定义数据替换了图像。

    htmlwidgets::onRender(
      q, "
      function(el) {
          el.on('plotly_click', function(d) {
          var pt = d.points[0]; 
          var fen =  d.points[0].customdata
          var img = {
                // location of image
                source: \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\",
                // top-left corner
                x: 0,
                y: 1,
                sizex: 0.2,
                sizey: 0.2,
                xref: 'paper',
                yref: 'paper'
              };
          Plotly.relayout(el.id, {
                   images: [img] 
          });
          })}
          ")
    

    【讨论】:

    • 谢谢!如果我的理解是正确的,如果你有 rchess 包那么你也应该有 Chessboard() 函数。但是我又不是很确定,也不知道如何检查(任何提示都会很有帮助)。使图像出现不是我要处理的问题。
    • 我明白了——我以为那是你的问题。我刚刚安装了rchess 包,但JavaScript 仍然缺少Chessboard() 函数。如果您在浏览器中打开您的绘图输出并右键单击,您可以看到这一点,转到“检查元素”并选择“控制台”。在那里你可以看到 JavaScript 错误。通过在您的 JavaScript 代码中添加 console.log() 语句,您可以对其进行调试。
    • 这很有帮助,谢谢。嗯,有没有可能在 javascript 部分使用 R 函数?我认为我需要的功能是这里的:https://github.com/jbkunst/rchess/blob/master/R/chessboardjs.R 但我认为这是以某种方式使用Chessboard() 功能...如果您认为我应该提出一个新问题,请告诉我。
    • 不,据我所知这是不可能的。您可以使用stackoverflow.com/questions/33409363/convert-r-image-to-base-64 为每个点以base64 格式存储图像,将其存储为数据框中的img,然后使用我上面给出的代码显示图像,source = d.points[0].img
    • 再次感谢您!我试过png(pic1 &lt;- tempfile(fileext = ".png")) ; chessboardjs(fen = mychess$fens[1]); dev.off()text = knitr::image_uri(pic1)text = sub(".*?,", "", text)html &lt;- sprintf('&lt;html&gt;&lt;body&gt;&lt;img src="data:image/png;base64,%s"&gt;&lt;/body&gt;&lt;/html&gt;', text)cat(html, file = tf2 &lt;- tempfile(fileext = ".html"))browseURL(tf2)但不幸的是没有显示... :(
    猜你喜欢
    • 2021-04-13
    • 1970-01-01
    • 2021-01-25
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    相关资源
    最近更新 更多