Mousewheel event stop occurs twice on OSX

I noticed that the mousewheel event occurs several times on mac osx. Can be applied to inertia function.

Is there any way to fix this behavior?

(self-signed ssl is not worried, please!) https://sandbox.idev.ge/roomshotel/html5_v2/

I am using scrollSections.js https://github.com/guins/jQuery.scrollSections

And he uses the mousewheel jquery plugin: https://github.com/brandonaaron/jquery-mousewheel

I see many people having the same problem: https://github.com/brandonaaron/jquery-mousewheel/issues/36

There are several solutions, but no one works with the scrollSections plugin.

Any ideas on how to disable this inertia function from JS?

My attempt to fix:

// Fix for OSX inertia problem, jumping sections issue. if (isMac) { var fireEvent; var newDelta = deltaY; if (oldDelta != null) { //check to see if they differ directions if (oldDelta < 0 && newDelta > 0) { fireEvent = true; } //check to see if they differ directions if (oldDelta > 0 && newDelta < 0) { fireEvent = true; } //check to see if they are the same direction if (oldDelta > 0 && newDelta > 0) { //check to see if the new is higher if (oldDelta < newDelta) { fireEvent = true; } else { fireEvent = false; } } //check to see if they are the same direction if (oldDelta < 0 && newDelta < 0) { //check to see if the new is lower if (oldDelta > newDelta) { fireEvent = true; } else { fireEvent = false; } } } else { fireEvent = true; } oldDelta = newDelta; } else { fireEvent = true; } 

You can see the fix implemented here: https://sandbox.idev.ge/roomshotel/html5_v2/ But this is a hit / miss.

+6
source share
4 answers

The last timeout solution had one major drawback: the kinetic scrolling effect can last quite a long time (even 1 second or so) ... and disabling scrolling for 1-2 seconds would not be the best solution.

Soooo, as promised, here is a different approach.

Our goal is to provide one answer for one user action, which in this case scrolls.

What a "scroll" . To solve this problem, letโ€™s say that โ€œscrollingโ€ is an event that lasts from the moment the page transition begins until the moment the movement ends .

The effect of kinetic scrolling is achieved by moving the page many times (say, every 20 ms) a short distance. This means that our kinetic scroll consists of many very small linear โ€œscrollsโ€.

Empirical testing has shown that these small โ€œscrollsโ€ occur every 17-18 m in the middle of the kinetic scroll and about 80-90 ms at the beginning and at the end. Here is a simple test we can install to see that:

 var oldD; var f = function(){ var d = new Date().getTime(); if(typeof oldD !== 'undefined') console.log(d-oldD); oldD = d; } window.onscroll=f; 

Attention! Each time this mini-scroll occurs, a scroll event is fired. So:

  window.onscroll = function(){console.log("i'm scrolling!")}; 

will shoot 15 to 20 times in one kinetic scroll. BTW, onscroll has really good browser support (see the compatibility table ), so we can rely on it (with the exception of touch devices, I will talk about this problem a bit later);

Some might say that overriding window.onscroll is not the best way to set event listeners. Yes, you are advised to use

  $(window).on('scroll',function(){...}); 

or whatever you like, this is not a problem problem (I personally use my own library).

So, with the onscroll event, we can confidently say whether this particular mini-page motion belongs to one solid kinetic scroll, or is it new:

  var prevTime = new Date().getTime(); var f = function(){ var curTime = new Date().getTime(); if(typeof prevTime !== 'undefined'){ var timeDiff = curTime-prevTime; if(timeDiff>200) console.log('New kinetic scroll has started!'); } prevTime = curTime; } window.onscroll=f; 

Instead of "console.log", you can call the desired callback function (or event handler), and you're done! The function will be launched only once for each kinetic or simple scroll that was our goal.

You may have noticed that I used 200 ms as a criterion for whether this is a new scroll or part of a previous scroll. It is up to you to set higher values โ€‹โ€‹at 999% to prevent additional calls. However, keep in mind that this is NOT what we used in my previous answer. This is just a period of time between any two page movements (whether it is a new scroll or a small part of a kinetic scroll). In my opinion, there is very little chance that there will be a lag of more than 200 ms between steps in the kinetic scroll (otherwise it will not be completely smooth).

