Ginger Binger

Lessons in programming, learning, and life

AS3 Mouse Wheel Trouble

| Comments

If you’ve ever tried to add mouse wheel support to a Flash web app, it’s likely you’ve run into this problem: Scrolling the mouse wheel will scroll the web page, regardless of any mouse wheel listeners or code you have inside the Flash. There seems to be no way to easily prevent the web page from scrolling. Here’s an example.

This is a regression from AS2. In AS2, adding a mouse wheel listener would prevent the web page from scrolling. Not so in AS3. Even preventDefault) doesn’t seem to help.

Currently, the best solution is to disable the mouse wheel in the browser using JavaScript such as with Liam O’Donnell’s MouseWheelTrap. Unfortunately, this solution only works if you have script access on the page that contains your Flash. In some cases, you don’t have control over where your SWF is hosted. It’d be nice if there was a Flash-side solution.

There is a little workaround that prevents the page from scrolling. If the mouse is over a TextField, and the TextField has more text than it can display, the mouse wheel will scroll the TextField, not scroll the web page! We can use this to our advantage by placing a TextField over the entire stage. Fill it with a ton of blank lines, prevent it from scrolling so it never reaches the top or bottom, and now it prevents the web page from scrolling. Here is the workaround in action.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);

// fill textfield with empty lines
const NUM_LINES:uint = 1000;
var dummyText:String = "";
for(var i:uint = 0; i < NUM_LINES; i++) {
  dummyText += "\n";
}
textField.text = dummyText;
// initially scroll to middle of text, so that we can scroll in both directions
textField.scrollV = NUM_LINES/2;

function onMouseWheel(event:MouseEvent):void {
  clip.y -= event.delta;
  // prevent TextField text from scrolling,
  // so that we can scroll indefinitely
  event.preventDefault();
}

This solution has a huge problem, though. Try clicking on the blue square in the first example, and then again in the second example with the workaround. Since a TextField is covering the stage, it will steal all of your MouseEvents, including clicks and rollovers. All of your buttons and mouse events will stop working! This might be OK in some cases where you don’t need full mouse functionality, such as a game that only checks mouseX and mouseY. But is there any way to use this workaround while still maintaining other mouse functionality?

The answer is probably not. I’ve tried all sorts of crazy schemes, such as:

  • setting the TextField’s width and height to 0 and making it follow the mouse,
  • listening for MouseOver events on the stage and adding the TextField as a child of the object the mouse is over,
  • fiddling with the TextField.mouseEnabled in ENTER_FRAME or RENDER handlers,
  • redispatching MouseEvents captured by the TextField to the clips that should have received them (!)

Most of these failed to maintain normal mouse control while always preventing the web page from scrolling. The last option seemed to be successful, but that’s an awful lot of messy work just to use a mouse wheel, and who knows if it causes any other problems!

Ideally, simply calling mouseEvent.preventDefault() should prevent the web page from scrolling. It looks like this is already a feature request on Adobe’s bug database, so if this has been bothering you as well, you should vote for it to encourage Adobe to fix this issue.

Cheers to Tyler Glaiel for turning me on to this problem.

Edit - May 04, 2011

Dennis Kolyako created a clever workaround that captures the mouse wheel by loading an AS2 movie inside the AS3 movie, allowing us to get the desired AS2 mouse functionality. This seems to be the best solution, so be sure to check it out. Thanks to Gaen for pointing it out!

Comments