javascriptpanelsynchronouscustom-scrolling

Using scrollEnd event to stop bouncing with scrollIntoView when making panels scroll synchronously


I am making a rather complex website that has as a key factor texts in different panels that I want to make scroll together (synchronously). That is: when the user scrolls down a few lines in one panel, the other panel presenting a parallel text should scroll the same few lines. Further, at the top of each panel I have an information line, saying just what text the panel contains. I want this to stay in view and not scroll out of sight, while the text below in the panel scrolls.

I can do one thing, but not the other. I have made a jSFiddle that shows my attempts to make this work at JS Fiddle. Here is a key bit of the code:

let thisLine=$(scrollMe[0]).find("p[n='"+nVal+"']")[0]
thisLine.scrollIntoView();

The whole file is available at www.inklesseditions.com/TCR/testsyncscroll.html. Thus:

  1. if you scroll in all four panels: you will see that the panels at the bottom scroll correctly. That is: the text "Stays at top when text scrolls" stays there while the text below scrolls. The panels at the top do not scroll correctly: the text "Scrolls with text" scrolls out of sight as the text below scrolls.
  2. Click the "Synchronize Scrolling" textbook so now it is checked. Scroll the text in either one of the top two panels. It works well: the text in both panels moves together when you scroll either one. BUT the text in the bottom two panels does NOT scroll correctly. Rather, it scrolls always to the very bottom of the text in each panel, even if you want to scroll just one line in either direction. Further, the line "Stays at top when text scrolls" scrolls out of sight.

Help! I've been stuck for ages on this. It appears that in the bottom panel scrolling in one window causes some kind of race condition, which does not end until both panels have scrolled to the very bottom.

I'm aware that scrolling is really tricky, with different combinations of "overflow auto/scroll/hidden" etc and different height settings causing unpredictable behaviour. I am sure that some combination exists that will do what I want. I just don't know what it is.

I've included in my code elements outside this particular problem. I did that because I use flexbox throughout and it's possible that there is some interaction with flexbox which is causing this misbehaviour.


Solution

  • I figured out the exact problem and how to fix it. The problem was that the synchronous scroll function sent an update message to a panel which triggered a scroll event in that target panel,which called the sychronous scroll function, which then went then sent another update, and on for ever. The solution was:

    1. Disable the call to the synchronous scroll function on the target panel before sending it the update
    2. Attach the (relatively) new "scrollend" event to the target panel, so that when it had finished responding to the update, the synchronous scroll function would be re-enabled AFTER the panel had finished scrolling

    The core code is this:

     function scrollPanel(targetPanel, scrollMe){
        targetPanel.off("scroll"); //turn off call to sync function
        targetPanel.addEventListener("scrollend", (event) => {
            targetPanel.on("scroll", cfScroll); //turn it back on after scroll      
        }); 
        targetPanel[scrollMe].scrollIntoView(); 
    }
    

    This is in a JSFiddle at https://jsfiddle.net/peterrr73/83beksng/5/.

    A slight wrinkle: I added a few lines to catch cases where the scroll had already been done. Not sure if this is a problem with scrollend. Anyway, works well. Scroll any one of the five panels and the others all move in harmony.