11

I have created a site where users are able to scroll through a gallery using mouse scroll or arrow up/down. It is working like I want it to, and changing one image pr scroll when scrolling with a mouse. But if the user is scrolling with a trackpad it is almost impossible to scroll a single image at a time.

So my question is: Is there a way to check if the user is scrolling by trackpad, and then changing the behavior of the scrolling, so it becomes less sensitive, and thereby easier to scroll a single image at a time?

I am not very good at jquery, my solution so far has been put together from a couple of scripts:

http://jsfiddle.net/MukuMedia/PFjzX/33/

Hope someone can help me :)

Cody
  • 317
  • 1
  • 5
  • 14

6 Answers6

5

No, this is not possible. The only solution I can think of is set a limit on the scrolling speed. I'm not going to try and decipher your code but I'd recommend making a timedOut variable initialized to zero which is set to one every time you scroll to a new image. Use a setTimeout() to set it back to zero after, say, 50ms. Before you scroll to a new image, check this timedOut variable and only scroll if it's zero. (Make sure you place your setTimeout inside of the timedOut check, otherwise it will be constantly called every time the mousewheel moves, which is not what you want.)

HellaMad
  • 5,294
  • 6
  • 31
  • 53
  • Thanks, I will give it a try - my only concern is if it will still feel as smooth when scrolling with a mousewheel og using the up and down keys. – Cody Sep 18 '12 at 23:47
  • This is not anymore true. I found out a solution to detect it 99% of the time. See my answer: http://stackoverflow.com/a/31195419/2244209 – David Fariña Jul 02 '15 at 22:06
5

I found out that the magic number here was 40.

It seems that with the trackpad (probably with the magic mouse too) the delta get increased 40 times.

And it stays that way even if you take back your normal mouse and scroll with it later.

So what I did, using the jquery mousewheel plugin :

b.mousewheel(function(evt,delta,deltaX,deltaY){
    if(Math.abs(deltaY)>=40)
        deltaY/=40;
    if(Math.abs(deltaX)>=40)
        deltaX/=40;

    //Do your stuff here.
});
Yoann
  • 3,020
  • 1
  • 24
  • 34
1

This is pretty much what DC_ suggested. Figured I'd post this since it's an actual implementation.

// similar to _.debounce, but was having issues with it, so I made this.
function rateLimit(func, time){
        var callback = func,
                waiting = false,
                context = this;
        var rtn = function(){
            if(waiting) return;
            waiting = true;
            var args = arguments;
            setTimeout(function(){
                waiting = false;
                callback.apply(context, args);
            }, time);
        };
        return rtn;
    }

    function onWheel(e){
      // Add your code here
    }

    // will only fire a maximum of 10 times a second
    var debouncedOnWheel = rateLimit(onWheel, 100);
    window.addEventListener("wheel", debouncedOnWheel);
Danish Adeel
  • 728
  • 4
  • 11
  • 27
posit labs
  • 8,951
  • 4
  • 36
  • 66
0

I ran into a similar problem with a "section-change" plugin that I created. I ended resolving it with an "animation" variable: the wheel action only works if this variable is set to 'false' and once this is triggered the variable switches to 'true', then I would switch the variable back to 'false' once the animation is completed. Hope this helps!

armanox
  • 9
  • 1
0

I found a solution which detects if the user is using a touchpad. It works great and has only two tiny drawbacks.

Firstly it detects the mousescroll after the first fired event, so theres one click with the mousewheel which does nothing. But this is only the first time. Then we can cache the value which leads to the second tiny problem. When the user has a trackpad and a mouse with wheel it detects whatever gets used first. To me those problems are negligible. Here the code

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) { // in this if-block 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
            }
        }
    }
}

document.addEventListener("mousewheel", mouseHandle, false);
document.addEventListener("DOMMouseScroll", mouseHandle, false);
David Fariña
  • 1,536
  • 1
  • 18
  • 28
  • Thanks for this - unfortunately when I popped it in a codepen, both trackpad, magic mouse and mouse with wheel all seem to console log as wheel... so not finding it differentiating between wheel and pad I'm afraid: http://codepen.io/iamkeir/pen/XmYgGG?editors=001 Any thoughts? – iamkeir Oct 30 '15 at 14:25
  • have you reloaded the page after every test? because like i said, this script will detect once, if you change the device for scrolling it will not work as the script assumes that you are using the same device for scrolling since making the very first scroll on the page – David Fariña Nov 02 '15 at 16:09
0

None of the answers worked for me but here is what I did:

function detectTrackPadHorizontalMovement(event) {
    if (Math.abs(event.deltaY) < 5) return true
    if (Math.abs(event.deltaX) !== 0) return true
    return false
}

Touchpad almost always produces delta x and y where mouse wheel x is -0 Touchpad delta is smaller than 5 where mousewheel is bigger than 5 (for me usually around 13 I guess it depends on mousewheel speed)

Vasil Enchev
  • 1,656
  • 15
  • 18