To download the code, you must agree to the following license:

Copyright 2010, GreenSock, Inc.

"NO CHARGE" NON-EXCLUSIVE SOFTWARE LICENSE AGREEMENT
-----------------------------------------------------------------------------
PLAIN ENGLISH SUMMARY:

  1. You may use the code at no charge in commercial or non-commercial web sites, games, components, applications, and other software as long as end users are not charged a fee of any kind to use your product or gain access to any part of it. If your client pays you a one-time fee to create the site/product, that's perfectly fine and qualifies under the "no charge" license. If end users are charged a usage/access/license fee, please sign up for a corporate Club GreenSock membership which comes with a special commercial license granting you permission to do so. See http://www.greensock.com/club/ for details.
  2. Use at your own risk. No warranties are offered.
  3. Please respect the copyright.

-----------------------------------------------------------------------------

LEGALESE:

This is a legal agreement between you (either an individual or a single entity) and GreenSock, Inc. ("GREENSOCK") for the proprietary GreenSock ActionScript code known as TweenLite, TweenMax, TweenNano, TimelineLite, TimelineMax, and other code that is available for download at http://www.greensock.com (this code and documentation, as well as any updates which may at GREENSOCK's sole discretion be provided to you from time to time, are referred to in this Agreement as "PROGRAM") By downloading, copying, or otherwise using the PROGRAM, you agree to the terms and conditions of this Agreement. If you do not agree to the terms and conditions of this Agreement, please do not download or use the PROGRAM.

I. LICENSE
A. Subject to the terms and conditions of this Agreement, GREENSOCK hereby grants you a non-exclusive, worldwide, non-transferable right to use the PROGRAM in web sites, games, components and other software applications for which the end user is NOT charged any fees. If you would like to use the code in a commercially licensed software product for which end users are charged a fee (either for usage or access), simply sign up for a corporate Club GreenSock membership at http://www.greensock.com/club/.

II. LIMITATION OF LICENSE AND RESTRICTIONS
A. You agree that you will not disclose, sell, rent, or license the PROGRAM's source code or any derivative works thereof to any third party without the prior written consent of GREENSOCK. Derivative works are defined as modifications that add substantive functionality to the PROGRAM and do not include bug fixes or other minor modifications required to operate the PROGRAM as originally intended. Distribution of the source code as part of your Work Product is acceptable so long as the recipients agree to the terms of this Agreement. You agree not to modify or delete GREENSOCK'S existing copyright notice located in the source code.

B. You may use, duplicate, and distribute the compiled object code as embedded in a Work Product created by you, either for your own use or for distribution to a third party so long as end users of the Work Product are not charged a fee for usage of or access to any portion of the Work Product. Please see http://www.greensock.com/licensing/ for descriptions of Work Products that qualify for the "No Charge" license.

III. CONSIDERATION
A. The license rights granted to you under this Agreement are at no charge, but only in the following circumstances: If on your own behalf or on behalf of a third party you incorporate the PROGRAM into a web site, game, software application, program or any component thereof (collectively, "Work Product"), which in the case of a web site, must be accessible to internet users without payment of a fee of any kind, and in the case of a software application, game, program or component, neither you nor anyone to whom you distribute the Work Product charges a user a fee of any kind to use such Work Product or application, game, program or component into which such Work Product is embedded. The foregoing shall apply regardless of whether you are paid to create such Work Product.

B. In the event your intended use of the PROGRAM does not meet the criteria for the "no charge" license rights set forth in the immediately preceding paragraph, then you are not licensed to use the PROGRAM under this Agreement and must license the PROGRAM under GREENSOCK'S separate fee-based Software License Agreement which is granted to corporate Club GreenSock members (see http://www.greensock.com/club/ for details).

IV. TITLE AND OWNERSHIP
A. The PROGRAM is licensed, not sold, and is protected by copyright laws and international treaty provisions. You acknowledge that no title to the intellectual property in the PROGRAM is transferred to you. You further acknowledge that title and full ownership rights to the PROGRAM, including all intellectual property rights therein, will remain the exclusive property of GREENSOCK and you will not acquire any rights to the PROGRAM except as expressly set forth in this Agreement. You agree that any copies of the PROGRAM you make will contain the same proprietary notices which appear on and in the PROGRAM. You agree that GREENSOCK may identify you as a licensee unless you make a written request otherwise. GREENSOCK hereby grants to you the right to disclose that your product, game, software application, component, or other Work Product makes use of GREENSOCK code (for example, "Powered by TweenLite").

V. DISCLAIMER OF WARRANTY AND LIMITATION OF LIABILITY
A. THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. GREENSOCK DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE PROGRAM WILL MEET YOUR REQUIREMENTS OR THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. GREENSOCK shall not be liable for special, indirect, incidental, or consequential damages with respect to any claim on account of or arising from this Agreement or use of the PROGRAM, even if GREENSOCK has been or is hereafter advised of the possibility of such damages. Because some states do not allow certain exclusions or limitations on implied warranties or of liability for consequential or incidental damages, the above exclusions may not apply to you. In no event, however, will GREENSOCK be liable to you, under any theory of recovery, in an amount in excess of $250. Notwithstanding anything else in this agreement, you agree to indemnify GREENSOCK, its assignees, and licensees, and hold each of them harmless from and against any and all claims, demands, losses, damages, liabilities, costs, and expenses, including legal fees resulting from your use of the PROGRAM.

B. GREENSOCK may, at its sole discretion, provide support services related to the PROGRAM, but has no obligation to do so.

VI. TERMINATION
If you at any time fail to abide by the terms of this Agreement, GREENSOCK shall have the right to immediately terminate the license granted herein, require the return or destruction of all copies of the PROGRAM from you and certification in writing as to such return or destruction, and pursue any other legal or equitable remedies available.

