Javascript Tutorial - The Scroll Wheel
| Below, there is a little box (which should say "Scroll In Me" unless you already played around). If your mouse cursor is over that box and you scroll the scroll wheel, it should print out two numbers in the box. The first number is the amount that the browser said your scroll wheel moved (which can be different depending on the bowser), and the second number is a 'normalized' version, which should be the same across all browsers. |
| Scroll In Me! |
Amusing, eh? Well, it actually isn't that hard to do at all. In the end, it is just a different event to attach to, and then you have to grab data off of the result event object. The weirdness comes in because IE and Firefox have very different names for the scroll event. In Internet Explorer, the event is called
onmousewheel, while in Firefox the event is called DOMMouseScroll. To make it even worse, Opera uses the Internet Explorer event name (without the 'on' part, so just mousewheel), but Opera needs to use the Firefox way of attaching event listeners.Fortunately, it is pretty easy to wrap up. Remember the
hookEvent and unhookEvent functions from way back in the Javascript Events tutorial? Well, they are about to get a small update:function hookEvent(element, eventName, callback)
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.addEventListener)
{
if(eventName == 'mousewheel')
{
element.addEventListener('DOMMouseScroll',
callback, false);
}
element.addEventListener(eventName, callback, false);
}
else if(element.attachEvent)
element.attachEvent("on" + eventName, callback);
}
function unhookEvent(element, eventName, callback)
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.removeEventListener)
{
if(eventName == 'mousewheel')
{
element.removeEventListener('DOMMouseScroll',
callback, false);
}
element.removeEventListener(eventName, callback, false);
}
else if(element.detachEvent)
element.detachEvent("on" + eventName, callback);
}
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.addEventListener)
{
if(eventName == 'mousewheel')
{
element.addEventListener('DOMMouseScroll',
callback, false);
}
element.addEventListener(eventName, callback, false);
}
else if(element.attachEvent)
element.attachEvent("on" + eventName, callback);
}
function unhookEvent(element, eventName, callback)
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.removeEventListener)
{
if(eventName == 'mousewheel')
{
element.removeEventListener('DOMMouseScroll',
callback, false);
}
element.removeEventListener(eventName, callback, false);
}
else if(element.detachEvent)
element.detachEvent("on" + eventName, callback);
}
Essentially, these two functions will let you always call the event
mousewheel - in keeping with most of the other event names. Essentially, for Internet Explorer, we just add the 'on' part when attaching it (and we already had to do that for all the other events), and for Firefox/Opera/Safari we just attach both mousewheel and DOMMouseScroll. We can do this because none of the browsers mind if we attach to an event that doesn't exist - so Firefox doesn't care about mousewheel and Opera doesn't care about DOMMouseScroll.But, sadly, that is only half the battle. There are two ways that the browsers return scroll wheel data. Thankfully, they are both on the event object -
detail (for Firefox and Opera), and wheelData (for Internet Explorer, Safari, and Opera). Opera went and implemented both for some reason. So a function to get wheel data might look something like this:function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail : e.wheelDelta;
//do something
}
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail : e.wheelDelta;
//do something
}
And that would be it, except for the fact that not only do the browsers use different property names, the scaling of the data is different. For instance, a value of 3 from Firefox or Opera in
detail is equal to a value of 120 in wheelDelta for Internet Explorer or Safari. Oh, and don't forget that scrolling down is a positive number for detail, but a negative number for wheelDelta. All that can be easily remedied, though, with a quick adjustment:function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;
//do something
}
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;
//do something
}
What this function does now is always return things using the Firefox scaling, but makes scrolling down negative (which I think makes the most sense). It is easy enough to change if you would like the final result in a different form. Generally, I've found that a result of 3 from this function is equal to a single click of the scroll wheel, but it actually can depend on your operating system and the type of mouse you are using.
There is one other thing that you are probably wondering. How do you make the page stop from scrolling when you are capturing the scroll event? Well, that is actually quite easy. Again, we are going to draw on the Events tutorial, this time grabbing the
cancelEvent function:function cancelEvent(e)
{
e = e ? e : window.event;
if(e.stopPropagation)
e.stopPropagation();
if(e.preventDefault)
e.preventDefault();
e.cancelBubble = true;
e.cancel = true;
e.returnValue = false;
return false;
}
{
e = e ? e : window.event;
if(e.stopPropagation)
e.stopPropagation();
if(e.preventDefault)
e.preventDefault();
e.cancelBubble = true;
e.cancel = true;
e.returnValue = false;
return false;
}
If you cancel the scroll wheel event, the page itself will not scroll. So, for instance, we can modify our above
MouseWheel function to read:function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;
//do something
return cancelEvent(e);
}
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;
//do something
return cancelEvent(e);
}
With that function, any scroll event that made it into that function would have no affect on the actual scrolling of the page.
So lets put all that together, and recreate the example from the top of the tutorial. First, the really simple html:
<div style="width:530px;height:75px;
border:1px solid black;" id="scrollContent">
</div>
border:1px solid black;" id="scrollContent">
</div>
Now for the javascript (using the
cancelEvent and hookEvent functions from above:function printInfo(e)
{
e = e ? e : window.event;
var raw = e.detail ? e.detail : e.wheelDelta;
var normal = e.detail ? e.detail * -1 : e.wheelDelta / 40;
document.getElementById('scrollContent').innerHTML =
"<br/> Raw Value: " + raw +
"<br/> Normalized Value: " + normal;
cancelEvent(e);
}
hookEvent('scrollContent', 'mousewheel', printInfo);
{
e = e ? e : window.event;
var raw = e.detail ? e.detail : e.wheelDelta;
var normal = e.detail ? e.detail * -1 : e.wheelDelta / 40;
document.getElementById('scrollContent').innerHTML =
"<br/> Raw Value: " + raw +
"<br/> Normalized Value: " + normal;
cancelEvent(e);
}
hookEvent('scrollContent', 'mousewheel', printInfo);
And that is that! Hopefully you are now enlightened when it comes to the mouse wheel and javascript, and as always, if you have any questions or comments, feel free to post them below.
Posted in Javascript, All Tutorials by The Tallest |

November 20th, 2007 at 1:32 pm
thanks
January 3rd, 2008 at 1:24 am
The functionality for (e) ? e : window.event; not clear
January 3rd, 2008 at 10:58 am
What it means is that if e is undefined/null (i.e., ‘false’), we need to use the event object from window.event. You can learn why this check has to happen in the Working With Events tutorial.
January 4th, 2008 at 4:43 am
Many thanks, this info was very helpful, I badly needed a discrete scrollbar - I mean scroll bar cannot be dragged to any part of the page, now I have my own custom scroll bar for this, instead of using overflow:scroll;
January 21st, 2008 at 11:39 am
Perfect!
This is exactly what I needed.
I have Google map on my site and need to deactivate page scrolling when zooming the map with wheel scroll. This solved my problem.
Thank you.
March 5th, 2008 at 9:05 am
Hi, great article.
I’m trying to find out if it is possible to prevent zooming in IE7 (ctrl-mousewheel, ctrl+ / ctrl-). Has anyone got some ideas?
thanks
July 9th, 2008 at 5:09 am
mark try to detect ctrl press then deactivate event key ctrl
August 5th, 2008 at 9:40 pm
Argh — amazing amazing article but one bug in here had me ripping my hair for 30 minutes trying to figure out why IE wouldn’t register any value!!
You wrote:
function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail : e.wheelData;
//do something
}
(This is the third box of code in the article.)
But that last variable should be e.wheelDelta, not e.wheelData.
=) Thanks though!
August 6th, 2008 at 7:15 am
Good catch. I’ve fixed the code block which had that typo. Thanks!