Disable Predictive Scrolling - Mousewheel (OnScroll) Event fires too often (Touchpad)
Asked Answered
T

2

9

I am executing Javascript onScroll. My code works great with any normal computer mouse, but when I use my notebook's touchpad, I encounter the following situation:

  • my mouse fires (about 1 to 8) mousewheel events while the finger is moving the wheel.
  • my touchpad fires a lot more (~60) mousewheel events while the two fingers are touching the pad and continues to fire after my fingers are up in the air again.

I know this behavior from mobile touch devices. The Feature is called "Predictive Touch" - The Scrolling continues if your finger movement had enough acceleration before lifting it up.

I think the touchpad drivers are setting this "smooth scrolling" behavior.

To debug this case, I have used the following code:

/* Handle Mouse-Wheel Scrolling */
var lastChange = +new Date();
$(window).bind('mousewheel',    function(e){
    console.log("mw");
    if(+new Date() - lastChange > 1000){
        console.log("mw allowed");
        if(e.originalEvent.wheelDelta > 0)  {/*go to previous*/}
        else{   /*go to next*/}
        lastChange = +new Date();
    }
return false;});

This is a simple code that "allows" a mouse-scrolling-event every second.

If I make a fast touchpad-scroll, the mousewheel event is fired ~300 times. The one-second-condition is letting 3 events happen. My fingers were on the touchpad for far less than a second.

With this test, I discovered that the mousewheel events are still fired (almost continuously for 3 seconds), even when my fingers are already off the touchpad.

Is there a Javascript function or a workaround / trick / hack to avoid this behavior?

Something like a onTouchEnd event for touchpads, maybe?

Tedie answered 16/1, 2016 at 19:23 Comment(0)
T
1

To achieve this, you'd have to distinguish between mouse scroll events and touchpad events, which is not (yet) possible using JavaScript. It was already asked in question How to capture touch pad input.

Pointer Events are currently in state of Editor's Draft and not yet supported by any browser. See also touch events docs on MDN.

Tomokotomorrow answered 19/2, 2016 at 21:24 Comment(5)
It wouldn't be enough to just distinguish between touchpad events and wheel events, would it? You'd still need a way to determine if an event was triggered by inertial scrolling, and that will probably require touchpads to start triggering the touchstart and touchend events. Or am I not thinking this through?Archenemy
@Archenemy Yes, you're right. I assume that Pointer Events will provide touchstart and touchend events for touchpads.Ritter
two years later, we now got a level 2 editor's draft, it's a shame it's developing that slowly, but i appreciate that there is a progress at all :) w3.org/TR/pointerevents2Tedie
three years later, we now have a level 3 editor's draft. Guys, we are almost there! w3c.github.io/pointerevents - already with full browser support or polyfill in all major browsers: caniuse.com/#feat=pointer . I might test soon if my issue can be resolved using this API.Tedie
@Tedie Unfortunately and as is this won't help as touchpad events are still emitted as mouse events by the browsers/OS (don't know which one is to blame here)...Biotin
E
1

EDIT: This doesn't appear to work for trackpads. Once they are widely supported, this could be implemented using Touch Events, specifically the Touch End event. By tracking when the finger leaves the trackpad, you can prevent the page scrolling at that particular point.

https://jsfiddle.net/gLkkb5z0/3/

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid1, handler);

        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    }

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid2, handler);

        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };

})();

Demo

Taken from http://james.padolsey.com/javascript/special-scroll-events-for-jquery/

Eastbound answered 14/2, 2016 at 17:15 Comment(8)
Hello, thank you for the answer. Reading the article, i thought this is exactly what i need. But I tried the demo on my Laptop and the "scrolling" status is still active for like 3 to 4 seconds after my fingers are off the touchpad. It does not work for me, do you have another idea?Tedie
Possibly using touch events, specifically the touchend event.Eastbound
Hello, i have tested the touch events API using a touchscreen laptop. The touchscreen is detected and works as intended. The touchpad however has it's default scrolling behaviour and there are no events recorded. I also tried different mousewheel & scrolling events in this demo, but it did not help as well. Do you have another idea?Tedie
@Gothdo reading the docs, touch events should be able to support trackpads in the future: "touch events offer the ability to interpret finger (or stylus) activity on touch screens or trackpads."Tedie
Looks as if touchpads aren't currently supported in most cases, however it looks like you may be able to achieve what you want in the future using those events, with any luck. On the negative side, we have no idea when these events will be supported by browsers for trackpads. It also looks as if this feature is disabled in firefox due to issues with some sites. I'll add this to the answer for anyone searching this in the future.Eastbound
I've also added a jsfiddle that should work when these events are fully supported. My scroll stopping code doesn't feel right however.Eastbound
Thank your for the effort you put into answering this question. The jsfiddle didn't work like this due to some wrong code but i fixed it and played around a bit. It is interesting that if i tell the browser to scroll to top on touchend, it does scroll to top if my (touchscreen-) finger lifts off with no remaining acceleration, but if lift it up "in the move", the event is triggered but the scroll to top never happens, the div actually continues to scroll down. I'm curious how this can be handled in the futureTedie
Great! Thanks for fixing that code. Do you mind if I add it to the answer? I'd rather having a working demo for future readers to see than a semi working one.Eastbound
T
1

To achieve this, you'd have to distinguish between mouse scroll events and touchpad events, which is not (yet) possible using JavaScript. It was already asked in question How to capture touch pad input.

Pointer Events are currently in state of Editor's Draft and not yet supported by any browser. See also touch events docs on MDN.

Tomokotomorrow answered 19/2, 2016 at 21:24 Comment(5)
It wouldn't be enough to just distinguish between touchpad events and wheel events, would it? You'd still need a way to determine if an event was triggered by inertial scrolling, and that will probably require touchpads to start triggering the touchstart and touchend events. Or am I not thinking this through?Archenemy
@Archenemy Yes, you're right. I assume that Pointer Events will provide touchstart and touchend events for touchpads.Ritter
two years later, we now got a level 2 editor's draft, it's a shame it's developing that slowly, but i appreciate that there is a progress at all :) w3.org/TR/pointerevents2Tedie
three years later, we now have a level 3 editor's draft. Guys, we are almost there! w3c.github.io/pointerevents - already with full browser support or polyfill in all major browsers: caniuse.com/#feat=pointer . I might test soon if my issue can be resolved using this API.Tedie
@Tedie Unfortunately and as is this won't help as touchpad events are still emitted as mouse events by the browsers/OS (don't know which one is to blame here)...Biotin

© 2022 - 2024 — McMap. All rights reserved.