VII. MISCELLANEOUS
A. This Agreement shall be construed in accordance with the laws of the State of Illinois. In the event of any dispute between you and GREENSOCK with respect to this Agreement, we both agree that if we cannot resolve the dispute in good faith discussion, either of us may submit the dispute for resolution to arbitration with the American Arbitration Association before a single arbitrator using the AAA Rules for Commercial Arbitration. The arbitrator's decision is final and can be enforced in any court with jurisdiction over such matters.

B. This agreement represents the complete and exclusive statement of the agreement between GREENSOCK and you and supersedes all prior agreements, proposals, representations and other communications, verbal or written, between them with respect to use of the program. This agreement may be modified only with the mutual written approval of authorized representatives of the parties.

C. The terms and conditions of this Agreement shall prevail notwithstanding any different, conflicting, or additional terms or conditions which may appear in any purchase order or other document submitted by you. You agree that such additional or inconsistent terms are deemed rejected by GREENSOCK.

D. GREENSOCK and you agree that any xerographically or electronically reproduced copy of this Agreement shall have the same legal force and effect as any copy bearing original signatures of the parties.

I'd like to learn how to get bonus plugins, update notifications, SVN access, and more.
To join Club GreenSock, you must agree to the following license:

TransformManager (AS2) – Scale/Rotate/Move any MovieClip

  • Version: 5.6, Updated 1/7/2008
  • Compatibility: Flash Player 6 and later (AS2) (NEW AS3 version available now)
  • File size added to compressed SWF: about 11k

Download Now
 
Donate

Need an AS3 version? I have completely rebuilt TransformManager in AS3 with lots of new features.

COMING SOON: I have ported all the bells & whistles of the AS3 version (multiple selections, extra handles, better cursors, much better code-based control, arrow key functionality, etc.) back to AS2 (Flash Player 8 or later required) and plan to offer it for sale soon. Let me know if you'd like to get an advanced copy.

Description

This class gives the user the ability to scale, rotate, and/or move any MovieClip on the stage using an intuitive interface (similar to most modern drawing applications). When the user clicks on the TransformItem's MovieClip, a selection box will be drawn around it along with four handles for scaling. When the user places their mouse just outside of any of the scaling handles, the cursor will change to indicate that they're in rotation mode. Hold down shift to constrain scaling proportions or to limit rotation to 45 degree increments. This TransformManager class will handle multiple TransformItem instances, switching the selection boxes (so that only one is selected at a time) as well as updating the properties with a single call. See the TransformItem class for more details about features.

The new AS3 version adds a slew of new features including multiple item selection, extra handles, etc. If you want some of those features ported to an AS2 version (Flash 8 only), I'm available for hire to do that.

The first (and only) parameter in the constructor accepts an object with any number of properties. This makes it easier to set only the properties that shouldn't use their default values (you'll probably find that most of the time the default values work well for you). It also makes the code easier to read.

Other links: AS3 version | Forums

Features

  • Scale, rotate, or move any MovieClip (or TextField)
  • The cursor will automatically change to indicate scaling or rotation mode (roll your mouse close to the handles to see)
  • You do NOT need to make sure that each MovieClip's registration point is centered!
  • You can lock the scale, rotation, or position of any MovieClip
  • Constrain items to coordinates you define (using the "bounds" property - an object with xMax, xMin, yMax, and yMin properties)
  • Force the selection to come to the front (in the stacking order) by setting the forceSelectionToFront property to true
  • Constrain scaling to be proportional by either holding down the shift key when scaling or set the constrainScale property
  • Constrain rotation to go in increments of 45 degrees by holding down the shift key when rotating.
  • As of version 5.1, it uses the same method of event handling as the new AS3 model (addEventListener("select", myFunction), etc.).
  • You can allow the class to delete MovieClips when the user hits the delete key and a TransformItem is selected by setting the allowDelete argument to true.
  • You can control the size and color of the handles and selection box and even the padding area that triggers the rotation tool. Simply change the lineColor, handleSize, handleFillColor, or paddingForRotation properties.
  • You can enable or disable the entire TransformManager or an individual TransformItem by setting the "enabled" property to true or false.
  • Manually select a MovieClip or TextField using the static TransformItem.selectTargetObject(myClip_mc) method.
  • You can deselect everything by calling the static TransformItem.deselectAll() method.

Important properties

  • constrainScale : Boolean [default:false]
  • scaleFromCenter : Boolean [default:false]
  • lockScale : Boolean [default:false]
  • lockRotation : Boolean [default:false]
  • lockPosition : Boolean [default:false]
  • autoDeselect : Boolean [default:true]
  • allowDelete : Boolean [default:false]
  • eventHandler : Function
  • lineColor : Number [default:0x3399FF]
  • handleSize : Number [default:8]
  • handleFillColor : Number [default:0xFFFFFF]
  • paddingForRotation : Number [default:10]
  • enabled : Boolean [default:true]
  • forceSelectionToFront : Boolean [default:false]
  • bounds : Object (an object with xMax, xMin, yMax, and yMin properties)
  • selectedTargetObject : Object (MovieClip or TextField that the TransformManager currently has selected) (read-only)
  • selectedItem : TransformItem or TransformItemTF (read-only)

Important methods

  • addItem()
  • addItems()
  • select() //You can pass a reference to the MovieClip, TextField, or its associated TransformItem or TransformItemTF.
  • deselect()
  • reset()
  • getItemFromTargetObject()
  • destroy()

