How to check each new scroll and avoid Apple mouses issue (multiple-scroll effect)
Asked Answered
R

3

9

I try to make a mousewheel event script, but getting some issues since I'm using an Apple Magic Mouse and its continue-on-scroll function.

I want to do this http://jsfiddle.net/Sg8JQ/ (from jQuery Tools Scrollable with Mousewheel - scroll ONE position and stop, using http://brandonaaron.net/code/mousewheel/demos), but I want a short animation (like 250ms) when scrolling to boxes, AND ability to go throught multiple boxes when scrolling multiple times during one animation. (If I scroll, animation start scrolling to second box, but if I scroll again, I want to go to the third one, and if I scroll two times, to the forth, etc.)

I first thought stopPropagation / preventDefault / return false; could "stop" the mousewheel velocity (and the var delta) – so I can count the number of new scroll events (maybe with a timer) –, but none of them does.

Ideas?

EDIT : If you try to scroll in Google Calendars with these mouses, several calendars are switched, not only one. It seems they can't fix that neither.

EDIT 2 : I thought unbind mousewheel and bind it again after could stop the mousewheel listener (and don't listen to the end of inertia). It did not.

EDIT 3 : tried to work out with Dates (thanks to this post), not optimal but better than nothing http://jsfiddle.net/eZ6KE/

Rayner answered 4/10, 2012 at 12:23 Comment(3)
This won't be an issue just on Magic Mice, but all systems with inertia scrolling (i.e. all recent Macs, many newer PCs), Your suggestion about counting scroll events sounds sensible, and you may have to implement it yourself.Neonatal
Yes you're right, that's an inertia issue (and I'm experimenting this with my Magic Mouse). If counting scroll events sounds a good fix, I've no idea how to perform this. I tried to check – at each scroll event (called everytime during inertia) if previous delta was > or <, but the curve is not linear, it's elastic on my test. Any ideas ? (Thanks anyway!)Rayner
Possible fix : github.com/brandonaaron/jquery-mousewheel/issues/36 (untested yet).Rayner
B
1

Best way is to use a timeout and check inside the listener if the timeout is still active:

var timeout = null;
var speed = 100; //ms
var canScroll = true;

$(element).on('DOMMouseScroll mousewheel wheel', function(event) {
    // Timeout active? do nothing
    if (timeout !== null) {
        event.preventDefault();
        return false;
    }

    // Get scroll delta, check for the different kind of event indexes regarding delta/scrolls
    var delta = event.originalEvent.detail ? event.originalEvent.detail * (-120) : (
            event.originalEvent.wheelDelta ? event.originalEvent.wheelDelta : (
                    event.originalEvent.deltaY ? (event.originalEvent.deltaY * 1) * (-120) : 0
    ));

    // Get direction
    var scrollDown = delta < 0;

    // This is where you do something with scrolling and reset the timeout
    // If the container can be scrolling, be sure to prevent the default mouse action
    // otherwise the parent container can scroll too
    if (canScroll) {
        timeout = setTimeout(function(){timeout = null;}, speed);
        event.preventDefault();
        return false;
    }

    // Container couldn't scroll, so let the parent scroll
    return true;
});

You can apply this to any scrollable element and in my case, I used the jQuery tools scrollable library but ended up heavily customizing it to improve browser support as well as adding in custom functionality specific to my use case.

One thing you want to be careful of is ensuring that the timeout is sufficiently long enough to prevent multiple events from triggering seamlessly. My solution is effective only if you want to control the scrolling speed of elements and how many should be scrolled at once. If you add console.log(event) to the top of the listener function and scroll using a continuous scrolling peripheral, you will see many mousewheel events being triggered.

Annoyingly the Firefox scroll DOMMouseScroll does not trigger on magic mouse or continuous scroll devices, but for normal scroll devices that have a scroll and stop through the clicking cycle of the mouse wheel.

Brittaney answered 28/10, 2015 at 0:30 Comment(0)
S
0

I had a similar problem on my website and after many failed attempts, I wrote a function, which calculated total offset of selected box and started the animation over. It looked like this:

function getOffset() {
    var offset = 0;
    $("#bio-content").children(".active").prevAll().each(function (i) {
        offset += $(this)[0].scrollHeight;
    });
    offset += $("#bio-content").children(".active")[0].scrollHeight;

    return offset;
}

var offset = getOffset();
$('#bio-content').stop().animate( {
            scrollTop: offset
}, animationTime);

I hope it gives you an idea of how to achieve what you want.

Sponge answered 19/11, 2012 at 17:17 Comment(3)
I must be misunderstanding but I don't see how it can fix the issue…Rayner
From what I understand, you want to be able to scroll again while animation is happening. Am I right? If so, then what you need to do, is find out the offset of that particular box, you want to scroll to, stop the animation in progress and start a new one, which will scroll to your desired offset.Sponge
Actualy, the real issue is the impossibility to stop the inertia scroll once we launched an animation. Being able to launch it again (once we stopped inertia, and if user scroll again) is secondary. In your example like in mine, the animation will be called several times for one scrolling because of the inertia.Rayner
S
0

you can try detecting when wheel stops moving, but it would add a delay to your response time

$(document).mousewheel(function() {
  clearTimeout($.data(this, 'timer'));
  $.data(this, 'timer', setTimeout(function() {
     alert("Haven't scrolled in 250ms!");
     //do something
  }, 250));
});

source: jquery mousewheel: detecting when the wheel stops?

or implement flags avoiding the start of a new animation

var isAnimating=false;

$(document).bind("mousewheel DOMMouseScroll MozMousePixelScroll", function(event, delta) {
   event.preventDefault();
   if (isAnimating) return;
   navigateTo(destination);
});

function navigateTo(destination){
   isAnimating = true;
   $('html,body').stop().animate({scrollTop: destination},{complete:function(){isAnimating=false;}});
}
Schoolgirl answered 11/3, 2014 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.