February 5, 2008

Zooming
in Flash & Flex

Have you ever tried to implement zooming that works like Google Maps where you can use your mouse wheel to zoom to a particular point on the map?

Well, I did and it took me quite some time to get zooming to work like that. Typically, in Flash or Flex, if you scale an object it uses the upper left corner as reference point and this can lead to akward results like the ones in the following example:

Example: Zooming Broken

To zoom, use your mouse wheel or the arrow keys on your Keyboard, especially if you're on a Mac where Flash Player is (still) missing mouse wheel support.
To rotate the object, press and hold the Alt key while scrolling.
Panning works with drag and drop or, again, with the arrow keys on your keyboard.

Example: Zooming Broken

View Example

Basically, any transformation that you apply to a DisplayObject has its origin at the object's registration point. The registration point of an object is typically the upper left corner and cannot be changed directly in ActionScript.

While working on tandem, I tried to implement the behavior that normal mapping applications have where you can zoom to the coordinates your mouse points at by scrolling. Oh my, how long it took me. To work around the issue, I nested two Sprites and moved the inner object in such a way that the registration point of the outer one was at the coordinates of the mouse. This way to dynamically change the registration point was a hack at best.

However, the revelation came soon: zooming (or scaling) is a linear transformation. This means I can scale an object and readjust its position afterwards so that it appears as if it has never moved but rather scaled right from the origin I pointed at.

At this point I successfully wrote a function to scale from an arbitrary point on an object. This code was not too long, actually pretty sweet after all my previous, fruitless endeavours. But yesterday, after looking at the source code of Piccolo, a powerful framework for building Zoomable User Interfaces (ZUI) in Java or C#, I came across an even more elegant solution:

AffineTransform is the name of the class where the magic lies in Java.

What Are Affine Transformations?

Affine transformations are part of the mathematics of linear algebra. Simply put, they are a way to mathematically describe transformations such as scale, rotation, skew and translation. An interesting property of affine transformations is that they preserve the straightness of lines while transforming, so that parallel lines stay parallel.

I won't go into deeper discussion of this topic at this point but if you have time, I recommend you to read the theory behind affine transformations and linear algebra in general. Before this enlightening experience I am about to share here, linear algebra and I were not very close. I took a linear algebra course in first semester computer science but unfortunately the professors never got around using 2D or 3D as basis for their examples which would have been great. They didn't do it because it seemed that they only got excited about n-dimensional vector spaces where n > 5. Too bad.

Affine Transformations & Flash

When I made my discovery in the source code of Piccolo, I was about to port the Java AffineTransform class to ActionScript. Then I discovered that ActionScript had a similar class called Matrix.

Basically, any visible object in Flash has a transformation attached to it which can be accessed through a property called transform. What you'll get is a Transform object that gives you, through its matrix property, access to the transformation matrix of a DisplayObject.

Usually, we change the appearance of a Sprite or MovieClip (both inherit from DisplayObject) through properties such as x, y, width, height, scaleX, scaleY or rotation. These properties can be seen as a high-level abstraction of the underlying transformation matrix of a DisplayObject.

Basically, if you need more low-level access, for example to implement zooming or rotating around a particular point, use the Transform and Matrix class.

Enough theory, let's see how it's done.

Example: Zooming Done Right

Example: Zooming

View Example | View Source | Download Source (ZIP, 5KB)

Code Walk-Trough

Let us go step by step through the code of the example class called ZoomCanvas that you'll find in the source of the example above.

Let's say you have an object you want to scale at a certain point.
First, you get its transformation Matrix:

44
   affineTransform = transform.matrix

Then you move the object to the origin of the point you want to scale from:

49
   affineTransform.translate( -originX, -originY )

After that, you are safe to scale the object:

52
   affineTransform.scale( scale, scale )

Then, you simply move the object back to its original position:

55
   affineTransform.translate( originX, originY )

In the end, you apply the new transformation to the object

59
   transform.matrix = affineTransform

Since I love clear and simple code, I was very pleased with the result.
From my observations this method for transforming an object seems at least as fast as the conventional way of doing it.

I hope this helps you as much as it did help me.

Further Reading