Important events

  • select
  • deselect
  • delete
  • clickOff (only called when the autoDeselect is false, otherwise the "deselect" event is called)
  • deleteKeyDown (only called when allowDelete is false, otherwise the "delete" event is called)
  • scale
  • rotate
  • move

Events return an object with the following properties:

  • target : TransformManager
  • targetObject : Object (MovieClip or TextField)
  • action : String (one of the following: "select", "deselect", "delete", "clickOff", "deleteKeyDown", "scale", "rotate", "move")
  • manager : TransformManager (if one exists that's associated with this TransformItem)
  • transformed : Boolean (if it was scaled, moved, or rotated, this is true. Otherwise it's false)
  • item : TransformItem (or TransformItemTF if it's a TextField)

Usage

addItem(target:Object, variables:Object);
  • Description:Adds a MovieClip or TextField to the TransformManager so that it can control (transform) it.
  • Parameters:
    1. target: Target MovieClip or TextField
    2. variables: (optional) An object containing the properties you'd like to set. See the list of "KEY PROPERTIES" above for options.
addItems(targets:Array, variables:Object);
  • Description: Same as addItem() except that you can pass an array of MovieClips (or TextFields) that you'd like to add at one time which uses less code.
  • Parameters:
    1. targets: An array with references to the target MovieClips or TextFields that you'd like to be able to transform.
    2. variables: (optional) Same as addItem() (see above).
select(target:Object);
  • Description: To select a particular MovieClip or TextField that you've already added to the TransformManager, just use this method.
  • Parameters:
    1. target: The MovieClip or TextField that you'd like to select.
deselect();
  • Description: Deselects all items that this particular TransformManager controls.
reset();
  • Description: Resets the _x, _y, _xscale, _yscale, and _rotation properties of all MovieClips and TextFields that the TransformManager controls back to their original values.
getItemFromTargetObject(target:Object);
  • Description: Returns the TransformItem (or TransformItemTF for TextFields) associated with a particular MovieClip (or TextField). This is useful for when you wan to call methods on a particular TransformItem, like updating its display/selection after you've manually changed its properties (like manager_obj.getItemFromTargetObject(my_mc).update()).
  • Parameters:
    1. target: The MovieClip (or TextField) that's associated with the TransformItem (or TransformItemTF).
removeItem(item:TransformItem):Void
  • Description: To remove a TransformItem, pass its reference to this function. Remember, the item refers to a TransformItem, NOT a MovieClip. If you need to find the corresponding TransformItem for a given MovieClip, just use the getItemFromTargetObject() method, like myManager.removeItem(getItemFromTargetObject(my_mc)); Keep in mind that removing an item doesn't delete the MovieClip/TextField - it just stops it from being controlled by the TransformManager so it's not selectable/scalable/rotatable/movable.
  • Parameters:
    1. item: The TransformItem (or TransformItemTF) that you'd like to remove.

EXAMPLES

To make two MovieClips transformable (with default settings):

Actionscript:
  1. import gs.TransformManager;
  2. var transformManager_obj = new TransformManager({transformObjects:[myClip1_mc, myClip2_mc]});

To make two MovieClips transformable, constrain their scaling to be proportional (even if the user is not holding down the shift key), call the onTransformEvent function on every event (when one of the MovieClips has been selected, scaled, moved, rotated, deselected, deleted, etc.), lock the rotation value of each MovieClip (preventing rotation), and allow the delete key to actually delete the selected MovieClip, do:

Actionscript:
  1. import gs.TransformManager;
  2. var transformManager_obj = new TransformManager({transformObjects:[myClip1_mc, myClip2_mc], eventHandler:onAnyEvent, constrainScale:true, lockRotation:true, allowDelete:true, autoDeselect:true});
  3. function onAnyEvent(event_obj:Object):Void {
  4.     trace("Action: "+event_obj.action+", MovieClip or TextField: "+event_obj.targetObject+", transformed?: "+event_obj.transformed);
  5. }

FAQ

  • I'm loading an image dynamically, but it won't seem to work with TransformManager - why not? I get this question a lot. The problem is that you're not giving Flash time enough to fully instantiate the dynamically loaded image/SWF. In order for TransformManager to work, it must be able to accurately measure the _width and _height properties, but those values aren't available until a few milliseconds after the image loads. I'd recommend either using the onLoadInit() of the MovieClipLoader or set a delayed call to a function that adds your dynamically loaded image/SWF to the TransformManager.
  • I'd like multiple selections and all the other features that you added to the AS3 version - how can I get it? I plan to being selling an AS2 version with virtually all of the features of the AS3 version including multiple selections, more handles, etc. e-mail me if you'd like more information.

Need help?

Feel free to post your question on the forums. You'll increase your chances of getting a prompt answer if you provide a brief explanation and include a simplified FLA file (and any class files) that clearly demonstrates the problem.

Donate
Author: Jack Doyle
Copyright 2009, GreenSock (This work is subject to the terms here.)

Comments (66) RSS

Posted by Carvel on February 8, 2007

Jack,

Wow! What great work you’ve done here! Thanks so much for this class. One thing though. Allow delete doesn’t seem to be working. I have the following but when I press the key nothing happens:

// need to move to front when transformed
import mx.behaviors.DepthControl.*;
import gs.TransformManager;

var manager_obj = new TransformManager([test], onTransformEvent, true, false, false, true, false, true, true);
function onTransformEvent(event_obj:MovieClip):Void {
mx.behaviors.DepthControl.bringToFront(this.mc);
}

Posted by Scott on February 16, 2007

This is terrific! I’ve been searching and searching trying to figure out how to possibly allow scaling of images but remain constrained.

I may try to impliment a variation on my site but because it would pertain to users customizing a product do you know of a way to see what the customer actually did. Say they resize the image and move some text to particluar spot. I’m not sure how I might see their ‘finished’ product so I can impliment it. If you have any suggestions on that front that would be great. I don’t necessarily have to allow dragging but might want to for an eventual product offering.

Again, this is really cool!

-Scott

Posted by jack on February 16, 2007

Scott, if I understand your question correctly, it should be pretty easy to capture what the customer did. Keep in mind that the eventHandler_func function gets called every time the user selects/scales/rotates/moves/deletes/deselects a TransformItem, so you can use that to trigger a save routine which records the MovieClip’s new properties (_x, _y, _xscale, _yscale, _rotation, etc.). Or maybe you just have a “save” button on the screen that loops through the MovieClips and records their properties. In fact, the application that I built this for does exactly that – I had to allow users to interact with MovieClips on the stage, rearrange them, and then save the new layout. Worked like a charm.

Posted by Carvel on February 22, 2007

Jack,

I was thinking about using this as a tool for detailed image cropping. For an example, allow someone to upload their picture and then let them drop a circular movieclip onto the stage and freeform crop it around their face. Then save it. Would be really cool to be able to add more cropping handles.

Any thoughts on that?

Carvel

Posted by James on March 7, 2007

I’m having trouble figuring out how to detect when the user deletes an item (which I have working now). I want to call a function I wrote when they hit the delete key. I’m not sure how to write this at all. Can you help?

Posted by jack on March 7, 2007

If you’d like to detect when the user deletes an item, you can just do something like:

function onTransformEvent(event_obj:Object):Void {
  if (event_obj.action_str == “delete”) {
    //YOUR CODE HERE
  }
}

And then make sure the eventHandler_func property of your TransformManager or TransformItem points to that function by either setting that property directly or passing it into the constructor, like so:

var myTransformManager_obj = new TransformManager([my_mc], onTransformEvent);

Remember, that function will get called every time an item gets selected, deselected, transformed, or deleted. The action_str property of the event_obj that gets passed every time will tell you exactly what action was taken.

Posted by jack on March 8, 2007

I’ve been getting a lot of people commenting about the delete function not working, but the reason they think it’s not working is because they’re only trying it in the authoring test environment (after hitting CTRL-ENTER when working in their FLA) and they haven’t selected the “Disable Keyboard Shortcuts” under the Control menu. Doing so would prevent Flash from intercepting the key press. If/when they tested it in the browser or in a projector or anywhere outside of the test environment, it was working fine for them. So please remember to select “Disable Keyboard Shortcuts” under the “Control” menu when you’re looking at your test movie inside Flash!

Posted by James on March 11, 2007

I have the delete working now but how can I know which one they just deleted? It doesn’t appear to be returning the “event_obj.target_mc” like the ’select’ does.

Posted by jack on March 12, 2007

I’ve been asked by a few people how to find which MovieClip has been deleted. It would be pointless to pass a target_mc to the eventHandler_func when you delete a MovieClip because, well, it’s deleted so the reference would point to nothing. You could handle it in a few different ways. Here are a couple of ideas of the top of my head:

You could just keep track of what element is currently selected at any given time and then when a delete event is fired, you know it must have been the last thing selected. Kinda like this:

import gs.TransformManager;
var startingMC_array = [test_mc, test2_mc, test3_mc];
var manager_obj = new TransformManager({targetObjects:startingMC_array, eventHandler:onTransformEvent});
var curSelected_mc = null;
function onTransformEvent(event_obj:Object):Void {
if (event_obj.action == “select”) {
curSelected_mc = event_obj.targetObject;
}
if (event_obj.action == “delete”) {
trace(“we must have just deleted “+curSelected_mc);
}
}

You could also keep your own array of MovieClips that you dump into the TransformManager. Then, when one gets deleted, you can grab the TransformManager’s mc_array and compare it to your’s to see which one is now missing after the deletion. Here’s some brief code you might use for something like that:

import gs.TransformManager;
var startingMC_array = [test_mc, test2_mc, test3_mc];
var manager_obj = new TransformManager({targetObjects:startingMC_array, eventHandler:onTransformEvent});
function onTransformEvent(event_obj:Object):Void {
if (event_obj.action == “delete”) {
var mc_array = manager_obj.targetObjects;
for (var i = 0; i < startingMC_array.length; i++) {
var found_boolean = false;
for (var n = 0; n < mc_array.length; n++) {
if (startingMC_array[i] == mc_array[n]) {
found_boolean = true;
break;
}
}
if (!found_boolean) {
trace(“we must have just deleted index number “+i+” which referenced: “+startingMC_array[i]);
}
}
}
}

Please note that I just added the targetObjects property to the TransformManager class, so make sure you download version 5.1 or later.

In either case, it’s actually going to reference nothing since the MovieClip has been deleted, but I hope this code provides you with some ideas for how to accomplish what you need.

Posted by Christian on March 14, 2007

I was hoping I could replace one of the movieclips with a simple:

loadMovie(“image.jpg”, test_mc);

Although the movieclip is now untransformable, any help on why this would be the case and possibly a work around.

Posted by jack on March 15, 2007

The reason your newly loaded MovieClip isn’t transformable has to do with the fact that when you do a loadMovie() call, Flash dumps everything about the old MovieClip and replaces it with the new one, so the “hooks” that the TransformManager had into the old clip are broken. I’d suggest simply doing something like:

var oldItem_obj = myTransformManager_obj.getItemFromMC(myClip_mc);
myTransformManager_obj.removeItem(oldItem_obj);
loadMovie(“image.jpg”, myClip_mc);
//Do some kind of preloader that senses when it has finished loading and triggers the onFinishedLoading() function below:
function onFinishedLoading():Void {
    myTransformManager_obj.addItem(myClip_mc);
}

Just make sure you wait until the clip has finished loading so that the TransformManager can sense the _width and _height and _x and _y properties, etc. So essentially you’re just removing it from the TransformManager, then loading your clip, then adding it back to the TransformManager. You can select it immediately if you want after it loads by calling myTransformManger_obj.select(myClip_mc);

Hope this helps.

Posted by Gavin on March 15, 2007

Niiiiice tool. I’m planning to use it as part of an image cropping control (non-commercial), but one thing has me stuck.

Is there any way to get the width and height of a clip independent of the rotation? When I access a clip’s _width or _height properties, I get the effective dimensions after the rotation, in an absolute way.

Is it possible to get these properties in a relative way?

Posted by jack on March 15, 2007

Gavin, the TransformItem class now has width and height properties that do exactly what you’re asking about. So if you’re working with a TransformManager instance and want to find out what the width of the currently selected MovieClip is, you can do:

var width = myTransformManager_obj.selectedItem.width;

Posted by DenisPat on May 25, 2007

Thanks for the class, exemple and time.
I’ve learned alot from your code and greatly appreciate how you have donated so generously.
I’m using it with the bitmapData object to make a rotate, scale, crop and ‘add text’ image editor.

I greatly appreciate it.

Posted by siva on June 12, 2007

hi,

just got to look into latest. wow it’s got the same functionality i had previously searched for and during that time i made it hard coded the bounds property.

one bug is for text control. if we rotate the text the text field becomes transparent.

Posted by jack on June 12, 2007

Actually, siva, the text disappearing isn’t a bug – there’s a big warning in the documentation at the top of the class file – Flash won’t render any TextField that’s rotated UNLESS you embed the fonts. My bet is that your TextField doesn’t have embedded fonts. As soon as you embed them, I’m confident it’ll work perfectly for you. If you’re going to use a TextField without embedded fonts, I’d recommend setting the lockRotation property to true in order to avoid any confusion.

Posted by Nishanthe on June 26, 2007

Hello Jack,
Thank you 1000000000000000000000000000000000 times for saving my days. I was searching for transform manager for last few days and no help. Specially I wanted to know how to constrain a transforming MC within a defined area. But With your class that can be done like a charm. :)
I am going to use this with http://www.rockstargeodesigner.com .. :)
Thank you again
-Nish

Posted by Sam on July 26, 2007

Hey Jack

This TransformManager is excellent, I’ve tried a couple of different classes and this is by far the best that I have come across. It’s allowing me to do more than I actually wanted to, which is now giving me more flexibility in my application. Thank you for allowing us to use this freely, very much appreciated.

Sam

Posted by JV on August 2, 2007

“Or maybe you just have a “save” button on the screen that loops through the MovieClips and records their properties. In fact, the application that I built this for does exactly that – I had to allow users to interact with MovieClips on the stage, rearrange them, and then save the new layout. Worked like a charm.”

Hey Jack,

Do you have any hints on how to do this?

Great work!

Posted by jack on August 2, 2007

JV, if you’re asking me how to loop through the TransformManager’s MovieClips and get their properties, it’d be something like (not tested):

import gs.TransformManager;
var myManager_obj = new TransformManager({targetObjects:[myClip1_mc, myClip2_mc]});

function getNewValues():Void {
var clips_array = myManager_obj.targetObjects;
var mc:MovieClip;
for (var i = 0; i < clips_array.length; i++) {
mc = clips_array[i];
trace(“New values for ” + mc + “: _x:” + mc._x + “, _y:” + mc._y + “, _xscale:” + mc._xscale + “, _yscale:” + mc._yscale + “, _rotation:” + mc._rotation);
}
}

And then you’d just have your button call the getNewValues() function and save them wherever you want (I just traced them out so you can see them in the above function).

Hope that helps.

Posted by Luis Vilanova on August 11, 2007

Luis from São Paulo, Brasil, a novice in Actionscript. Thanks for your help, Jack.

I want to capture the name of the mc clicked by the user. I tried inserting
on(release){
_global.mc_clicked=this._name;
trace(mc_clicked);
}
directly in the movieclips.

But it seems that TransformManager “deafen” events on objects “TransformManagered”. No answer.

But suddenly something astonishment ocurred! After one week making a lot of trials, I constructed a set of movieclips and the code above worked perfectly on them.

An they are identical to the others mcs! But now I can’t reproduce the “good way”.

May you help me?

Posted by jack on August 14, 2007

Yes, Luis, in order to make the MovieClips clickable/draggable, my class must “hijack” the onPress and onRelease handlers, so if you set your own and then apply my TransformManager, it’ll overwrite them (until you set the enabled property to false). But it’s really easy to do what you’re trying to accomplish. Do something like:

var manager_obj = new TransformManager({targetObjects:[test_mc, test2_mc]});
manager_obj.addEventListener(“select”, onSelectItem);
function onSelectItem(event_obj:Object):Void {
trace(“selected MovieClip named: “+event_obj.item.targetObject._name);
}

Posted by Jesse Ross on August 27, 2007

First, thanks Jack for this amazing code!

My situation is this: I’m trying to use these scripts in conjunction with the Sepy ColorPicker. However, when I click to use the colorpicker, it recognizes the click as a deselect, so I lose focus on the transformable item I wanted to change the color of. Is it possible to tell the deselect to not really perform a deselect by ignoring clicks on certain movieclips? Thanks in advance for any pointers.

Posted by jack on August 27, 2007

Jesse, yes, there is definitely a solution to your problem. In fact, I had to do almost exactly the same thing on a project I worked on. Simply set the autoDeselect property to false (it’s true by default). Then in order to sense when the user clicks off of the item (like when they’re clicking on your color picker), set up a listener for the “clickOff” event. In your event handler, you can test to see if the user is clicking on the ColorPicker – if so, do nothing (keep it selected), if not, deselect it by calling the deselect() method.

Posted by Govan on September 8, 2007

This is EXACTLY what I’ve been looking for. I’m glad I stayed up late tonight :-) Will let you know when I have put it to good use. Thanks a great deal.

Posted by snowboardfoo on September 18, 2007

Great work with this class, it’s very useful, and it’s awesome that you are giving it to the community to use and learn from.

I do have one question…

If the object that you are transforming is in a container mc that is dynamic masked (and so the selection outline and handles disappear under the mask as well), is there a way to keep the _selection_mc from being masked too?

I tried modding some lines in TrandormItem.as..

findNextHighestDepth(_selection_mc._parent)

(changed to) findNextHighestDepth(_root),

and also changing _selection_mc = _targetObject._parent.createEmptyMovieClip(“selection”+l+”_mc”, l);

(changed to) _selection_mc = _root.createEmptyMovieClip(“selection”+l+”_mc”, l);

.. which did work to place selection_mc above the transform object and container movieclip that is masked, but now the selection_mc is created at _root coordinates 0,0 as it is no longer default to 0,0 in the same object..

Is there a better way to do this, or a way to mod it to account for the x and y offset…? Or are the x.y coords being set again somewhere else preventing me from setting them with _selection_mc._x = _targetObject._x; _selection_mc._y = _targetObject._y; in the initHandles() function?

..Or is this class designed around nesting the selection_mc in the target mc’s _parent and not really mod-able like this?

Thanks a million, love your code.

Posted by snowboardfoo on September 19, 2007

AS per my last q post…

I realized that what I have to do is set the selection MC X/Y coord’s to the not just the target X/Y, but that PLUS the container mc’s X/Y…

After the last modifications and going through and accounting for the parent’s X/Y offset everywhere there is a reference to the target MC’s position, it works great! It just goes to show how dynamic and flexible this well-formed code you’ve created can be.

Thanks again for this class, I will link you the site when it is done, and also donate something as well to encourage you to keep developing with such generosity.

Awesome!

Posted by Binay on September 21, 2007

Great flash tool

Can you help me on this?

I have a large MovieClip_A and inside it another smaller MovieClip_B
(Circle MC inside rectangle MC)

I want to make both movieclips transform using your component.

manager_obj.addItem(MovieClip_A);
manager_obj.addItem(MovieClip_B);

But only MovieClip_A will transform but not MovieClip_B

Posted by jack on September 21, 2007

Binay, there are actually two problems with the idea of nested MovieClips being transformable:

1) Since the user needs to be able to simply click on a MovieClip to select it, how would Flash know when the user wanted to transform the subclip instead of the parent clip since technically clicking on the subclip IS clicking on the parent clip? Keep in mind that TransformManager applies onPress and onRelease handlers to each item and a parent’s handlers will override its subclip’s handlers in this case. That’s a Flash thing, not a TransformManager thing.

