I am using bind/unbind for mousewheel scrolling, based on this SO response:
Jquery, unbinding mousewheel event, then rebinding it after actions are completed?
I'm tunneling up the event tree from delta, to target only the X mousewheel values. All is working well. The problem I'm trying to overcome: I want to simply scroll forward/backward ONE panel, then stop scrolling. Currently, I'm unbinding the mousewheel event immediately after the move, and that effectively stops the scrolling...but unbinding the mousewheel event also jacks the page. What I need is to be able to sniff the very first deltaX value for direction, then make a move and stop listening. Do I need to look to autoscroll for answers? Binding/unbinding feels klugy, but I can't, for the life of me, figure how to kick out after one move, while still then being able to scroll after that move is complete. Here's my mousewheel function:
function mouseHandler(event, delta) {
$('.homeScrollable').bind('mousewheel', mouseHandler);
var deltaX = event.originalEvent.wheelDeltaX;
//console.log(event.originalEvent.wheelDeltaX);
if(deltaX <= 0) {
//move forward 1 screen and stop
scrollapi.move(1);
$('.homeScrollable').unbind('mousewheel', mouseHandler);
} else if(deltaX > 0) {
//move backward 1 screen and stop
scrollapi.move(-1);
$('.homeScrollable').unbind('mousewheel', mouseHandler);
}
event.preventDefault();
// Rebind mousewheel event:
$('.homeScrollable').bind('mousewheel', mouseHandler); };
I've also looked at setting a timer, a la:
jquery mousewheel plugin: how to fire only one function every scroll
which seemed incredibly promising, but no-go. Here's the plugin page for this guy: http://brandonaaron.net/code/mousewheel/docs
Thanks for checking it out.
Since the DOM doesn't offer any way of differentiating between the first scrolling event fired and subsequent ones that happen to be part of the same scrolling motion, we're forced to think about indirect methods of distinguishing between them.
If you rapidly scroll through any particular element, a scrolling event is fired many times in sequence. Using the following code, we can get an idea about exactly how often that happens:
$('#exampleDiv').bind('mousewheel', function () {
console.log(new Date().getTime());
});
When you scroll over that div, you'll get a console output that looks like this:
// Using mouse wheelbar
251327626600149
251327626600215
251327626600265
251327626600282
251327626600332
251327626600365
// Using touchpad
251327626626207
251327626626225
251327626626261
251327626626276
251327626626312
251327626626345
Looking at this output, it seems like the mousescroll
events are generally fired within somewhere between 20 ms and 60 ms of each other. To be safe, we'll take the upper end to be 100 ms. This is very informative, because we can use it to distinguish between scrolling events that are part of the same action and ones that are likely distinct and deliberately initiated by the user.
What you could do from here is to make a globally accessible 'timestamp' variable, updating it every time a mousescroll
event is fired, whether successful or not. Something like this:
var timeStamp = new Date().getTime();
$('#exampleDiv').bind('mousewheel', function (event) {
var timeNow = new Date().getTime();
// Need to prevent the default scrolling behavior
event.preventDefault();
// If the last mousescroll happened less that 100 ms ago, update
// timeStamp and do nothing
if (timeNow - timeStamp < 100) {
timeStamp = timeNow;
return;
} else {
timeStamp = timeNow;
scrollToSomeOtherDiv();
}
});
This effectively ignores all mousescroll
events that are fired after the initial event that preceded them all but starts working again after the user has paused for 100 ms.
This would solve your problem, except if your scrollToSomeOtherDiv()
function involved some kind of time-consuming animation. You could of course make a global boolean isAnimating
, and check to see if it's true every time a mousescroll
event is fired (making sure to turn it false in a callback once the animation is over).
That would work, except that it could provide a jarring experience for the user. Someone who wants to scroll through two panels quickly will likely not pause between scrolls even after seeing the animation begin. The code above will see all their mousescroll
events as part of the same scrolling motion and continue to ignore them!
In that case, you could simply use the animation time as your threshold. You set a timeStamp once the animation is begun and then ignore all mousescroll
events during that period of time. I've written up an example here: http://jsfiddle.net/Sg8JQ/
The relevant code is here:
var lastAnimation = 0;
var animationTime = 1000; // in ms
var quietPeriod = 500; // in ms, time after animation to ignore mousescroll
function scrollThis(event, delta, deltaX, deltaY) {
var timeNow = new Date().getTime();
// change this to deltaX/deltaY depending on which
// scrolling dir you want to capture
deltaOfInterest = deltaY;
if (deltaOfInterest == 0) {
// Uncomment if you want to use deltaX
// event.preventDefault();
return;
}
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < quietPeriod + animationTime) {
event.preventDefault();
return;
}
if (deltaOfInterest < 0) {
if ($('.active').next('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').next('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
} else {
if ($('.active').prev('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').prev('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
}
}
// Note: mousewheel() is defined in the mousewheel plugin by Brandon Aaron
// You could do without it, but you'd need to adjust for firefox and webkit
// separately.
//
// You couldn't use $(document).scroll() because it doesn't allow you to
// preventDefault(), which I use here.
$(document).mousewheel(scrollThis);
I've also included quietPeriod
which is time beyond the animation time during which you want to continue to ignore mousescroll
events. You can set it to 0 if you want the scroll to be 'responsive' as soon as the animation is complete.
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