Thoughts
  1. 06.02.2008
    10:44

    Dominik Kaeser

    If you had been in my Linear Algebra HS2007 lessons, you would have known this before fiddling around with it. :P
    A classical matrix application :)
    Cheers

  2. 06.02.2008
    10:52

    Daniel Gasienica

    Hey Dominik,
    Thanks, you are probably right.
    As I said, there’s room for improvement in ETH’s linear algebra curriculum.
    Regards,
    Daniel

  3. 06.02.2008
    11:20

    bo

    You might also be interested in how this is done in an n-dimensional vector space where n = 3 ;)
    http://msdn2.microsoft.com/en-us/library/bb206260.aspx

  4. 29.02.2008
    6:43

    Andrew

    Daniel,
    Fantastic post! This has cleared up a lot of my frustrations, as I’ve been struggling with the exact same issues that you describe in the post. As I was reading your explanation, it all started to make sense for the first time. Great work and thank you!

  5. 24.04.2008
    10:08

    adeem

    thats just bomb man, i was looking around and asking for zoom. but almost no one know this technique lol …. so thax u so much for such a great help :)

  6. 04.05.2008
    0:56

    p1ner0

    believe it or not, i was making a map with zoom and scale function, and reading this, wow, i have to quote:
    Fantastic post! This has cleared up a lot of my frustrations, as I’ve been struggling with the exact same issues that you describe in the post. As I was reading your explanation, it all started to make sense for the first time. Great work and thank you!

  7. 04.05.2008
    1:28

    p1ner0

    btw
    if you’re on a Mac where Flash Player is (still) missing mouse wheel support.
    solution:

    http://blog.pixelbreaker.com/flash/swfmacmousewheel/

  8. 08.05.2008
    15:52

    CoDeLab

    Awesome! I am working on a map tool, and this is exactly what I was looking for. Do you know if tweening can be introduced to this?

  9. 30.05.2008
    4:50

    Hello, tandem. — RTFM / Daniel Gasienica

    [...] Zooming in Flash & Flex [...]

  10. 14.07.2008
    20:16

    nuiman

    GREAT stuff :)

    This was big help for this: http://nuigroup.com/forums/viewthread/2125/

  11. 07.08.2008
    15:17

    deus

    but does it displays when you scale it over 8191 x 8191?

  12. 19.08.2008
    18:29

    Daniel Gasienica

    Deus,
    You’re right, there are limitations when dealing with large objects. Just today, I found this article which states that Flash Player 10 will raise the bar for it, though:

    Large bitmap support
    Flash Player 10 now provides the ability to manipulate larger bitmaps, up to 16,777,216 pixels (4,096 × 4,096) with a maximum length of 8,191 pixels per side.
    Justin Everett-Church (Adobe): Introducing Flash Player 10 beta

    Regards,
    Daniel

  13. 04.11.2008
    7:52

    Aldo Bucchi

    A little late to the party ;)

    Very nice blog! I am really enjoying your take on Deep Zoom.
    Anyway, for visitors reading this post: you might also be interested in the following, to keep on adding to this very nice explanation:

    http://blog.aldobucchi.com/2008/08/decomposing-regular-transformation.html

    Eigenvalue decomposition to the rescue… part of bigflexlib.com

  14. 08.11.2008
    19:53

    Daniel Gasienica

    Hello Aldo,
    Thanks for the link to the very interesting article on your blog.
    Cheers,
    Daniel

  15. 22.11.2008
    15:50

    Rajah

    Thanks bro, been looking for this technique for some time

  16. 08.01.2009
    23:34

    noj

    Its amazing how you can take the concept of 3×3 matrix for 2D graphics and 4×4 for 3D graphics.

  17. 15.07.2009
    5:48

    Steve

    I love you. You are the only normal person on the internets. This shit is HARD. Sure it’s easy, but if you dropped out of Maths at 15, like any normal person, its like beating yourself in the face with a shoe. I have been a relatively successful programmer for 11 years and this shit has always freaked me out, YOUR ARTICLE IS LIKE NAKED NIPPLY SUPER HAPPY TO ME!!1! I totally got that. First! Why cants I find any other resources like this, the rest of this place is rubbish. Going home now, you made someone in New Zealand pretty fucking happy and that happiness my friend will be translated into a good boning for the missus. You made 2 people happy! ! At least she says she likes it. Maybe just one, but thats one happy mother fucker! whoopwhoopwhopwhooop thanks bro!

  18. 15.07.2009
    10:36

    Daniel Gasienica

    Steve,
    You’ve made my day!
    Say hi to your missus from me. ;)
    If you have any other questions around this subject, please join our community at http://getsatisfaction.com/openzoom
    Yours,
    Daniel

  19. 17.09.2009
    19:56

    Taniguchi, J.T.

    HI Steve,

    I know that the topic its already old but I couldn’t just click the next link without saying thanks for the research!
    Although I like to crack my head up with complex code to create better and simple classes, it really makes me happy to know that AS3, Flash and Flex community are one of the best, less spam and friendly on the whole web (specially for AS3 noobs like me -__-).

    Again, thanks and keep up with the good work!

  20. 17.09.2009
    19:59

    Taniguchi, J.T.

    By the way, its HI DANIEL and not STEVE :( sorry :)
    cheers from Japan!

  21. 02.10.2009
    14:05

    Steffen

    Hi Daniel,

    First, it looks really great!!! This is exactly what i’ve been looking for!!

    Ive managed to put it into my document class so i can scale the whole stage. Unfortunately it wil only scale between two sizes?? And theres no really smooth effect as in your perfect example :D Any ideas on why thats so? Ive been looking for a good and useable zoom effect for three days now, so im really exited finally to come accross such a nice one!!

    Any help appreciated!

    Cheers

  22. 02.10.2009
    14:25

    Steffen

    No worries i got it figured out :D I simply forgot to address my_mc
    in the beginning of scaleAt like affineTransform = my_mc.transform.matrix.

    Again thanks for this!!!! When im finished with this never ending project, im gonna go all in with the Flex environment and openZoom!!!

    Have a great weekend!!

  23. 10.11.2009
    15:01

    NMHai

    Hi Daniel,

    I had some troubles of my homework, need to zoom all Sprites.
    I got your idea about transform.matrix and solved the problem.

    Thank you very much!

  24. 13.11.2009
    21:25

    Ken Colangelo

    Extremely helpful! Wonder if there’s any way to get the mouse wheel working when the map is in a non-full-screen Flash embed?

  25. 15.11.2009
    2:38

    Daniel Gasienica

    Ken,
    In this example, the mousewheel only doesn’t work on Mac OS. This is a known bug of the Flash Player for Mac. In order to make it work, check out the following topic in the OpenZoom community:
    http://getsatisfaction.com/openzoom/topics/using_externalmousewheel
    Cheers,
    Daniel

  26. 09.12.2009
    15:45

    Steffen

    Hi Daniel,

    Awesome blog and really helpfull!!

    Is there any way of tweening the transistions so the scaling will go a bit more smoothly? Ive tried for days with TweenLite , and cant seem to figure out how to pull this one off.

    Cheers!

  27. 10.12.2009
    19:34

    Jack Doyle

    For those asking about how to tween this type of effect, it is exactly what the transformAroundPoint plugin is for in TweenLite/Max – check out the interactive example in the Plugin Explorer at http://www.TweenLite.com (click “EXAMPLE” next to transformAroundPoint). One line of code is all you need. (note: the plugin is a membership benefit of Club GreenSock, so it isn’t included in the free downloads)

  28. 10.12.2009
    20:18

    Daniel Gasienica

    Steffen,
    If you’re already using TweenLite then Jack’s suggestion is the way to go. If not, simply omit the last step of applying the transform to the target object and tween it to the property values of the affineTransform.
    Let me know if this works for you.
    Cheers,
    Daniel

  29. 19.12.2009
    22:18

    skepsys

    plain superb ….thanx

  30. 22.12.2009
    10:37

    guillermo

    Really good post.
    Thanks a lot.

  31. 16.01.2010
    19:46

    ActionScript Scraps » Blog Archive » Zooming using transform Matrix

    [...] is a brilliant post ‘Zooming in Flash & Flex’ on how to use the transform Matrix to zoom and rotate DisplayObjects. Daniel Gasienica writes well [...]


What do you think?

Leave a Reply