2) All of the items in each TransformManager instance must share the same _parent MovieClip. No nesting is allowed. You can, however, create new TransformManager instances for multiple MovieClips – just stay away from nesting, that’s all.

Posted by Binay on September 24, 2007

Hi Jack,

Any way i managed to transform both parent and child movieclip.

Parent MC: parent_MC
child MC: child_MC , circle_MC

parent_MC contains rectangular shaped child_MC and circular shaped circle_MC

If child_MC is selcted then remove child_MC from manager_obj and add parent_MC in manager_obj this will transfrom the parent_MC (i.e when we resize and rotate parent_MC, child_MC and circle_MC also gets transformed)

Now on delselect event remove parent_MC and add child_MC

While parent_MC is selected, if we want to select circle_MC which is child movie child of parent_MC, we have to deselect parent_MC first(i.e click outside parent_MC and then click on circle_MC)

Here is the code

var manager_obj = new TransformManager({forceSelectionToFront:false, allowDelete:true});
manager_obj.addItem(parent_MC.circle_MC);
manager_obj.addItem(parent_MC.child_MC);
manager_obj.addEventListener(“select”, onSelect);
manager_obj.addEventListener(“deselect”, onDeSelect);

function onSelect(event_obj:Object):Void {
_root.selectedMC=event_obj.targetObject;
if(event_obj.targetObject._name==”child_MC”)
{
mc=event_obj.targetObject;
_root.manager_obj.removeItem(mc);
_root.manager_obj.addItem(mc._parent);
}
}

