0

I'd like to synchronize the vertical scroll of two handsontables through the shiny app (using the rhandsontable library). I'm aware that there might be some HTML and CSS code involved, but I'm not experienced in those two coding languages.

Here is an example of the code:

library(shiny)
library(shinydashboard)
library(rhandsontable)

ui = dashboardPage(skin="red",
                   dashboardHeader(title="App"),
                   dashboardSidebar(),
                   dashboardBody(
                     div(style="white-space:nowrap;overflow-x:auto;overflow-y:hidden",
                         div(style="display:inline-block",
                             rHandsontableOutput("A")
                         ),
                         div(style="display:inline-block;margin-left:35px",
                             rHandsontableOutput("B")
                         )
                     )
                   )
)

server = shinyServer(function(input, output, session){
  
  A = as.data.frame(matrix(rnorm(1600),40,40))
  B = as.data.frame(matrix(rnorm(1600),40,40))
  
  output$A <- renderRHandsontable({
    rhandsontable(A,
                  height = 500,
                  width = 1000,)
  })
  output$B <- renderRHandsontable({
    rhandsontable(B,
                  height = 500,
                  width = 1000,)
  })
  
})


runApp(list(ui=ui, server=server))

There is supposed to be a solution here for the horizontal scroll sync, but when I run the example code it doesn't work. Also, here is a solution for the horizontal scroll but using DataTables and not for handsontables. (I tried changing the code to get vertical scroll sync but without success).

1 Answers1

1

Here is a way but the problem is that there are multiple horizontal scrollbars.

library(shiny)
library(shinydashboard)
library(rhandsontable)

ui = dashboardPage(skin="red",
                   dashboardHeader(title="App"),
                   dashboardSidebar(),
                   dashboardBody(
                     tags$div(
                       style = "max-height:500px; overflow-y: scroll; overflow-x: scroll;",
                       splitLayout(
                         rHandsontableOutput("A"),
                         rHandsontableOutput("B")
                       )
                     )
                   )
)

server = shinyServer(function(input, output, session){
  
  A = as.data.frame(matrix(rnorm(1600),40,40))
  B = as.data.frame(matrix(rnorm(1600),40,40))
  
  output$A <- renderRHandsontable({
    rhandsontable(A,
                  height = 500,
                  width = 1000)
  })
  output$B <- renderRHandsontable({
    rhandsontable(B,
                  height = 500,
                  width = 1000)
  })
  
})


runApp(list(ui=ui, server=server))

Edit: with jQueryScroll

library(shiny)
library(shinydashboard)
library(rhandsontable)

js <- "
var myInterval = setInterval(function() {
  var containers = $('#A .ht_master .wtHolder, #B .ht_master .wtHolder');
  if (containers.length === 2) {
    clearInterval(myInterval);
    containers.scrollsync();
  }
}, 200);
"

css <- "
.ht_master .wtHolder {overflow: scroll !important}
"

ui = dashboardPage(skin="red",
                   dashboardHeader(title="App"),
                   dashboardSidebar(),
                   dashboardBody(
                     tags$head(
                       tags$script(src = "https://cdn.jsdelivr.net/gh/zjffun/jquery-ScrollSync/dist/jquery.scrollsync.js"),
                       tags$script(HTML(js)),
                       tags$style(HTML(css))
                     ),
                     div(#style="white-space:nowrap;overflow-x:auto;overflow-y:hidden",
                         div(style="display:inline-block", class = "ysync",
                             rHandsontableOutput("A")
                         ),
                         div(style="display:inline-block;margin-left:35px", class = "ysync",
                             rHandsontableOutput("B")
                         )
                     )
                   )
)

server = shinyServer(function(input, output, session){
  
  A = as.data.frame(matrix(rnorm(1600),40,40))
  B = as.data.frame(matrix(rnorm(1600),40,40))
  
  output$A <- renderRHandsontable({
    rhandsontable(A,
                  height = 500,
                  width = 1000,)
  })
  output$B <- renderRHandsontable({
    rhandsontable(B,
                  height = 500,
                  width = 1000,)
  })
  
})

runApp(list(ui=ui, server=server))
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • Thank you for your answer. The problem with this solution is that for the vertical scroll to appear, the tables have to fit the whole screen. Also, I'd like the functionality to scroll one table so the other one synchronizes with the scroll. You posted a solution for horizontal sync scroll in https://stackoverflow.com/questions/62850537/synchronize-horizontal-scrollbars-for-datatables-in-r-shiny-application using javascript, css and an api. I wonder if there could be a solution for handsontable instead of DataTable. – Jordi Legorreta Jun 06 '23 at 17:00
  • For me the tables do not need to it the whole screen. Did you try in a true browser? (not in the RStudio browser). – Stéphane Laurent Jun 06 '23 at 18:06
  • Yes, I opened it through the web browser. Actually, if I zoom in or out the web page, the layout of the tables change. If I zoom too much the tables overlap and if I zoom out the tables start spreading away. I'm using firefox btw. – Jordi Legorreta Jun 06 '23 at 18:19
  • @JordiLegorreta Yes it works with jQueyScroll!! See my edit. – Stéphane Laurent Jun 06 '23 at 18:58
  • Yes, now the vertical scroll works perfectly! Although the horizontal scroll is also synchronized. Is there a way to disable it? Maybe the jQueyScroll script has to be edited? – Jordi Legorreta Jun 06 '23 at 19:35
  • @JordiLegorreta `containers.scrollsync({x_sync:false, y_sync:true);`. But not sure it works. – Stéphane Laurent Jun 06 '23 at 19:37
  • It worked!! For some strange reason, I had to switch the true-false order, like this: `containers.scrollsync({x_sync:true ,y_sync:false});`, but now only the vertical scrollbars are synchronized. Thank you so much for your help! I'm new to posting questions in Stack Overflow. How do I proceed to say that your post answered my problem in question? – Jordi Legorreta Jun 06 '23 at 19:50
  • @JordiLegorreta Cool! You have to click the checkmark to accept the answer and the arrow to upvote. – Stéphane Laurent Jun 06 '23 at 20:12