Mouse Wheel Programming in JavaScript

AID: 2281
  • Status: Published

9650 points

  • By
  • TypeTutorial
  • Posted on2010-01-16 at 20:11:44
Awards
  • Experts Exchange Approved
In this article I'll describe cross-browser techniques for using the mouse wheel (or "scroll wheel") in your JavaScript programming for HTML pages.  I'll show example Javascript for option selection and image zooming.

The mouse wheel is generally used for scrolling, but it can also be convenient for other U/I functionality.  Image zooming is a common use; for instance in Google Maps, spinning the mouse wheel zooms you in or out.  I've seen the mouse wheel used to raise or lower the "camera viewpoint" in first-person 3D games.  Another use I've seen is to cycle though a series of objects.  In HalfLife, et al., you can choose a weapon with the wheel -- though it's a bit awkward (it's better to use the direct choice keys [1,2,3...] if you want to avoid becoming fragmeat by the time you find the weapon you want.)

I was revising an old JavaScript program I'd written years ago (when mouse wheels were uncommon) and I realized that I could improve the UI by supporting mousewheel events.
Fig1-1.jpg
  • 29 KB
  • Pentomino piece selection with the mouse wheel.
Pentomino piece selection with the mouse wheel.

The application is a fascinating puzzle/game called Pentominos.  For some background, see the Wikipedia entry.  You can see my revised (but unfinished) recreational programming project  here.

The goal of Pentominos is to place all 12 pieces into the puzzle board.  But each piece can be rotated and/or flipped in various ways, so there are a total of 62 unique shapes (piece orientations).  In the earlier version, each time you click on a piece in the lower frame, it would cycle from one orientation to the next.  This version still handles that, but it also lets you use the mouse wheel to spin through the options.

One challenge of supporting the mouse wheel is that there are differences in how each of the major webbrowsers implement the event handling.  In the following code, I'll show the basic technique that works for (at least) IE, Firefox, and Chrome.

What do you need to know about a mousewheel event?

  • The direction of the spin.  We'll set up a delta value of +1 to mean "forward/larger" and -1 to mean "backward/smaller."

  • Mouse location.  The X,Y coordinates in the event object are the same as for mouse clicks, and they can be used without any special handling.

  • The on-screen object that is in play.  This can be determined by the mouse location OR you can assign a separate event listener for each object that can be affected by wheel spins (that's the technique I'll show here).

  • How much of a spin was given.  The mouse wheel itself usually works in single-step increments.  You roll the wheel one "notch" at a time, and each "wheel click" is an individual event.  It is possible to keep track of these events and synthesize a "velocity" or "distance" even an "inertia" for use in your program, but we won't go into that here.


In the following code snippets, the HTML page is assumed to include...
<body onload="DoSetup();">
<div id="oInfo"></div>
<img id="oImage" src="PL0.jpg" alt="The 'L' Piece">
                                    
1:
2:
3:

Select allOpen in new window

...which creates an IMG object named oImage that will be the target of mousewheel events and a DIV for debugging and displaying information.  

Here's the core of this article... the actual cross-browser event handler:

"" title="Event Handler"]

function onMouseWheelSpin(e) {
    var nDelta = 0;
    if (!e) { // For IE, access the global (window) event object
        e = window.event;
    }
    // cross-bowser handling of eventdata to boil-down delta (+1 or -1)
    if ( e.wheelDelta ) { // IE and Opera
        nDelta= e.wheelDelta;
        if ( window.opera ) {  // Opera has the values reversed
            nDelta= -nDelta;
        }
    }
    else if (e.detail) { // Mozilla FireFox
        nDelta= -e.detail;
    }
    if (nDelta > 0) {
        HandleMouseSpin( 1, e.clientX, e.clientY );
    }
    if (nDelta < 0) {
        HandleMouseSpin( -1, e.clientX, e.clientY );
    }
    if ( e.preventDefault ) {  // Mozilla FireFox
        e.preventDefault();
    }
    e.returnValue = false;  // cancel default action
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:

Select allOpen in new window

And here's how to set up so that the above code gets called:

"" title="Event Handler Setup"]