function onDeSelect(event_obj:Object):Void {
if(event_obj.targetObject._parent._name==”parent_MC”)
{
mc=event_obj.targetObject;
_root.manager_obj.removeItem(mc); _root.manager_obj.addItem(mc.child_MC);
}
}

Thanks for your transform manager class.

Posted by Gerald Gibson on September 27, 2007

Please excuse my previous request for help. I keep forgeting that things show up differently in the Macromedia design time versus the run time… when I ran this exact same SWF in a run time situation the transform outline and handles were correctly centered on the MC… Your class has saved me an unknown # of hours (which I am sure you know how many hours it saved me) … If my company ends up using this in the final product I will be back to donate as we regularly buy components to help save me time… Thanks! Check out my website if you do any C# coding and maybe you will find some free code there that may help you out as well…

Posted by Dan on October 8, 2007

Hi Jack,

Absolutely love this package – saved me hours and hours of work so thank you!

One question: When transforming a textfield, it seems to only work like in the above example (without distorting the text) when it is set to selectable = true. But when it’s selectable, it can’t be moved because the cursor changes to a “select text” cursor when the mouse is over the textfield.

I’ve put a selectable=false call in the “select” event, but then it stops the textfield from being transformable at all!

Any ideas how to get around this?

Posted by jack on October 8, 2007

