I am trying to implement synchronized scrolling for two DIV
with the following code.
DEMO
$(document).ready(function() {
$("#div1").scroll(function () {
$("#div2").scrollTop($("#div1").scrollTop());
});
$("#div2").scroll(function () {
$("#div1").scrollTop($("#div2").scrollTop());
});
});
#div1
and #div2
is having the very same content but different sizes, say
#div1 {
height : 800px;
width: 600px;
}
#div1 {
height : 400px;
width: 200px;
}
With this code, I am facing two issues.
1) Scrolling is not well synchronized, since the divs are of different sizes. I know, this is because, I am directly setting the scrollTop
value. I need to find the percentage of scrolled content and calculate corresponding scrollTop
value for the other div
. I am not sure, how to find the actual height and current scroll position.
2) This issue is only found in firefox
. In firefox, scrolling is not smooth as in other browsers. I think this because the above code is creating a infinite loop of scroll events.
I am not sure, why this is only happening with firefox. Is there any way to find the source of scroll event, so that I can resolve this issue.
Any help would be greatly appreciated.
You can use element.scrollTop / (element.scrollHeight - element.offsetHeight)
to get the percentage (it'll be a value between 0
and 1
). So you can multiply the other element's (.scrollHeight - .offsetHeight)
by this value for proportional scrolling.
To avoid triggering the listeners in a loop you could temporarily unbind the listener, set the scrollTop
and rebind again.
var $divs = $('#div1, #div2');
var sync = function(e){
var $other = $divs.not(this).off('scroll'), other = $other.get(0);
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
other.scrollTop = percentage * (other.scrollHeight - other.offsetHeight);
// Firefox workaround. Rebinding without delay isn't enough.
setTimeout( function(){ $other.on('scroll', sync ); },10);
}
$divs.on( 'scroll', sync);
http://jsfiddle.net/b75KZ/5/
Runs like clockwork (see DEMO)
$(document).ready(function(){
var master = "div1"; // this is id div
var slave = "div2"; // this is other id div
var master_tmp;
var slave_tmp;
var timer;
var sync = function ()
{
if($(this).attr('id') == slave)
{
master_tmp = master;
slave_tmp = slave;
master = slave;
slave = master_tmp;
}
$("#" + slave).unbind("scroll");
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
var x = percentage * ($("#" + slave).get(0).scrollHeight - $("#" + slave).get(0).offsetHeight);
$("#" + slave).scrollTop(x);
if(typeof(timer) !== 'undefind')
clearTimeout(timer);
timer = setTimeout(function(){ $("#" + slave).scroll(sync) }, 200)
}
$('#' + master + ', #' + slave).scroll(sync);
});
This is what I'm using. Just call the syncScroll(...)
function with the two elements you want to synchronize. I found pawel's solution had issues with continuing to slowly scroll after the mouse or trackpad was actually done with the operation.
See working example here.
// Sync up our elements.
syncScroll($('.scroll-elem-1'), $('.scroll-elem-2'));
/***
* Synchronize Scroll
* Synchronizes the vertical scrolling of two elements.
* The elements can have different content heights.
*
* @param $el1 {Object}
* Native DOM element or jQuery selector.
* First element to sync.
* @param $el2 {Object}
* Native DOM element or jQuery selector.
* Second element to sync.
*/
function syncScroll(el1, el2) {
var $el1 = $(el1);
var $el2 = $(el2);
// Lets us know when a scroll is organic
// or forced from the synced element.
var forcedScroll = false;
// Catch our elements' scroll events and
// syncronize the related element.
$el1.scroll(function() { performScroll($el1, $el2); });
$el2.scroll(function() { performScroll($el2, $el1); });
// Perform the scroll of the synced element
// based on the scrolled element.
function performScroll($scrolled, $toScroll) {
if (forcedScroll) return (forcedScroll = false);
var percent = ($scrolled.scrollTop() /
($scrolled[0].scrollHeight - $scrolled.outerHeight())) * 100;
setScrollTopFromPercent($toScroll, percent);
}
// Scroll to a position in the given
// element based on a percent.
function setScrollTopFromPercent($el, percent) {
var scrollTopPos = (percent / 100) *
($el[0].scrollHeight - $el.outerHeight());
forcedScroll = true;
$el.scrollTop(scrollTopPos);
}
}
If the divs are of equal sizes then this code below is a simple way to scroll them synchronously:
scroll_all_blocks: function(e) {
var scrollLeft = $(e.target)[0].scrollLeft;
var len = $('.scroll_class').length;
for (var i = 0; i < len; i++)
{
$('.scroll_class')[i].scrollLeft = scrollLeft;
}
}
Here im using horizontal scroll, but you can use scrollTop here instead. This function is call on scroll
event on the div, so the e
will have access to the event object.
Secondly, you can simply have the ratio of corresponding sizes of the divs calculated to apply in this line $('.scroll_class')[i].scrollLeft = scrollLeft;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With