14
Sep
07

Rotating images using the Matrix class

Somebody recently asked on a forum how you could rotate images using the Matrix class. I quickly built this super-simple little example which shows how to use the <mx:Rotate /> effect as well as the Matrix class’s rotate() method.

Full code after the jump.

If you’re new to transforms and matrices, check out Senocular.com’s excellent article, “Understanding the Transform Matrix in Flash 8“.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/14/rotating-images-using-the-matrix-class/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="horizontal"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:String id="deg">&#0176;</mx:String>

    <mx:Script>
        <![CDATA[
            import mx.core.UIComponent;

            private function img1_effectEnd():void {
                /* Set the appropriate Label text. */
                lbl1.text = "img1.rotation = " + img1.rotation.toString() + deg;
            }

            private function img2_creationComplete():void {
                /* "Copy" the existing matrix. */
                var m1:Matrix = img2.transform.matrix;
                /* Rotate the matrix 45 degrees (note that we have to
                   convert from degrees to radians since the rotate()
                   method expects radians. */
                m1.rotate(degreesToRadians(45));
                /* Concatenate the original matrix onto the rotated
                   matrix so we don't lose the original X and Y
                   coordinates and any other effects. */
                m1.concat(img2.transform.matrix);
                /* "Copy" the new matrix over the existing matrix. */
                img2.transform.matrix = m1;
                /* Set the appropriate Label text. */
                lbl2.text = "img2.rotation = " + img2.rotation.toString() + deg;
            }

            private function img_rollOver(cTarget:UIComponent):void {
                cTarget.toolTip = cTarget.name + ".rotation = " + cTarget.rotation.toString();
            }

            private function radiansToDegrees(radians:Number):Number {
                var degrees:Number = radians * (180 / Math.PI);
                return degrees;
            }

            private function degreesToRadians(degrees:Number):Number {
                var radians:Number = degrees * (Math.PI / 180);
                return radians;
            }
        ]]>
    </mx:Script>

    <mx:Rotate id="rotate" angleFrom="0" angleTo="45" duration="1" />

    <mx:ApplicationControlBar dock="true">
        <mx:Label id="lbl1" />
        <mx:Spacer width="50" />
        <mx:Label id="lbl2" />
    </mx:ApplicationControlBar>

    <mx:Image id="img1"
            source="http://www.helpexamples.com/flash/images/logo.png"
            creationCompleteEffect="{rotate}"
            effectEnd="img1_effectEnd();"
            rollOver="img_rollOver(UIComponent(event.currentTarget));" />

    <mx:Spacer width="50" />

    <mx:Image id="img2"
            source="http://www.helpexamples.com/flash/images/logo.png"
            creationComplete="img2_creationComplete();"
            rollOver="img_rollOver(UIComponent(event.currentTarget));" />

</mx:Application>

View source is enabled in the following example.

And just for giggles, here is a similar example which lets you rotate the image using a couple of Button controls. Note that the rotation is done around the center point of the image by calling the Matrix class’s translate() method to move the image before and after the rotation.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/14/rotating-images-using-the-matrix-class/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            private function button_click(evt:Event):void {
                var direction:int;
                switch (evt.currentTarget) {
                    case degreesUp:
                        direction = +1;
                        break;
                    case degreesDown:
                        direction = -1;
                        break;
                }

                var radians:Number = degreesToRadians(direction);
                var offsetWidth:Number = img.width / 2;
                var offsetHeight:Number = img.height / 2;
                var tempMatrix:Matrix = img.transform.matrix;
                tempMatrix.translate(-offsetWidth, -offsetHeight);
                tempMatrix.rotate(radians);
                tempMatrix.translate(+offsetWidth, +offsetHeight);

                img.transform.matrix = tempMatrix;

                rotateDeg = img.rotation;
            }

            private function radiansToDegrees(radians:Number):Number {
                var degrees:Number = radians * (180 / Math.PI);
                return degrees;
            }

            private function degreesToRadians(degrees:Number):Number {
                var radians:Number = degrees * (Math.PI / 180);
                return radians;
            }
        ]]>
    </mx:Script>

    <mx:Number id="rotateDeg">0</mx:Number>
    <mx:NumberFormatter id="numberFormatter" precision="0" />
    <mx:String id="deg">{String.fromCharCode(176)}</mx:String>

    <mx:ApplicationControlBar dock="true">
        <mx:Label text="rotation:" />
        <mx:Button id="degreesUp"
                label="+"
                autoRepeat="true"
                click="button_click(event);"
                buttonDown="button_click(event);" />
        <mx:Button id="degreesDown"
                label="-"
                autoRepeat="true"
                click="button_click(event);"
                buttonDown="button_click(event);" />
        <mx:Spacer width="50" />
        <mx:Label id="lbl"
                text="{numberFormatter.format(rotateDeg)}{deg}" />
    </mx:ApplicationControlBar>

    <mx:VBox>
        <mx:Image id="img"
                source="http://www.helpexamples.com/flash/images/logo.png" />
    </mx:VBox>