//-------- set up to handle wheel events on object: oImage
function DoSetup() {
    if (oImage.addEventListener) {
        oImage.addEventListener('DOMMouseScroll', onMouseWheelSpin, false);
        oImage.addEventListener('mousewheel', onMouseWheelSpin, false); // Chrome
    }
    else {
        oImage.onmousewheel= onMouseWheelSpin;
    }
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window


Note: You can also set the event handler other ways, such as coding it directly in the HTML:
           <img id="oImage" src="PL0.jpg" onmousewheel="SomeFn()">
but using a DoSetup() function like this is the most flexible since it lets you use some cross-browser compatibility logic, as shown.


We have an object (oImage) and a way to set up a wheel handler, so now we just need to provide some program code that will do something with or to that object when the mousewheel spins on it.  Each "wheel click" will trigger the event which will call your custom function named HandleMouseSpin().


Item/Option Selection
In this first example, we'll cycle through the eight possible orientations for a particular pentomino piece, as illustrated in fig1-1, above.   I have eight JPG files named PL0.jpg, PL1.jpg,... PL7.jpg so all I need to do is is change the src attribute of that object to swap-in a different version of the puzzle piece.   A "wheel forward" event (delta= +1) goes forward though the list and a "wheel backward"  event (delta= -1) goes backward though the list.  Upon reaching the end of the list, it wraps to the other end.

"" title="Example HandleMouseSpin function"]Item Selection

//----------- change the image from PL0.jpg to PL1, PL2,... PL7... PL0
var gnOrient = 0;
function HandleMouseSpin( nDelta, x,y ) {
    gnOrient += nDelta;
    if (gnOrient < 0) gnOrient = 7;
    if (gnOrient > 7) gnOrient = 0;
    
    oImage.src="PL"+gnOrient+".jpg";
    oInfo.innerHTML = "Delta: " + nDelta + "<br>" + oImage.src;
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window



Image Magnification
As a second example, we'll use the same HTML, but change the handler so that mousewheel action enlarges or shrinks the image.  
Fig1-2.jpg
  • 63 KB
  • Image zooming with the mouse wheel
Image zooming with the mouse wheel

"" title="Example HandleMouseSpin function"]Image Zoom

