Something Wrong with the System

A Flash/Actionscript blog

Zoom In/Out Image viewer (.swf & source)

First of all, I made it to ten posts! W00, I really wasn’t sure if I’d make it this far.

Recently at work, I had to write an AS3 image viewer with zoom and pan capabilities. It was a lot harder than I had anticipated. I decided to write another (much better) version for the blog. I’m hoping that by releasing this code I’m saving a couple people a lot of grief.

You can zoom in/out with the buttons in the bottom right corner, or by using your mouse wheel (Mouse wheel might not work on a Mac! Let me know if it’s an issue or if you have a solution).

After the break you can see the application in action.

I’ll also try to explain some of the ActionScript parts I found interesting.

Here's a link to the swf on it's own. The mouse wheel reacts better if your whole browser window isn't scrolling along with it.

Download the Source

Now to the code!

First I should let you know that there's a lot of code in the .as files, it's mostly UI stuff though so don't panic.

I handle zooming two different ways.

The first type of zoom is associated with the mouse Wheel and clicks on the stage.

When I was thinking about the problem, I reduced it down to the following:

When I zoom on an image, how do I ensure that the pixel under the mouse cursor before zooming is the same pixel under the mouse cursor after zooming.

POINT #1:

Find the relative X,Y position of the mouse inside the image before zooming. This is the x,y position inside the image.

POINT #2

I scale the image to it's new value.

POINT #3

Now I sample the X,Y pixels under the mouse after the image is scaled.

Next, I want to figure out how many pixels I have to shift the image so that the original X,Y values are still underneath the mouse cursor.

To do this I subtract the original X,Y values from Step #1 by the new scaled X,Y values, and multiply the result by the scale of the image. Remember that the values I've been sampling so far have been in the scope of the zoomed image. Multiplying the result by the scale moves things to the relative scope of the stage.

POINT #4

I set the new position of the image. And then run it by a validation function to make sure that the image is still properly centered on the stage.


private function zoomOnMouse():void {

  //POINT #1
  var overPixelX:Number = displayLayer.mouseX;
  var overPixelY:Number = displayLayer.mouseY;

  //POINT #2

  displayLayer.scaleX = displayLayer.scaleY = zoomPosition;

  //POINT #3

  var pixelDifferenceX:Number = (overPixelX - displayLayer.mouseX) * zoomPosition;

  var pixelDifferenceY:Number = (overPixelY - displayLayer.mouseY) * zoomPosition;

  //POINT #4

  var nextX:Number = displayLayer.x - pixelDifferenceX;
  displayLayer.x = validateX(nextX);
  var nextY:Number = displayLayer.y - pixelDifferenceY;
  displayLayer.y = validateY(nextY);
}

When the user zooms using the slider I use a different function. Here I find the top left viewable pixels of the image and add to that Half of the Stages width/height to find the center pixels of the viewable area.

Then I figure out what their ratio to image is. If the image is zoomed in on the left I'd get something like 0.2. Now when I enlarge or shrink the image I just multiply that ratio by the width/height of the image and the image will be re-centered to the same relative position it was before.


private function zoomToCenter(evt:Event) {
  var overPixelX:Number = -displayLayer.x + (stageWidth / 2);
  var overRatioX:Number = overPixelX / displayLayer.width;
  var overPixelY:Number = -displayLayer.y + (stageHeight / 2);
  var overRatioY:Number = overPixelY / displayLayer.height;
  zoomPosition = zoomSlider.value;
  displayLayer.scaleX = displayLayer.scaleY = zoomPosition;
  var nextX:Number = (stageWidth / 2) - (displayLayer.width * overRatioX);
  var nextY:Number = (stageHeight / 2) - (displayLayer.height * overRatioY);
  displayLayer.x = validateX(nextX);
  displayLayer.y = validateY(nextY);
}

So, the one nagging question I'm left with is why I couldn't consolidate the two zoom types... Ultimately, I went two separate routes because it was easier. When I tried to use the same code for both it ended up looking funny. Probably a bug on my part but I wasn't in the mood to dig deeper.

Also, I really should have split up the mouse icon handling stuff into a separate class.

I've decided to distribute this code under the MIT license as it's a potentially useful application. Feel free to download and modify the code to your hearts content. Just make sure I'm credited!

May 18th, 2008 by Peter Organa

