Rotating images using the Matrix class

by Peter deHaan on September 14, 2007

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.

{ 21 comments… read them below or add one }

Flanture September 14, 2007 at 4:01 pm

This line doesn’t work for me:
°

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

Good example.

Reply

peterd September 14, 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

Reply

Joe Corner Reeve September 20, 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

Reply

Ravindra Nath Chowdary October 30, 2007 at 3:20 am

This is fine

Reply

chas November 12, 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

Reply

Rob Cannon December 6, 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;

}

Reply

Alexander Rose December 30, 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!

Reply

Karl Garske March 2, 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.

Reply

Adam April 19, 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.

Reply

Anonymous August 19, 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;

Reply

Taniguchi Toshio, J. May 6, 2009 at 1:52 am

Im losing my head here…
I’m trying to adapt this sample using slider insted button but it just won’t work. My code:

<code>
private function rotateImage(evt:SliderEvent):void {
evt.preventDefault();
var tar:Slider = Slider(evt.currentTarget);

var direction:int;

direction = tar.value;

var radians:Number = degreesToRadians(direction);

var offsetWidth:Number = abc.width / 2;
var offsetHeight:Number = abc.height / 2;

var tempMatrix:Matrix = abc.transform.matrix;

tempMatrix.translate(-offsetWidth, -offsetHeight);
tempMatrix.rotate(radians);
tempMatrix.translate(+offsetWidth, +offsetHeight);

abc.transform.matrix = tempMatrix;

cmtTxt.text = “Rotating image…” + direction;
}
</code>

I have the radiansToDegrees and degreesToRadians functions. The thing is, when I use this code, the X, Y, scaleX and scaleY get all mess and the image jumps from one side to the other. By the way, image its inside a canvas and yes, I am accessing the image.

Thanks!

Reply

Taniguchi Toshio, J. May 6, 2009 at 2:40 am

Got a solution for my problem from Joel’s blog:
http://www.joelconnett.com/flex-rotation-around-a-point-using-a-matrix.html

Works like a charm!

Thanks :)

Reply

Sundance June 1, 2009 at 10:52 pm

i have a problem with big images, when i rotate the image this get over other components like application control bar, there’s some way to resolve this issue? Cheers

Reply

sundarapandian November 24, 2009 at 12:58 am

I too have this issue .. have u got solution for this?.. if any body has solution for this please share with me..

Reply

RazFlex June 9, 2009 at 6:17 am

What if y want a Y ax rotation ?
What the matrix will be ?
Regards

Reply

Anton June 13, 2009 at 2:00 pm

Aren’t there any developers out there who know how to spell and use good grammar? What is with you people?

Reply

Andrea November 10, 2009 at 5:24 am

Many of us are from non-english-speaking countries (and I’m not even sure what last sentence is correct…). Anyway… the thing is, nowadays, English is the unviversal language, and web try to adjust to it as good as we can, but it’s not easy, specially when the conversation is about technologies. Not my case, but there are a lot of fully qualified Flex developer in India, for example.
I don’t think that’s something to be sorry for… good grammar or bad grammar, the important thing is to give something back to the community that always helps us.

Reply

susrut316 October 28, 2009 at 10:17 am

I have created a fully functional transform tool or object handler in as3 with the help of the matrix transform. Have a look http://talkxe.com/?p=63

Reply

Daniel December 18, 2009 at 4:27 pm

Here is the code you need to rotate the item when it is not at the origin. The inverted matrix is to get to the local coordinates of the item, the offsets are to rotate around the middle, and then the items initial transform is concatenated to get back to the global coordinates. I wasn’t totally brushed up on my linear algebra and it sounds like this can save everyone some time.

The radians variable is the change in rotation to apply.

var offsetWidth:Number = item.width / 2;
var offsetHeight:Number = item.height / 2;
 
var invertedMatrix:Matrix = item.transform.matrix;
invertedMatrix.invert();
 
var matrix:Matrix = item.transform.matrix;
matrix.concat(invertedMatrix);
matrix.translate(-offsetWidth, -offsetHeight);
matrix.rotate(radians);
matrix.translate(offsetWidth, offsetHeight);
matrix.concat(item.transform.matrix);
 
item.transform.matrix = matrix;

Reply

mihai January 23, 2010 at 7:17 am

And how can I scale Image from center after I rotated it?

Reply

Circass August 10, 2010 at 10:46 pm

Hello,
i am trying to rotate my image which is a child of my view panel.
I wrote something like that :

var rotate:mx.effects.Rotate = new mx.effects.Rotate();
//var iTmp:Image = new Image();
//iTmp = viewerPanel.getChildAt(0) as Image;
rotate.target= viewerPanel.getChildAt(0);
rotate.angleFrom=viewerPanel.getChildAt(0).rotation;
rotate.angleTo=viewerPanel.getChildAt(0).rotation – 90;
rotate.duration=1000;
rotate.originX=viewerPanel.getChildAt(0).width/2;
rotate.originY=viewerPanel.getChildAt(0).height/2;
rotate.play();

it rotates the panel from top left.

then i wrote something like that :
var iTmp:Image = new Image();
iTmp = viewerPanel.getChildAt(0) as Image;
var q:Number = 90 * Math.PI / 180 // 30 degrees in radians
var m:Matrix = new Matrix();
var centerX:Number = iTmp.width / 2;
var centerY:Number = iTmp.height /2;
m.translate(-1 * centerX, -1 * centerY);
m.rotate(q);
viewerPanel.removeChildAt(0);
viewerPanel.addChild(iTmp);
and this made the same thing.

So How can i rotate an image which is added to a panel as a child ?
Thank you.

Reply

Leave a Comment

Sorry, this blog is terrible at eating HTML comments.
If you're pasting any HTML/XML/MXML code, you need to convert your < characters to &lt; and your > characters to &gt; .

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: