For a different question I composed this answer, including this sample code.
In that code I use the mouse wheel to zoom in/out of an HTML5 Canvas. I found some code that normalizes speed differences between Chrome and Firefox. However, the zoom handling in Safari is much, much faster than in either of those.
Here's the code I currently have:
var handleScroll = function(e){
var delta = e.wheelDelta ? e.wheelDelta/40 : e.detail ? -e.detail/3 : 0;
if (delta) ...
return e.preventDefault() && false;
};
canvas.addEventListener('DOMMouseScroll',handleScroll,false); // For Firefox
canvas.addEventListener('mousewheel',handleScroll,false); // Everyone else
What code can I use to get the same 'delta' value for the same amount of mouse wheel rolling across Chrome v10/11, Firefox v4, Safari v5, Opera v11 and IE9?
This question is related, but has no good answer.
Edit: Further investigation shows that one scroll event 'up' is:
| evt.wheelDelta | evt.detail ------------------+----------------+------------ Safari v5/Win7 | 120 | 0 Safari v5/OS X | 120 | 0 Safari v7/OS X | 12 | 0 Chrome v11/Win7 | 120 | 0 Chrome v37/Win7 | 120 | 0 Chrome v11/OS X | 3 (!) | 0 (possibly wrong) Chrome v37/OS X | 120 | 0 IE9/Win7 | 120 | undefined Opera v11/OS X | 40 | -1 Opera v24/OS X | 120 | 0 Opera v11/Win7 | 120 | -3 Firefox v4/Win7 | undefined | -3 Firefox v4/OS X | undefined | -1 Firefox v30/OS X | undefined | -1
Further, using the MacBook trackpad on OS X gives different results even when moving slowly:
wheelDelta
is a value of 3 instead of 120 for mouse wheel.detail
is usually 2
, sometimes 1
, but when scrolling very slowly NO EVENT HANDLER FIRES AT ALL.So the question is:
What is the best way to differentiate this behavior (ideally without any user agent or OS sniffing)?
Edit September 2014
Given that:
…I can only recommend using this simple, sign-based-counting code:
var handleScroll = function(evt){
if (!evt) evt = event;
var direction = (evt.detail<0 || evt.wheelDelta>0) ? 1 : -1;
// Use the value as you will
};
someEl.addEventListener('DOMMouseScroll',handleScroll,false); // for Firefox
someEl.addEventListener('mousewheel', handleScroll,false); // for everyone else
Original attempt to be correct follows.
Here is my first attempt at a script to normalize the values. It has two flaws on OS X: Firefox on OS X will produce values 1/3 what they should be, and Chrome on OS X will produce values 1/40 what they should be.
// Returns +1 for a single wheel roll 'up', -1 for a single roll 'down'
var wheelDistance = function(evt){
if (!evt) evt = event;
var w=evt.wheelDelta, d=evt.detail;
if (d){
if (w) return w/d/40*d>0?1:-1; // Opera
else return -d/3; // Firefox; TODO: do not /3 for OS X
} else return w/120; // IE/Safari/Chrome TODO: /3 for Chrome OS X
};
You can test out this code on your own browser here: http://phrogz.net/JS/wheeldelta.html
Suggestions for detecting and improving the behavior on Firefox and Chrome on OS X are welcome.
Edit: One suggestion from @Tom is to simply count each event call as a single move, using the sign of the distance to adjust it. This will not give great results under smooth/accelerated scrolling on OS X, nor handle perfectly cases when the mouse wheel is moved very fast (e.g. wheelDelta
is 240), but these happen infrequently. This code is now the recommended technique shown at the top of this answer, for the reasons described there.