21 Responses to “Zoom In/Out Image viewer (.swf & source)”

  1. Chris Says:

    The zoom doesn’t work on my Mighty Mouse’s scroll wheel, but it’s a-OK otherwise!

  2. Peter Organa Says:

    Yeah, something fishy about how the scroll wheel works. Not sure if it’s just an OS issue or something deeper. Doesn’t really matter too much, I added drag functionality when you’re in zoom in/out mode. Just drag the mouse and it’ll switch to drag mode auto-magically!

  3. Anya Says:

    The only problem I’m having is possibly because it’s posted on the blog. When I use my scroll mouse wheel it not only controls the picture but controls the browser window as well – which makes for a very … distracting viewing.

    Up, down, side to side
    Up, down, side to side

    Sorry – a very weird song with those words popped into my head while writing this…

  4. marcinz Says:

    make it open in a new window with no scroll using js, the scroller works but stupid browser scrolls too

  5. Peter Organa Says:

    http://blog.organa.ca/flashContent/zoomGuy/zoom.html

    There is a link to the solo swf in the post guys, it’s right under the swf 😀

    I figured the scroll wheel might be a problem, but that’s why I provided two alternative navigation methods.

  6. Anya Says:

    Now really, are you truly expecting us to be that un-lazy? That we would actually click ANOTHER link? Look who you’re talking to!

    :oP

  7. Ben Reed Says:

    Hey! nice work, I found the post on Kirupa’s forums as I need to do something similar to this myself!

    As for the question of Mac OSX scroll wheels try this: http://blog.pixelbreaker.com/2006/11/08/flash/swfmacmousewheel/

    it is an add on for SWFObject that enables the use of the scroll wheel on a mac. I havent used it myself but I imagine it works fine.

    Thanks again for releasing this code, I wasn’t looking forward to doing this from scratch!

  8. Me Says:

    Mouse wheel scrolling is an issue with Windows too. Scrolling the wheel upwards works fine, but scrolling the wheel downwards causes the browser window to scroll instead.

  9. Alessandro Curci Says:

    nice, but where’s the .fla ?

  10. Alessandro Curci Says:

    ops! just found it 😉

  11. camel_smuggler Says:

    Legendary stuff dude!!!
    Ive been searching for what seems to be a lifetime, looking for this!
    Just a little thing.
    How do I change the zoom parameters? I need the minimum to be 100% and the maximum to be 300%?
    Cheers
    Keep up the good work

  12. michael Says:

    hey thank you very much i love your example it is very useful

  13. Morkus Says:

    Hey i really need to do the same thing but 2 my map you know you can look at it at http://www.hurghada.com/map.aspxand i would be really greatfull if you told me which part i could use to add it to my action script to apply this zooming to my map plz contact me and i will send you the source for the map part and if you could help me that would be gr8 and iam willing to pay you for your help please contact me thnx i really need help with it thnx alot

  14. Zuper Says:

    You saved my life, man. I also thought this was going to be much easier.

  15. Perry Says:

    I love the example, but when I download the code and transfer it to my website design (Flash CS4 / AS3) if don’t work. All I get is a black box and red preload bar on the screen. Can you tell me what I am doing wrong.

  16. Marcus Says:

    This is a really unique way of setting up a drag/zoom class. I’m currently trying to figure out different methods of pan/drag/zooming, and was wondering (if you have the time that is) if you might describe basically how and in what order these functions are called out. Also, I’ve been messing with trying to add a tween on release with the dragging (so that it slides to a stop) and while that would be a simple task with most draggers, I’m stumped on yours. Any insight would be much appreciated…just trying to learn at this point.

  17. David Alexandru Says:

    10x u for this great script. It saved me a lot of time.

  18. Brad Kut Says:

    Speaking for inexperienced users: We did step-by-step instruction for this script. The source files are simply not enough.

  19. Kyle Evans Says:

    This is epic – thanks SO much for posting this! Incredibly useful.

  20. Arnaud Says:

    This is great, thanks a lot. However, i’ve noticed a little zoom out when the blue ball of the slider is pressed for the first time (before actually moving the ball along the bar).

  21. Peter Organa Says:

    Hey Arnaud,

    You’re right. This code is buggy 🙂

    Sadly, it’s also so old I don’t want to mess with it anymore, so you’re stuck with what you see here.

    Maybe if I can stop playing video games long enough I’ll make a completely new version. But I’m also working on a iPhone game so don’t hold your breath 🙂