Search code examples
javascriptjquerymousewheelnicescroll

Avoid jittery scrolling on horizontal touchpads when using Nicescroll and mousewheel.js


So I'm using mousewheel.js to handle mousewheel scrolling in any part of the document so I can scroll a custom scroller made by Nicescroll.

You can check a fiddle of it working here

Here's part of the code that handles the scrolling:

function activate_mousewheel()
{
    $(document).bind('mousewheel', function(event, delta, deltaX, deltaY) 
    {
        if(delta < 0)
        {
            console.log(1);
            $('#postscroller').scrollTop($('#postscroller').scrollTop() + 60);
        }
        else
        {
            console.log(2);
            $('#postscroller').scrollTop($('#postscroller').scrollTop() - 60);
        }
    });
}

Now my problem is that when this is used in a computer with a touchpad with horizontal scrolling enabled the movement is all jittery rendering it unusable. So this problem will affect people using any kind of laptop with horizontal scrolling like a chromebook or a macbook.

I've tried doing various fixes, playing with the deltas but to no avail.

I was hoping someone here could find a solution.

Thanks.


Solution

  • I had to find a solution for the problem myself, and after hours of trying and beeing creative here is what i came up with. Of course you have to modify it to integrate it to work smoothly with nicescroll etc. as this is plain JS:

    Well I needed to get a solution. So I found a acceptable solution for this problem:

    var scrolling = false;
    var oldTime = 0;
    var newTime = 0;
    var isTouchPad;
    var eventCount = 0;
    var eventCountStart;
    
    var mouseHandle = function (evt) {
        var isTouchPadDefined = isTouchPad || typeof isTouchPad !== "undefined";
        console.log(isTouchPadDefined);
        if (!isTouchPadDefined) {
            if (eventCount === 0) {
                eventCountStart = new Date().getTime();
            }
    
            eventCount++;
    
            if (new Date().getTime() - eventCountStart > 50) {
                    if (eventCount > 5) {
                        isTouchPad = true;
                    } else {
                        isTouchPad = false;
                    }
                isTouchPadDefined = true;
            }
        }
    
        if (isTouchPadDefined) {
            // here you can do what you want
            // i just wanted the direction, for swiping, so i have to prevent
            // the multiple event calls to trigger multiple unwanted actions (trackpad)
            if (!evt) evt = event;
            var direction = (evt.detail<0 || evt.wheelDelta>0) ? 1 : -1;
    
            if (isTouchPad) {
                newTime = new Date().getTime();
    
                if (!scrolling && newTime-oldTime > 550 ) {
                    scrolling = true;
                    if (direction < 0) {
                        // swipe down
                    } else {
                        // swipe up
                    }
                    setTimeout(function() {oldTime = new Date().getTime();scrolling = false}, 500);
                }
            } else {
                if (direction < 0) {
                    // swipe down
                } else {
                    // swipe up
                }
            }
        }
    }
    

    And registering the events:

    document.addEventListener("mousewheel", mouseHandle, false);
    document.addEventListener("DOMMouseScroll", mouseHandle, false);
    

    Here is how it works:

    When the user first scrolls, it will detect and check that in 50ms not more than 5 events got triggered, which is pretty unusual for a normal mouse, but not for a trackpad.

    Then there is the else part, which is not for importance for the detection, but rather a trick to call a function once like when a user swipes. Please come at me if I wasn't clear enough, it was very tricky to get this working, and is of course a less than ideal workaround.

    Edit: I optimized the code now as much as I can. It detects the mouseroll on the second time and swipe on trackpad instantly. Removed also a lot of repeating and unnecessary code.