Dan, you’re right, it is tricky to handle transforming the text because it must be selectable but at the same time you want to give the user the ability to grab the whole text box and move it. So I took a similar approach to what a lot of graphics programs do – you just have to grab the EDGE of the text box and you can drag it around. Genius, I know. :-)

But seriously, if you (or anyone) has a better idea, feel free to share. In the mean time, you should be able to grab the edges of the selection box to drag it around.

Posted by Sascha on October 11, 2007

this is really great and of course I will leave credits to you inside the project…just what I looked for!! wow! killer app!

Posted by Michael on November 3, 2007

Very impressive! Thank you, thank you, thank you! You have potentially saved us dozens of hours (if not more)…expect a donation once we have our application off the ground.

Posted by Max on November 8, 2007

Hello Jack,

Your manager blowed my mind. I’m trying to add some undo – redo buttons to my application. I managed to save the transformed properties into different arrays (x y xscale yscale rotation). But now I don’t know how to trigger the new transformation with that values. Could you give me some example of how to call it directly by code?

Regards,
Max.

Posted by jack on November 8, 2007

Max, to apply new rotation/position/scale properties to an item via code, just do it directly and then call the update() method on the TransformItem object associated with the MovieClip, like:

var transform_obj = new TransformManager({targetObjects:[my_mc]});
my_mc._x = 2;
my_mc._y = 89;
my_mc._xscale = 23;
my_mc._yscale = 23;
my_mc._rotation = 82;
transform_obj.getItemFromTargetObject(my_mc).update();