As I mentioned above, the onscroll event works differently on touch devices. It does not work with every small step of the kinetic scroll. But it will fire when the page movement is finally over. Moreover, there is an ontouchmove event ... So, this is not very. If necessary, I can also offer a solution for touch devices.

PS I understand that I wrote too much, so I would be happy to answer all your questions and provide additional code if you need to .

The provided solution is supported in all browsers, it is very lightweight and, more importantly, suitable not only for Mac, but also for every device that can perform kinetic scrolling, so I think this is really a way.

+5
source

You know, I think it's better to use timeouts in this case. Why not write something like this:

 // Let say it a global context or whatever...: var fireEvent = true; var newDelta, oldDelta, eventTimeout; newDelta = oldDelta = eventTimeout = null; // ... and the function below fires onmousewheel or anything similar: function someFunc(){ if(!fireEvent) return; // if fireEvent is not allowed => stop execution here ('return' keyword stops execution of the function), else, execute code below: newDelta = deltaY; if(oldDelta!=null&&oldDelta*newDelta>0){ // (1.1) if it not the first event and directions are the same => prevent possible dublicates for further 50ms: fireEvent = false; clearTimeout(eventTimeout); // clear previous timeouts. Important! eventTimeout = setTimeout(function(){fireEvent = true},500); } oldDelta = newDelta; someEventCallback(); // (1.2) fire further functions... } 

So, any mousewheel event fired within half a second after any previous mouse call will be ignored if it is done in the same direction as the previous one (see condition in 1.1). . This will solve the problem, and in no way would the user notice this. The amount of delay can be changed to better meet your needs.

The decision is made on pure JS. You can ask any questions about integration into your environment, but then you will need to provide additional code for your page.

PS I did not see anything like calling eventCallback () in your code (see 1.2 of my solution). there was only a fireEvent flag. You did something like:

 if(fireEvent) someEventCallback(); 

later or something else?

PPS Note that fireEvent must be in the global scope in order to work here with setTimeout. If this is not the case, it is also very easy to get it working fine, but the code needs to be changed a bit. If this is your business, tell me and I will fix it for you.

UPDATE

After a brief search, it turned out that a similar mechanism is used in the Underscore _debounce () function. See the documentation under the heading here.

+4
source

Did you use fullpage.js ? It has a delay between arriving at the section and the moment when you can move on to the next section, which solves part of the problem that Mac users face with track mats or magic Apple mice.

It will also provide you with some other benefits, such as many more options, methods, and compatibility with touch devices and older browsers without CSS3 support.

+1
source

To start with something, let your solution be shorter (so it's easier to understand and debug):

 var fireEvent; var newDelta = deltaY; var oldDelta = null; fireEvent = EventCheck(); oldDelta = newDelta; function EventCheck(){ if(oldDelta==null) return true; //(1.1) if(oldDelta*newDelta < 0) return true; // (1.2) if directions differ => fire event if(Math.abs(newDelta)<Math.abs(oldDelta)) return true; // (1.3) if oldDelta exceeds newDelta in absolute values => fire event return false; // (1.4) else => don't fire; } 

As you can see, it does absolutely what your code does. However, I cannot understand this part of your code (which corresponds to (1.3) in my fragment):

  //check to see if the new is lower if (oldDelta > newDelta) { fireEvent = true; } else { fireEvent = false; } 

from the code, if it is not clear how deltaY is calculated. As you might expect, the delta is equal to endPosition - initialPosition. So, oldDelta> newDelta does not mean that the new position is lower, but the new gap between the two values โ€‹โ€‹is wider. If this is what it means and you are still using it, I suppose you are trying to track the inertia with that. Then you must change the comparison operator (use less than instead, and vice versa). In other words, I would write:

 if(Math.abs(newDelta)>Math.abs(oldDelta)) return true; // (1.3) 

You see, now I used the "greater than" operator, which means: newDelta is greater than oldDelta in absolute values โ€‹โ€‹=> this is not inertia, and you can still fire the event.

Is this what you are trying to achieve, or am I misinterpreting your code? If so, explain how deltaY is calculated and what your goal was, comparing old and new Deltas. Postscript I suggest not using if (isMac) at this step, while the problem could also potentially hide there.

0
source

Source: https://habr.com/ru/post/976637/


All Articles