//----------- increase/decrease the size of the image
var gnOrigWide = -1;
var gnZoomLevel= 100;
function HandleMouseSpin(nDelta, x, y) {
    if (gnOrigWide == -1) {
        gnOrigWide = oImage.width;
    }
    gnZoomLevel += nDelta * 10;
    if ( gnZoomLevel < 10) gnZoomLevel=10;
    var nNewWide = (gnOrigWide * gnZoomLevel) / 100;
    oImage.width = nNewWide;

    oInfo.innerHTML = "Delta: " + nDelta + "<br>zoomed to: " + gnZoomLevel +"%";
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

Select allOpen in new window



Summary
This article shows how to add cross-browser mousewheel awareness to your HTML pages.  Since virtually every mouse has a "scroll wheel" nowadays, it makes sense to use it to enrich the experience of your viewer.

However, you should take care to not override the normal functioning of the mousewheel unless there is good reason...

Users expect to be able to use the wheel for normal page (and textarea) scrolling.  But when you have a non-scrolling page, or if you handle the event only on specific objects (not the document or the window as a whole) then it can be a useful shortcut for your users.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If you liked this article and want to see more from this author, please click the Yes button near the:
      Was this article helpful?
label that is just below and to the right of this text.   Thanks!
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  
    Asked On
    2010-01-16 at 20:11:44ID2281
    Tags

    mousewheel

    ,

    scroll wheel

    ,

    DOMMouseScroll

    ,

    onmousewheel

    ,

    pentominos

    ,

    wheelDelta

    ,

    Dan Rollins

    Topic

    JavaScript

    Views
    7959

    Comments

    Expert Comment

    by: Qlemo on 2010-01-24 at 14:21:38ID: 8413

    Well written as always. Got my YES.

    Expert Comment

    by: mplungjan on 2010-02-17 at 07:35:19ID: 9747

    I would change

    //-------- set up to handle wheel events on object: oImage
    function DoSetup() {
        if (oImage.addEventListener) {
    
    to
    //-------- set up to handle wheel events on object: oImage
    function DoSetup() {
      var oImage = document.getElementById('oImage');
      if (oImage.addEventListener) {1
                                            
    1:
    2:
    3:
    4:
    5:
    6:
    7:
    8:
    9:
    

    Select allOpen in new window

    Expert Comment

    by: mplungjan on 2010-02-17 at 07:50:32ID: 9749

    Add your Comment

    Please Sign up or Log in to comment on this article.

    Join Experts Exchange Today

    Gain Access to all our Tech Resources

    Get personalized answers

    Ask unlimited questions

    Access Proven Solutions

    Search 3.2 million solutions

    Read In-Depth How-To Guides

    1000+ articles, demos, & tips

    Watch Step by Step Tutorials

    Learn direct from top tech pros

    And Much More!

    Your complete tech resource

    See Plans and Pricing

    30-day free trial. Register in 60 seconds.

    Loading Advertisement...

    Top JavaScript Experts

    1. leakim971

      511,289

      Sage

      2,168 points yesterday

      Profile
      Rank: Genius
    2. mplungjan

      291,279

      Guru

      2,800 points yesterday

      Profile
      Rank: Savant
    3. nap0leon

      195,491

      Guru

      0 points yesterday

      Profile
      Rank: Sage
    4. Proculopsis

      182,948

      Guru

      0 points yesterday

      Profile
      Rank: Sage
    5. COBOLdinosaur

      157,309

      Guru

      0 points yesterday

      Profile
      Rank: Genius
    6. chaituu

      130,684

      Master

      0 points yesterday

      Profile
      Rank: Sage
    7. Ray_Paseur

      130,217

      Master

      330 points yesterday

      Profile
      Rank: Savant
    8. tommyBoy

      125,345

      Master

      0 points yesterday

      Profile
      Rank: Genius
    9. StingRaY

      114,318

      Master

      0 points yesterday

      Profile
      Rank: Wizard
    10. DaveBaldwin

      80,081

      Master

      336 points yesterday

      Profile
      Rank: Genius
    11. ansudhindra

      79,054

      Master

      2,000 points yesterday

      Profile
      Rank: Wizard
    12. ChrisStanyon

      62,768

      Master

      800 points yesterday

      Profile
      Rank: Sage
    13. hielo

      61,266

      Master

      0 points yesterday

      Profile
      Rank: Savant
    14. HainKurt

      59,030

      Master

      0 points yesterday

      Profile
      Rank: Genius
    15. BuggyCoder

      54,739

      Master

      0 points yesterday

      Profile
      Rank: Sage
    16. mroonal

      54,339

      Master

      10 points yesterday

      Profile
      Rank: Sage
    17. tagit

      54,093

      Master

      1,600 points yesterday

      Profile
      Rank: Genius
    18. gurvinder372

      52,824

      Master

      10 points yesterday

      Profile
      Rank: Genius
    19. basicinstinct

      52,586

      Master

      0 points yesterday

      Profile
      Rank: Genius
    20. JonNorman

      45,158

      2,200 points yesterday

      Profile
      Rank: Master
    21. Lalit-Chandra

      44,420

      0 points yesterday

      Profile
      Rank: Master
    22. xmediaman

      36,450

      3,800 points yesterday

      Profile
      Rank: Guru
    23. kozaiwaniec

      33,100

      0 points yesterday

      Profile
      Rank: Guru
    24. Kravimir

      32,700

      0 points yesterday

      Profile
      Rank: Genius
    25. designatedinitializer

      32,300

      0 points yesterday

      Profile
      Rank: Master

    Hall Of Fame