Posted by Leonardo on November 12, 2007

Hi Jack,
thank you for this lovely tool, very handy!!
I’ve two question/request:would be nice if your transform manager could be used togheter with a selection tool for selecting and manipulating multiple movieclip at time; there’s a way (via actionscript) to accomplish that?

Thank you so much for your beautiful work!

Posted by jack on November 12, 2007

Leonardo, sorry, but at this time there is no way to select/transform multiple items at once.

Posted by Sam on November 18, 2007

Jack, you are truly the man! This script does more than i even knew i needed.

Any way to customize the scale and rotate icons?

expect a donation from me when i am done with this integration.

Sam

Posted by jack on November 19, 2007

Sam, sure you can customize the scale/rotate icons if you want. Just replace my buildRotationCursor() and buildScaleCursor() functions with your own. They’re in the TransformItem class.

Posted by Sameer on November 30, 2007

Beautiful application. Thanks for sharing this. i have a question though :)

is it possible to do a proportional scale w/o using the shift key?

Thanks in advance

Posted by jack on November 30, 2007

Sameer, absolutely you can. Just set the constrainScale property to true! No need to hold down the SHIFT key then – it’ll scale proportionally every time.

Posted by Bobby The Goose on December 5, 2007

Jack, your a legend! This work is spot on and i’m amazed and grateful that your willing to share it with everyone.

One question though. Is it possible to attach a collision detect element to movie clips that use transform manager? Im trying to create a drag and drop like feature that moves a movie clip to a specific x and y position if it comes into contact with a certain movie clip on stage. At the moment ive been attaching a basic if statement to mc1 but this doesn’t seem to work!

on (release){
if (_root.mc1._droptarget == “/mc2″) {
this._x = 300;
this._x = 50;
}
}

Thanks in advance

Posted by jack on December 5, 2007

Hey “Bobby the Goose”

I’d recommend setting up a listener that listens for the “move” event in order to sense the drop, like:

var manager_obj = new TransformManager({targetObjects:[test_mc, test2_mc], forceSelectionToFront:true});
manager_obj.addEventListener(“move”, onDrop);

function onDrop(event:Object):Void {
trace(“Dropped mc: “+event.targetObject);
}

The problem with using an onRelease is that TransformManager sets up its own onRelease for your MovieClip, so it essentially overwrites yours (although if you remove the MovieClip from the TransformManager using removeItem(), it’ll restore your onRelease politely).

Good luck!

Posted by Shane Girish on December 28, 2007

This code saved me hours of work. I’m gonna implement this onto a non-commercial project released by SISO in India. So Thank you for this amazing piece of code.

Posted by yarek on December 31, 2007

Totally AMAZEING tool !
works perfectly.
Do you plan to add MULTIPLE selection (selecting movies with a bounding rectangle). This would be useful, because if your movie in composed of thin lines (hairline for instance): it is VERY difficult to select it or apply tranformation: you have to click on the THIN line: that means lot of precision and lot of patience.

Thanks a lot for this wonderfull tool

Posted by jack on December 31, 2007

yarek, I don’t have any immediate plans to add multiple selection capabilities to TransformManager. If I get a commercial project that requires it, I’ll add it at that point, but I can’t afford the time it would take to do it at this point with all the other stuff on my plate. Sorry! I hope the existing class at least serves as a jumping-off point for you.

Posted by mbip on January 8, 2008

Hi,

Thank u for ur works. Hard to say what u’ve done. It helps me lot. Thanks again. Let u know my site details after implementation of the same.

Thanks,
MBip

Posted by Jitendra Panwar on January 12, 2008

Thanks a lot to u. I was searching for transform manager for last few days and no help. Specially I wanted to know how to constrain a transforming MC within a defined area. But With your class that can be done like a charm.
This code saved me hours of work. This is really great and of course I will leave credits to you inside the project. Once again thanks for sharing this

Posted by Elliot on January 14, 2008

