44

I'm creating a scrolling effect using JQuery and I'm wondering if it's possible to distinguish between the user scrolling vs. programmatically scrolling.

I have something like this:

$('#element').on('scroll',function(e){
    $('#element').stop(true); // stop previous scrolling animation
    $('#element').animate({ // start new scrolling animation (maybe different speed, different direction, etc)
        scrollTop:...
    });
});

However, this event is triggered during every step of the animation. How can I tell if this event was triggered by the user or by the animation?

Leo Jiang
  • 24,497
  • 49
  • 154
  • 284
  • You are looking for [event.originalEvent](https://github.com/jquery/api.jquery.com/issues/319), see [event object documentation](https://api.jquery.com/category/events/event-object/) under **Other properties** and this [fiddle](http://jsfiddle.net/xdv5mgua/) for an example. – Eric Martinez Aug 01 '15 at 02:03
  • http://stackoverflow.com/questions/1659204/call-scroll-only-when-user-scrolls-not-when-animate/1659231#1659231 – FuzzyTree Aug 02 '15 at 00:43
  • You could try distinguishing it with the `wheel` event. A user can fire both `wheel` and `scroll` events, whereas jQuery probably only fires the `scroll` event. – Sebastian Simon Aug 06 '15 at 04:02
  • 1
    Instead of trying to determine the source of the scroll event, unsubscribe from the event before animate (after stop) and subscribe to scroll event again after animate. – Adam Moszczyński Aug 07 '15 at 10:10
  • @AdamMoszczyński The user must be able to stop the scroll animation by scrolling. – Leo Jiang Aug 07 '15 at 12:28

3 Answers3

5

Use a variable to determine when you are scrolling programmatically

Example:

var programScrolling = false;

$('#element').on('scroll',function(e){
    if (programScrolling) {
        return;
    }

    $('#element').stop(true); // stop scrolling animation

    programScrolling = true;

    $('#element').animate({
        scrollTop:...
    });

    programScrolling = false;
});

Not sure if that is exactly what you want, but the concept should work.

brettwhiteman
  • 4,210
  • 2
  • 29
  • 38
  • 1
    The user should be able to interrupt the scrolling animation at any time (hence the `$('#element').stop(true)`). This would make it such the user cannot interrupt the animation. – Leo Jiang Jul 17 '15 at 02:34
  • @Linksku Would putting the `$('#element').stop(true)` inside the `if` condition work for your scenario? – brettwhiteman Jul 17 '15 at 02:43
  • 1
    No because then the animation would stop after 1 step. I also just noticed that the conditional's body will never be run because `programScrolling` will always be false. – Leo Jiang Jul 17 '15 at 02:51
  • This may help http://stackoverflow.com/questions/9144560/jquery-scroll-detect-when-user-stops-scrolling – brettwhiteman Jul 17 '15 at 03:05
  • @Brett Don't you need to change `programScrolling` back **after** the animation has finished? – Toothbrush Aug 07 '15 at 20:26
  • Depending on your setup, you could set `programScrolling` to `false` when the user activates the mouse wheel and/or clicks the scroll bar. That could indicate the scroll is a result of these actions. To detect mouse wheel: http://stackoverflow.com/questions/8189840/get-mouse-wheel-events-in-jquery To detect scroll bar: http://stackoverflow.com/questions/10045423/determine-whether-user-clicking-scrollbar-or-content-onclick-for-native-scroll – noderman Aug 07 '15 at 21:17
  • 4
    This answer is incorrect. `$('#element').animate(...)` will start the animation but it will return *before the animation has completed* because an animation is an asynchronous process. It does not block. So `programScrolling = false;` will execute before the animation is over. – Louis Sep 21 '15 at 22:48
  • The question was how to detect user animation when jquery is animating – Eugene Mala Jul 08 '18 at 05:13
4

I would make functions for different kinds of scrollings to detect them and call a scroll handler for all of them, like so:

JS Fiddle

$(window).bind('mousewheel DOMMouseScroll', function(event){
    var direction;
    if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
        direction = 'up';
    }
    else {
        direction = 'down';
    }
    scrollHandler(direction, 'mouseWheel');
    event.preventDefault();
});

var scrollHandler = function(direction, origin) {
    var height = $(document).scrollTop();
    var movement = (direction == 'up') ? -100 : 100;
    console.log(origin);
    $('body').stop(true);
    $('body').animate({
        scrollTop: height + movement
    }, 250);
};

Then you can do different stuff according to the origin of the event!
You could also check if the user scrolls to the same direction that the screen is scrolling and do something different, or whatever you want with the info passed by the mousewheel event.

Original mousewheel event function copied from THIS answer

Community
  • 1
  • 1
Aramil Rey
  • 3,387
  • 1
  • 19
  • 30
  • `mousewheel` has limited support. Also, it doesn't work if the user scrolls using the scrollbar or on mobile. – Leo Jiang Aug 07 '15 at 01:46
  • Thats why I used `mousewheel DOMMouseScroll'`, it applies to IE9+ and all major browsers. You can also make a `$('body').on('touchmove', function(e) {` and pass to the smoothScroll function whatever you like, direction, origin.. You could also leave the native scrolling for mobile. – Aramil Rey Aug 07 '15 at 01:53
  • You could also add `onmousewheel` to the function catching the event to support IE8 and below – Aramil Rey Aug 07 '15 at 01:56
  • There is no mouse on touch screens! – Murhaf Sousli Jul 28 '21 at 23:55
-1

I would suggest possibly using the .originalEvent method. The downside is, this is very browser dependent. See here. Hopefully the following helps:

$('#element').scroll(function(e){
    var humanScroll = e.originalEvent === undefined;
    if(humanScroll) {
        $(this).stop(true);
    }
})
Community
  • 1
  • 1
Turtle
  • 1,369
  • 1
  • 17
  • 32
  • 8
    For anyone else who stumbles across this and is hopeful it might solve their issue, it's unfortunately only supported in Firefox ( https://developer.mozilla.org/en-US/docs/Web/API/Event/originalTarget#Browser_compatibility ) – DBS Aug 03 '18 at 12:27