So in Monday's post (about the Spin Control), I briefly mentioned using the mouse scroll wheel in javascript. Actually, what I really said was that you could use the scroll wheel with the spin control, and it would increment/decrement the spin control value as you moved the wheel. But I didn't go into any details at all as to how you can actually do this. Well, today, we are going to take a look at how to get scroll wheel information in javascript.
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 browser), 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:
{
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:
{
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:
{
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:
{
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:
{
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>
Now for the javascript (using the cancelEvent and hookEvent functions from above:
{
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 =
" Raw Value: " + raw + " 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.
11/20/2007 - 12:32
thanks
01/03/2008 - 00:24
The functionality for (e) ? e : window.event; not clear
01/03/2008 - 09:58
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.
01/04/2008 - 03:43
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;
01/21/2008 - 10:39
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.
03/05/2008 - 08:05
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
07/09/2008 - 04:09
mark try to detect ctrl press then deactivate event key ctrl
08/05/2008 - 20:40
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:
{
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!
08/06/2008 - 06:15
Good catch. I've fixed the code block which had that typo. Thanks!
10/10/2008 - 17:14
Note that if you want to refer the variable "element" to the entire window, you must use document.attachEvent rather than window.attachEvent in IE7 and possibly other versions of IE.
So, in IE7, hookEvent(window, 'mousewheel', printInfo); won't work. You need to use hookEvent(document, 'mousewheel', printInfo);
10/10/2008 - 17:19
One more thing, does anyone know why the scrolling is not smooth in Firefox 3 (both Win and Mac)? It works fine in Opera 9, IE 7, Safari (Mac), and Chrome.
11/20/2008 - 06:49
On chrome, the value is not corrected. It is divided by 40 but should be divided by 120 i think
11/29/2008 - 13:52
Perfect,thanks
04/22/2009 - 04:21
Anyone using this script to scroll a content inside a div using mouse wheel without having the entire page scroll as well? Please help if you can, I have no clue how to make this happen since Javascript is something I know nothing about! My problem is simple: I would like a script to scroll a content inside a div (avoiding css solution overflow: scroll and those nasty scroll bars). Is there a simple solution for this?
Thanks in advance!
04/22/2009 - 06:50
It is actually pretty simple - pretty much, after you have grabbed the event and done what you need (i.e., scroll the div) you want to cancel the event. That way, the event doesn't reach the browser as a whole, and so the page doesn't scroll. Canceling the event is covered in the tutorial above, so you can find the code for it there.
04/22/2009 - 07:37
Thanks a lot for the reply. I understood the script logically (you explained each step so well), no problem here. That is why I thought I could apply it to solve my issue. The problem is what to do, that is which function to use to scroll the content using javascript. This is kind of indirectly related to your script, as this function should go where you stated //do something (in my case scroll content inside div in your case it “counts scroll points”). I apologize if I am out of the line asking this since it is not actually a part of this script but it would mean a great deal if an expert like you could help.
Thnx.
04/22/2009 - 08:10
Ah! I didn't understand your question the first time. What you want to do is manipulate the
scrollTopandscrollLeftproperties of the div. These are the number of pixels that the element is scrolled - and to get the total scrollable area, look atscrollHeightandscrollWidth. For example, if you are scrolled all the way to the bottom of the the element,scrollTop + clientHeightshould be equal toscrollHeight.04/22/2009 - 09:28
Yes, exactly. So, can I find a tutorial for this somewhere (based on your “mouse listener”)? It is a long shot I know, but had to ask, since (and I am ashamed to admit it) the only thing I can do in javascript is basically customize it for my case (change names and such..). Sorry to bother you with this, I guess this simple problem does not have such simple solution.
04/23/2009 - 07:03
I don't know of a tutorial off hand that covers this topic - I might write one up in the next week or so.
08/17/2009 - 05:43
this one scrolls the
<div>window.onload = function()
{
if(window.addEventListener) document.addEventListener('DOMMouseScroll', moveObject, false);
document.onmousewheel = moveObject;
}
function moveObject(event)
{
var delta = 0;
if (!event) event = window.event;
if (event.wheelDelta)
{
delta = event.wheelDelta / 120;
}
else if (event.detail)
{
delta = -event.detail / 3;
}
var currPos=document.getElementById('Tst1');
if (delta != 0){
currPos.scrollTop=currPos.scrollTop - delta*10;
}
delta = 0;
}
</script>
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.