Where do you set the x and y constraints that stop objects from moving beyond a certain point? My project needs to be 800 x 600 pixels and the default coordinates are approx 550 x 400.

I’m trying to create an on-line version of the exercises from the book “Visual Literacy: A Conceptual Approach to Graphic Problem Solving.” Students drag and position items to solve design problems and your software is perfect!

Thanks…

Posted by jack on January 14, 2008

Elliot, you can control the constraints/bounds using the “bounds” property which you pass in to the constructor, like:

var myTransformManager = new TransformManager({transformObjects:[myClip1_mc, myClip2_mc], bounds:{xMin:0, xMax:800, yMin:0, yMax:600}, allowDelete:true});

Posted by Matt on February 18, 2008

Hi there,

excellent work! Wow!

Is there any posibility, to change the bounds xMax & yMax dynamically when the image is already loaded and registered?

Thanks for help.

Posted by Anand on February 18, 2008

This article is really terrific. The class files and sample file attached here is also great.

Posted by Jose Teixeira on February 18, 2008

Hi Jack!

Thank you very (very!!) much for your excelent solution to scale/rotate/move issues.
TransformManager saved me lots of time and was 100% suitable for the problem i came into.

I used TransformManager in my personal project: http://www.faceinhole.com.

Thank you!!
Jose Teixeira (Portugal)

Posted by jack on February 18, 2008

Sure, Matt, you should be able to change the “bounds” property anytime, either on the TransformItem or the TransformManager.

Posted by Saga on March 10, 2008

I like it very much………..

actually i’m a c# programer, I am going to develop a move for TShirt project.
It gives me courage and saves time

thank you very much…………..

Posted by Eric on April 18, 2008

Hi Jack,

Great work!! Thanks very much.

To set the width (or height) I have made a little function…

function set_width() {
// set manager_obj.autoDeselect=false
dd=manager_obj.selectedTargetObject
rot = dd._rotation;
dd._rotation = 0;
dd._width = s1.value;
dd._rotation=rot
manager_obj.selectedItem.update();
}

Hope it helps someone….

Eric

Posted by Mark on April 22, 2008

Hi Jack,
Great tool – very well designed and of immense help,
thank you,
Mark

Posted by Canazza on July 10, 2008

just been reading the comments and noticed what Yarek said (6 months ago, i know) but i’ve come up with a solution for hairline thin line objects. Just draw an invisible square within it to serve as the hit area.
i’ve modified the following code in the TransformManager class:
####################
if (tgo instanceof TextField) {
var new_obj = new TransformItemTF(tgo, …);
} else {
######## EDITED CODE ########
var bnds:Object = tgo.getBounds(tgo)
if(bnds.xMin – bnds.xMax < 5) { //if it’s thiner than 5 px in the X direction, add some padding
bnds.xMin -= 5;
bnds.xMax += 5
}
if(bnds.yMin – bnds.yMax < 5) {//if it’s thiner than 5 px in the Y direction, add some padding
bnds.yMin -= 5;
bnds.yMax += 5
}
tgo.beginFill(0,0)
tgo.lineStyle(0,0,0)
tgo.moveTo(bnds.xMin,bnds.yMin)
tgo.lineTo(bnds.xMax,bnds.yMin)
tgo.lineTo(bnds.xMax,bnds.yMax)
tgo.lineTo(bnds.xMin,bnds.yMax)
tgo.endFill()
######## END EDITED CODE ########
var new_obj = new TransformItem(tgo, … (lots of stuff here));

}
###################
you can change the values to suit yourself

Posted by sherest on July 15, 2008

Great tool! Thanks a lot..

how can I rotate/scale/flip the target object via custom script. I have few button placed down in my movie to perform those action, but it rotates the target movie clip form upper left corner instead of center. when we scale the target object via button, it’s enlarge the movie clip beyond the bound area mentioned in Transform Manager object. Please help me?

Posted by jack on July 15, 2008

sherest, I have good news and bad news for you. First the bad news: the AS2 version of TransformManager doesn’t allow you to directly transform objects through code (its transformations are purely interactive). However, you CAN directly alter any object’s scale/rotation/position and then call update() to force the selection handles to adjust to the new dimesions/position, but that won’t solve your problem relating to scaling around the center instead of the registration point that’s in the upper left.

Now for the good news…

1) I completely rebuilt the AS3 version of TransformManager and it lets you easily accomplish exactly what you’re after. Everything can be driven by user interaction OR code (or a mixture of both). It also adds a bunch of features including multiple selections, extra handles, depth management, and lots more. You can see an interactive demo at http://www.greensock.com/ActionScript/TransformManager/AS3/. If you can target AS3 in your project, I’d highly recommend it. I plan to sell licenses of the AS3 version of TransformManager on my site within the next few weeks.

2) If you must use AS2, you can join Club GreenSock and get the TransformMatrixProxy class (http://blog.greensock.com/transformmatrixproxy/) which allows you to set a custom registration point around which all matrix transformations occur. This would allow you to rotate around the center of your clip instead of the upper left corner where the registration point is. There’s an AS2 version of the class available (although you must target Flash Player 8 because earlier versions don’t recognize matrix transformations). You could use the class in conjunction with TransformManager (and its update() call) to accomplish what you’re after.

Posted by Jamison on October 1, 2008

Jack, you are the man. Thanks for such great source.

Posted by K999 on March 31, 2009

Jack, I have simply these words for you “YOU ARE AWESOME”, this class saved a lot of my time and efforts.thanks again.

Posted by Nagarajan on August 13, 2009

Dear Jack,
You are the great man in life and as2. You have reached two step ahead from others in our flash community.

Regards,
Nagarajan

Posted by LEO on November 4, 2009

You are the best!
Thanks you!