</mx:Application>

View source is enabled in the following example.


10 Responses to “Rotating images using the Matrix class”


  1. 1 Flanture Sep 14th, 2007 at 4:01 pm

    This line doesn’t work for me:
    °

    But this does:
    {String.fromCharCode(176)}

    Good example.

  2. 2 peterd Sep 14th, 2007 at 4:06 pm

    Flanture,

    Thanks, good catch! Another case of me forgetting to web-friendly the MXML code after posting it in the Interwebs.

    Example updated above and should hopefully work now. I’ll try and get View Source-able SWFs posted later this evening.

    Peter

  3. 3 Joe Corner Reeve Sep 20th, 2007 at 1:10 pm

    Hello I have Problem :(

    I want to leave this image on the position. an image will to rotate automacally.
    I see that mxml, why do you not use with ? I am ztying with problem of rotating image. :(

    Thanks Joe Corner Reeve

  4. 4 Ravindra Nath Chowdary Oct 30th, 2007 at 3:20 am

    This is fine

  5. 5 chas Nov 12th, 2007 at 1:52 pm

    beautiful! thank you, thank you, searched entire web for this and this is the only working example in all of googleland. thanks!

    c

  6. 6 Rob Cannon Dec 6th, 2007 at 2:37 pm

    If you examine the example carefully, it doesn’t rotate consistently around the exact center of the image. And then, if you go through an entire 360 degrees, the image position will be about 10 pixels or so below where it started.

    Using absolute positioning, try this function below instead. You have to pass the original x and y of the image control, don’t use the .x or .y properties since they change when the image is transformed.

    private function transformImage(img:Image, x:Number, y:Number, angle:Number):void {				
    
    	var offsetWidth:Number = img.contentWidth / 2 ;
    	var offsetHeight:Number = img.contentHeight / 2 ;
    
    	var sin=Math.sin(angle);
    	var cos=Math.cos(angle);
    
    	var tempMatrix:Matrix = new Matrix();
    
    	tempMatrix.a = cos;
    	tempMatrix.b = -sin;
    	tempMatrix.c = sin;
    	tempMatrix.d = cos;
    
    	tempMatrix.tx = x - cos * offsetWidth - sin * offsetHeight + offsetWidth;
    	tempMatrix.ty = y + sin * offsetWidth - cos * offsetHeight + offsetHeight;
    
    	img.transform.matrix = tempMatrix;
    
    }
    
  7. 7 Alexander Rose Dec 30th, 2007 at 5:02 pm

    Is it okay to use this on my own site? I’m happy to link back to you from my new site which I hope to have running by the end of January. Happy New Year to you, I hope it’s a good one!

  8. 8 Karl Garske Mar 2nd, 2008 at 3:10 pm

    Man, I got worked trying to integrate this into my own application. If the the Image is not the only thing included in the VBox, this example no longer behaves as advertised. Seems that the matrix is relative to whatever container the Image resides in, not the Image itself. Just making sure this is clear to others who are still new to this stuff.

  9. 9 Adam Apr 19th, 2008 at 12:37 am

    Can someone please explain to why the image needs to be in a VBox? This makes no sense to me.

  10. 10 Anonymous Aug 19th, 2008 at 2:51 am

    private function transformImage(img:Image, x:Number, y:Number, angle:Number):void {

    var offsetWidth:Number = img.contentWidth / 2 ;
    var offsetHeight:Number = img.contentHeight / 2 ;

    var sin=Math.sin(angle);
    var cos=Math.cos(angle);

    var tempMatrix:Matrix = new Matrix();

    tempMatrix.a = cos;
    tempMatrix.b = -sin;
    tempMatrix.c = sin;
    tempMatrix.d = cos;

    tempMatrix.tx = x - cos * offsetWidth - sin * offsetHeight + offsetWidth;
    tempMatrix.ty = y + sin * offsetWidth - cos * offsetHeight + offsetHeight;

    img.transform.matrix = tempMatrix;

Leave a Reply

This blog is terrible at eating HTML tags. If you plan on posting code/XML, please escape your "<" characters as "&lt;" and your ">" characters as "&gt;".