7

I've searched on Stackoverflow but can't seem to find a satisfactory answer to this question. Basically I'd like to know if the scroll was done via mousewheel or the browser scrollbar.

Howard
  • 3,648
  • 13
  • 58
  • 86
  • possible duplicate of [Detect whether scroll event was created by user](http://stackoverflow.com/questions/7035896/detect-whether-scroll-event-was-created-by-user) – Joe Swindell Dec 16 '14 at 19:46
  • 1
    @Joe, I don't think this duplicate is appropriate. Questioner wants to detect when scrolling is initiated from the browser's scrollbars or from the mouse wheel, not from user action or code / browser behavior. – Frédéric Hamidi Dec 16 '14 at 19:48
  • 3
    `scroll` is an even that is triggered when the the scroll offset of an element with an `overflow` is changed. `wheel`, `mousewheel` and `DOMMouseScroll` are not related to an element with `overflow` but will tell you if the scroll wheel was used. – t.niese Dec 16 '14 at 19:50
  • @JoeSwindell: I've already looked at that question. I'm not trying to detect if it was the user or not. I just want to know if it's done via mousewheel or scrollbar. – Howard Dec 16 '14 at 19:53
  • 2
    Might be a duplicate to [How can I differentiate a manual scroll (via mousewheel/scrollbar) from a Javascript/jQuery scroll?](http://stackoverflow.com/questions/2834667/how-can-i-differentiate-a-manual-scroll-via-mousewheel-scrollbar-from-a-javasc?rq=1) take care thet you should not use `.bind` anymore but `.on` – t.niese Dec 16 '14 at 19:54
  • @t.niese: Can you provide an example? I've tried by reading the event.type but it seems to default to 'scroll' sometimes. Though it will show as 'mousewheel' sometimes too. – Howard Dec 16 '14 at 19:55
  • @t.niese: I looked at that too. That question is about a scroll done by the user vs being done programmatically. So it doesn't answer my question. – Howard Dec 16 '14 at 19:56
  • @t.niese: I was thinking that was what's going on. but was wondering if there was another way to distinguish the event. – Howard Dec 16 '14 at 19:57
  • @rotaercz, I just thought of something and made a quick test -- on my current platform (GTK+ Firefox on Linux), rolling the mouse wheel on the scrollbars does scroll the document, so there will be cases when both your criteria are true. Can you elaborate on why you want to differentiate between them? – Frédéric Hamidi Dec 16 '14 at 20:09
  • @FrédéricHamidi: I have a custom header that grows and shrinks. I'd like it to act subtly differently based on if scrolling was done via mousewheel or scrollbar. – Howard Dec 16 '14 at 20:20
  • May I ask why you want to know what caused scrolling? – try-catch-finally Dec 16 '14 at 21:45
  • @try-catch-finally: I just answered that. Look right above your question. – Howard Dec 16 '14 at 22:05
  • Is your motivation more based on look and feel (sophistication) or on technical issues (the header does not shink/expand as expected)? – try-catch-finally Dec 16 '14 at 22:10
  • @try-catch-finally: Everything works perfectly. I just want to add some subtle niceness. – Howard Dec 16 '14 at 22:21

4 Answers4

7

Something like this might work for you but it is not the best solution.

If the a wheel event occurs right before the scroll event, then the scroll is done with the wheel otherwise it is done with using something else then the wheel. There is a slight time difference between both events that are triggered thats why I use a threshold currTime - lastWheelTime > 30.

$('.test').on('scroll wheel DOMMouseScroll mousewheel', function(e) {
    var lastWheelTime,
        currTime = (new Date()).getTime(); 

    if( e.type === 'scroll' ) {
        lastWheelTime = $(this).data().lastWheelTime || 0;

        if( currTime - lastWheelTime > 30 ) {
           $('.info').text('no wheel');
        } else {
           $('.info').text('with wheel');
        }

    } else {
        $(this).data().lastWheelTime = (new Date()).getTime(); 
    }
});
.test {
    width: 200px;
    height: 300px;
    border: 1px solid red;
    overflow: auto;
}
 
.inner {
    height: 600px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="info"></div>
<div class="test">
    <div class="inner"></div>
</div>
t.niese
  • 39,256
  • 9
  • 74
  • 101
  • This definitely would work but it's not perfect. Let's see if anyone else has a more optimal solution. – Howard Dec 16 '14 at 20:22
  • @rotaercz I slightly updated the code so that no globals are used. Is it the `currTime - lastWheelTime > 30` you don't like? – t.niese Dec 16 '14 at 20:39
  • It definitely works but yeah, it's relying on the order and timing of events so it's not elegant. It could break in the future if javascript events fire faster or the order of events changes. – Howard Dec 16 '14 at 20:44
  • @rotaercz I'm pretty sure that the `wheel` event will always occur before the `scroll`. As the `wheel` event is the low-level device event while the `scroll` is the event that has its origin this `wheel` event. – t.niese Dec 16 '14 at 20:47
  • I agree with you there. It's unlikely but I want it to be clean as possible. – Howard Dec 16 '14 at 20:49
  • @hjuster I can't confirm that is does not work. Tested it right now on my MacBookPro with current Chrome, Safari and Firefox and it displays `wheel` if trackpad or mouse is used, and `no wheel` the scrollbar is used. Could you please be more accurate what you tested and what happened? – t.niese May 11 '16 at 12:41
1

Here is my trick to detect scrolling by wheel or not
(Thanks @t.niese for the code snippet, I have made some modification for my demo)

var withWheel = true;
$('.test').on('scroll', function() {
  $(".info").text("with wheel: " + withWheel);
})


$('.inner').on('mouseover', function() {
  withWheel = true;

}).on('mouseleave', function(e) {
  e.stopPropagation();
  withWheel = false;

});
.test {
  width: 200px;
  height: 300px;
  border: 1px solid red;
  overflow: auto;
}
.info {
  position: fixed;
}
.inner {
  height: 600px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="info"></div>
<div class="test">
  <div class="inner"></div>
</div>
Vu Duong
  • 23
  • 3
0

I'd say both the wheel scroll and scrollbar scroll are the same. See the jquery page Here.

The scroll event is sent to an element when the user scrolls to a different place in the element. It applies to window objects

Reading this, it looks like the same event is going to be fired for both.

Jeremy W
  • 1,889
  • 6
  • 29
  • 37
  • I'd like to know if it was done via mousewheel or scrollbar. The scroll event itself isn't important to me. – Howard Dec 16 '14 at 20:04
  • 1
    I'm saying it looks like you can't. – Jeremy W Dec 16 '14 at 20:05
  • I'm pretty sure there is a way to distinguish them. Let's see what others have to say. – Howard Dec 16 '14 at 20:06
  • For modern browsers, `wheel` and `scroll` listeners are distinguishable as `wheel` returns a `WheelEvent`, `scroll` just returns an `Event`. If you listen for both `wheel` and `scroll`, however, using the mousewheel will trigger both listeners whereas using the scrollbar alone just triggers the `scroll` listener. It's best to examine the returned event instance to be sure. – Phil Tune Oct 07 '20 at 15:56
0

Another way that might be possible (i haven't tried it yet) is checking whether a mouse button was pressed during the scroll event (one has to click the scrollbar, right?).