Reusable Scroll Sync w/o JQuery
by thomastthai
HTML
<!--
Answer from Gregor y in a comment at:
https://stackoverflow.com/questions/9236314/how-do-i-synchronize-the-scroll-position-of-two-divs
-->
<div class="scrollSyncV" id="1">
<table>
<tr><td>Left Line 1</td></tr>
<tr><td>Left Line 2</td></tr>
<tr><td>Left Line 3</td></tr>
<tr><td>Left Line 4</td></tr>
<tr><td>Left Line 5</td></tr>
<tr><td>Left Line 6</td></tr>
<tr><td>Left Line 7</td></tr>
<tr><td>Left Line 8</td></tr>
<tr><td>Left Line 9</td></tr>
<tr><td>Left Line 10</td></tr>
<tr><td>Left Line 11</td></tr>
<tr><td>Left Line 12</td></tr>
<tr><td>Left Line 13</td></tr>
<tr><td>Left Line 14</td></tr>
<tr><td>Left Line 15</td></tr>
<tr><td>Left Line 16</td></tr>
<tr><td>Left Line 17</td></tr>
<tr><td>Left Line 18</td></tr>
<tr><td>Left Line 19</td></tr>
<tr><td>Left Line 20</td></tr>
<tr><td>Left Line 21</td></tr>
<tr><td>Left Line 22</td></tr>
<tr><td>Left Line 23</td></tr>
<tr><td>Left Line 24</td></tr>
<tr><td>Left Line 25</td></tr>
</table>
</div>
<div class="scrollSyncV" id="2">
<table>
<tr><td>Right Line 1</td></tr>
<tr><td>Right Line 2</td></tr>
<tr><td>Right Line 3</td></tr>
<tr><td>Right Line 4</td></tr>
<tr><td>Right Line 5</td></tr>
<tr><td>Right Line 6</td></tr>
<tr><td>Right Line 7</td></tr>
<tr><td>Right Line 8</td></tr>
<tr><td>Right Line 9</td></tr>
<tr><td>Right Line 10</td></tr>
<tr><td>Right Line 11</td></tr>
<tr><td>Right Line 12</td></tr>
<tr><td>Right Line 13</td></tr>
<tr><td>Right Line 14</td></tr>
<tr><td>Right Line 15</td></tr>
<tr><td>Right Line 16</td></tr>
<tr><td>Right Line 17</td></tr>
<tr><td>Right Line 18</td></tr>
<tr><td>Right Line 19</td></tr>
<tr><td>Right Line 20</td></tr>
</table>
</div>
<div...
CSS
/* use whatever method you want to put the tables side-by-side */
:root {
padding: 1rem;
}
.scrollSyncV {
float: left;
width: 50%;
height: 100px;
overflow: auto;
border: 1px solid black;
box-sizing: border-box;
}
.scrollSyncH {
width: 100%;
float: clear;
height: 100px;
overflow: auto;
border: 1px solid black;
box-sizing: border-box;
}
.scrollSyncH table td{
min-width: 80px;
}
table {
width: 100%;
}
tr:nth-child(even) td {
background-color: #eef;
}
.syncContainerLocked{
height: 100px;
width: 300px;
overflow: hidden;
}
.syncContainer{
height: 100px;
width: 300px;
overflow: auto;
}
.syncPaneAbs{
display: block;
overflow: hidden;
height: 1000px;
width: 1000px;
}
#lockedPaneRel{
display: block;
overflow: hidden;
height: 10px;
width: 10px;
}
#topPaneRel{
display: block;
overflow: hidden;
height: 100px;
width: 100px;
}
#leftPaneRel{
display: block;
overflow: hidden;
height: 500px;
width: 500px;
}
#middlePaneRel{
display: block;
overflow: hidden;
height: 100000px;
width: 100000px;
}
JavaScript
function syncOnScroll(selector,SyncFn) {
if(!SyncFn)return;
let active = null;
document.querySelectorAll(selector).forEach((div) => {
div.addEventListener("mouseenter", (e) => {active = e.target});
div.addEventListener("scroll", (e) => {
//ignore inactive-scroll events
if (e.target !== active) return;
//push the active-scroll event to synced elements
document.querySelectorAll(selector).forEach((target) => {
if (active === target) return;
SyncFn(target,active);
});
});
});
}
function scrollSync(selector,scrollType) {
let type = scrollType || 'both';
function calcPosFn(position,fromRange,fromWidth,toRange,toWidth){
if(fromRange == fromWidth) return 0;
return Math.floor(
position * ((toRange-toWidth)/
(fromRange-fromWidth))
);
}
switch(type.toLowerCase()){
case 'vertical':
syncOnScroll(selector,function(t,a){
t.scrollTop=calcPosFn(
a.scrollTop,
a.scrollHeight,
a.clientHeight,
t.scrollHeight,
t.clientHeight)});break;
case 'horizontal':
syncOnScroll(selector,function(t,a){
t.scrollLeft=calcPosFn(
a.scrollLeft,
a.scrollWidth,
a.clientWidth,
t.scrollWidth,
t.clientWidth)});break;
case 'both':default:
syncOnScroll(selector,function(t,a){
t.scrollTop = calcPosFn(
a.scrollTop,
a.scrollHeight,
a.clientHeight,
t.scrollHeight,
t.clientHeight);
t.scrollLeft = calcPosFn(
a.scrollLeft,
a.scrollWidth,
a.clientWidth,
t.scrollWidth,
t.clientWidth);
});break;
}
}
//RWM: Call the function on the elements you need synced.
scrollSync(".scrollSyncV",'vertical');
scrollSync(".scrollSyncH",'horizontal');
scrollSync('.syncV','vertical');
scrollSync('.syncH','horizontal');
scrollSync('.syncB');
//********* Build...