Limit 'mousewheel' delta to fire once per scroll
Asked Answered
S

3

6

I'm using the following code below, to scroll two divs in different directions () but I'm curious to know if you can limit the scroll so it only fires once per scroll (rather than it continually scrolling and sending my functions into an endless loop.

$('.page-left, .page-right').bind('mousewheel', function(event, delta) {
    var windowHeight = $(window).height();
    if (delta < 0) {
        prevProject();
    }
    if (delta > 0) {
        nextProject();
    }
});

You can see where I'm up up to here: http://dev.rdck.co/lyonandlyon/

Thanks in advance, R

Animation functions for reference:

var prevProject = function() { // up arrow/scroll up
    var windowHeight = $(window).height();

    $('.page-left .page-left-wrapper').css({bottom:'auto'});
    $('.page-left .page-left-wrapper').animate({top:0},800, function() {
        $('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
        $('.page-left .page-left-wrapper').css({top:-windowHeight});
    });
    $('.page-right .page-right-wrapper').css({top:'auto'});
    $('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
        $('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
        $('.page-right .page-right-wrapper').css({bottom:+windowHeight});
    });
};


var nextProject = function() { // down arrow/scroll down
    var windowHeight = $(window).height();

    $('.page-left .page-left-wrapper').animate({top:0},800, function() {
        $('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
        $('.page-left .page-left-wrapper').css({top:-windowHeight});
    });
    $('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
        $('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
        $('.page-right .page-right-wrapper').css({bottom:+windowHeight});
    });
};
Spessartite answered 18/1, 2014 at 21:13 Comment(4)
Look into debounce/throttle.Gerfalcon
bind is outdated. Use on.Quintal
@JanDvorak Okay if I change bind to on, fair enough, but how does this help?Spessartite
if you ever want to add event delegation, it's somewhat easier with on as bind and delegate don't quite agree on the argument order.Quintal
S
7

You can just check for animation within the mousewheel function (demo)

$('.page-left, .page-right').on('mousewheel', function(event, delta) {
    if ($('.page-left-wrapper, .page-right-wrapper').is(':animated') ) {
        return false;
    }
    var windowHeight = $(window).height();
    if (delta < 0) {
        prevProject();
    }
    if (delta > 0) {
        nextProject();
    }
});

Update: we resolved to use debounce as the long scroll (sliding a finger down a touchpad) needed to be stopped (updated demo).

$(document).keydown( $.debounce( 250, function(e) {
    switch (e.which) {
    case 38: // up arrow
        prevProject();
        break;
    case 40: // down arrow
        nextProject();
        break;
    }
}) );

$('.page-left, .page-right').on('mousewheel', $.debounce( 250, function(event, delta) {
    var windowHeight = $(window).height();
    if (delta < 0) {
        prevProject();
    }
    if (delta > 0) {
        nextProject();
    }
}) );
Sorcim answered 18/1, 2014 at 21:38 Comment(7)
This is great! It's still quite sensitive.. any way you can make it per scroll? Such as a long scroll?Spessartite
Try using @friedi's answer, but instead of clearing the isAnimating flag right away, clear it within a setTimeout function.Sorcim
can you elaborate? setTimeout(function() { var isAnimating = false; }, 5000);Spessartite
Yes, like that, but I wouldn't set it to 5 seconds, maybe 1 or 2.Sorcim
See live site. Doesn't prohibit a long scroll.Spessartite
Live site now has a js error: Uncaught ReferenceError: isAnimating is not definedSorcim
let us continue this discussion in chatSpessartite
L
3

You can get around this problem with a flag. You can use a global flag isAnimating and set it to true, if you are currently animating the position of the divs of your website.

So the code can look something like this:

var isAnimating = false;

$('.page-left, .page-right').bind('mousewheel', function(event, delta) {
    // if the div will be animated at this moment return
    if(isAnimating) {
        return;
    }

    var windowHeight = $(window).height();
    if (delta < 0) {
        prevProject();
    }
    if (delta > 0) {
        nextProject();
    }
});

var prevProject = function() {
    isAnimating = true;

    var oneIsDone = false,
        finish = function() {
            // if both animations are done, set the flag to false
            if(oneIsDone) {
                isAnimating = false;
            }
            // at least one is done...
            oneIsDone = true;
        };

    // animate the previous project and set the flag to false (in the callback)
    $('.page-left .page-left-wrapper').css({bottom:'auto'});
    $('.page-left .page-left-wrapper').animate({top:0},800, function() {
        $('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
        $('.page-left .page-left-wrapper').css({top:-windowHeight});
        finish();
    });
    $('.page-right .page-right-wrapper').css({top:'auto'});
    $('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
        $('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
        $('.page-right .page-right-wrapper').css({bottom:+windowHeight});
        finish(); 
    });
};

var nextProject = function() {
    // the same as in the prevProject function, but only in the other direction
};
Lent answered 18/1, 2014 at 21:33 Comment(2)
Thanks so much for the help. Have updated my question with the animation functions.Spessartite
@Lent Thank you so much. One a long scroll it fires twice (and thus scrolling through two projects) any way of limiting it?Spessartite
H
0

I suggest to detect extremums to fire the function:

var mw1 = 0;
var mw2 = 0;
var lock;
$(document).bind('mousewheel', function(evt) {
    var delta = evt.originalEvent.deltaY
    if(((delta > 0 && delta < mw2 && mw2 > mw1) || (delta < 0 && delta > mw2 && mw2 < mw1)) && !lock){
        console.log(mw1 + " " + mw2 + " " + delta)
        // call some function here
        lock = true;
        window.setTimeout(function(){
            lock = false;
        },200)
    }
    mw1 = mw2;
    mw2 = delta;
})

lock is actually should not be necessary but extremums sometimes are found more than once per scroll for some reason.

Hamrah answered 14/3, 2016 at 22:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.