/**
* VERSION: 0.94
* DATE: 9/22/2009
* AS2
* UPDATES AND DOCUMENTATION AT: http://blog.greensock.com/
**/
import flash.geom.*;
import mx.utils.*;
/**
* TweenProxy essentially "stands in" for a MovieClip, adding several tweenable properties as well as the
* ability to set a custom registration point around which all transformations (like rotation, scale, and skew)
* occur. In addition to all the standard MovieClip properties, TweenProxy adds:
*
registration
point is based on the MovieClip's parent's coordinate space whereas the localRegistration
corresponds
* to the MovieClip's inner coordinates, so it's very simple to define the registration point whichever way you prefer.
*
* import com.greensock.TweenProxy;
* import com.greensock.easing.Elastic;
* import flash.geom.Point;
*
* var myProxy:TweenProxy = TweenProxy.create(my_mc);
* myProxy.registration = new Point(100, 100);
* TweenLite.to(myProxy, 3, {skewX:30, scale:0.5, ease:Elastic.easeOut});
*
* Copyright 2011, GreenSock. All rights reserved. This work is subject to the terms in http://www.greensock.com/terms_of_use.html or for corporate Club GreenSock members, the software agreement that was issued with the corporate membership.
*
* @author Jack Doyle, jack@greensock.com
*/
dynamic class com.greensock.TweenProxy {
/** @private **/
public static var VERSION:Number = 0.93;
/** @private **/
private static var _DEG2RAD:Number = Math.PI / 180; //precompute for speed
/** @private **/
private static var _RAD2DEG:Number = 180 / Math.PI; //precompute for speed
/** @private **/
private static var _dict:Object = new Object();
/** @private **/
private static var _classInitted:Boolean;
/** @private **/
private var _target:MovieClip;
/** @private **/
private var _scaleX:Number;
/** @private **/
private var _scaleY:Number;
/** @private **/
private var _angle:Number;
/** @private **/
private var _proxies:Array; //populated with all TweenProxy instances with the same _target (basically a faster way to access _dict[_target])
/** @private **/
private var _localRegistration:Point; //according to the local coordinates of _target (not _target._parent)
/** @private **/
private var _registration:Point; //according to _target._parent coordinates
/** @private **/
private var _regAt0:Boolean; //If the localRegistration point is at 0, 0, this is true. We just use it to speed up processing in getters/setters.
/** @private **/
public var ignoreSiblingUpdates:Boolean = false;
/** @private **/
public var isTweenProxy:Boolean = true; //potentially checked by TweenLite
public function TweenProxy($target:MovieClip, $ignoreSiblingUpdates:Boolean) {
_target = $target;
if (_dict[_target] == undefined) {
_dict[_target] = [];
}
if (!_classInitted) {
var properties:Array = ["blendMode","cacheAsBitmap","_currentframe","_droptarget","enabled","filters","focusEnabled","_focusrect","forceSmoothing","_framesloaded","_highquality","hitArea","_lockroot","menu","_name","opaqueBackground","_parent","_quality","scale9Grid","scrollRect","_soundbuftime","tabChildren","tabEnabled","tabIndex","_totalframes","trackAsMenu","transform","_url","useHandCursor","_visible","_xmouse","_ymouse"];
var i:Number;
for (i = 0; i < properties.length; i++) {
TweenProxy.prototype.addProperty(properties[i], createIndexGetter(properties[i]), createIndexSetter(properties[i]));
}
var functions:Array = ["attachAudio","attachBitmap","attachMovie","beginBitmapFill","beginFill","beginGradientFill","clear","createEmptyMovieClip","createTextField","curveTo","duplicateMovieClip","endFill","getBounds","getBytesLoaded","getBytesTotal","getDepth","getInstanceAtDepth","getNextHighestDepth","getRect","getSWFVersion","getTextSnapshot","getURL","globalToLocal","gotoAndPlay","gotoAndStop","hitTest","lineGradientStyle","lineStyle","lineTo","loadMovie","loadVariables","localToGlobal","moveTo","nextFrame","play","prevFrame","removeMovieClip","setMask","startDrag","stop","stopDrag","swapDepths","unloadMovie"];
for (i = 0; i < functions.length; i++) {
this[functions[i]]();
}
_classInitted = true;
}
_proxies = _dict[_target];
_proxies.push(this);
_localRegistration = new Point(0, 0);
this.ignoreSiblingUpdates = ($ignoreSiblingUpdates == undefined) ? false : $ignoreSiblingUpdates;
calibrate();
}
public static function create($target:MovieClip, $allowRecycle:Boolean):TweenProxy {
if (_dict[$target] != undefined && $allowRecycle != false) {
return _dict[$target][0];
} else {
return new TweenProxy($target);
}
}
public function getCenter():Point {
var b:Object = _target.getBounds(_target._parent);
return new Point((b.xMin + b.xMax) / 2, (b.yMin + b.yMax) / 2);
}
public function get target():MovieClip {
return _target;
}
public function calibrate():Void {
_scaleX = _target._xscale / 100;
_scaleY = _target._yscale / 100;
_angle = _target._rotation * _DEG2RAD;
calibrateRegistration();
}
public function destroy():Void {
var a:Array = _dict[_target], i:Number;
for (i = a.length - 1; i > -1; i--) {
if (a[i] == this) {
a.splice(i, 1);
}
}
if (a.length == 0) {
delete _dict[_target];
}
}
//---- PROXY FUNCTIONS ------------------------------------------------------------------------------------------
/** @private **/
private static function createIndexGetter($property:String):Function {
return function():Object {return _target[$property]};
}
/** @private **/
private static function createIndexSetter($property:String):Function {
return function($value:Object):Void {this.onSetProperty($property, $value);};
}
/** @private **/
public function __resolve($name:String):Object {
if (_target[$name] instanceof Function) {
var f:Function = function():Object {
arguments.unshift($name);
return this.onCallProperty.apply(this, arguments);
};
TweenProxy.prototype[$name] = f;
return f(arguments);
} else {
return _target[$name];
}
}
/** @private **/
private function onCallProperty($name:String):Object {
arguments.shift();
return _target[$name].apply(_target, arguments);;
}
/** @private **/
private function onSetProperty($prop:Object, $value:Object):Void {
_target[$prop] = $value;
}
//---- GENERAL REGISTRATION -----------------------------------------------------------------------
/** @private **/
public function moveRegX($n:Number):Void {
_registration.x += $n;
}
/** @private **/
public function moveRegY($n:Number):Void {
_registration.y += $n;
}
/** @private **/
private function reposition():Void {
var p:Point = _localRegistration.clone();
_target.localToGlobal(p);
_target._parent.globalToLocal(p);
_target._x += _registration.x - p.x;
_target._y += _registration.y - p.y;
}
/** @private **/
private function updateSiblingProxies():Void {
for (var i:Number = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] != this) {
_proxies[i].onSiblingUpdate(_scaleX, _scaleY, _angle);
}
}
}
/** @private **/
private function calibrateLocal():Void {
_localRegistration = _registration.clone();
_target._parent.localToGlobal(_localRegistration);
_target.globalToLocal(_localRegistration);
_regAt0 = (_localRegistration.x == 0 && _localRegistration.y == 0);
}
/** @private **/
private function calibrateRegistration():Void {
_registration = _localRegistration.clone();
_target.localToGlobal(_registration);
_target._parent.globalToLocal(_registration);
_regAt0 = (_localRegistration.x == 0 && _localRegistration.y == 0);
}
/** @private **/
public function onSiblingUpdate($scaleX:Number, $scaleY:Number, $angle:Number):Void {
_scaleX = $scaleX;
_scaleY = $scaleY;
_angle = $angle;
if (this.ignoreSiblingUpdates) {
calibrateLocal();
} else {
calibrateRegistration();
}
}
//---- LOCAL REGISTRATION ---------------------------------------------------------------------------
public function get localRegistration():Point {
return _localRegistration;
}
public function set localRegistration($p:Point):Void {
_localRegistration = $p;
calibrateRegistration();
}
public function get localRegistrationX():Number {
return _localRegistration.x;
}
public function set localRegistrationX($n:Number):Void {
_localRegistration.x = $n;
calibrateRegistration();
}
public function get localRegistrationY():Number {
return _localRegistration.y;
}
public function set localRegistrationY($n:Number):Void {
_localRegistration.y = $n;
calibrateRegistration();
}
//---- REGISTRATION (OUTER) ----------------------------------------------------------------------
public function get registration():Point {
return _registration
}
public function set registration($p:Point):Void {
_registration = $p;
calibrateLocal();
}
public function get registrationX():Number {
return _registration.x;
}
public function set registrationX($n:Number):Void {
_registration.x = $n;
calibrateLocal();
}
public function get registrationY():Number {
return _registration.y;
}
public function set registrationY($n:Number):Void {
_registration.y = $n;
calibrateLocal();
}
//---- X/Y MOVEMENT ---------------------------------------------------------------------------------
public function get x():Number {
return _registration.x;
}
public function set x($n:Number):Void {
var tx:Number = ($n - _registration.x);
_target.x += tx;
for (var i:Number = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] == this || !_proxies[i].ignoreSiblingUpdates) {
_proxies[i].moveRegX(tx);
}
}
}
public function get y():Number {
return _registration.y;
}
public function set y($n:Number):Void {
var ty:Number = ($n - _registration.y);
_target.y += ty;
for (var i:Number = _proxies.length - 1; i > -1; i--) {
if (_proxies[i] == this || !_proxies[i].ignoreSiblingUpdates) {
_proxies[i].moveRegY(ty);
}
}
}
//---- ROTATION ----------------------------------------------------------------------------
public function get rotation():Number {
return _angle * _RAD2DEG;
}
public function set rotation($n:Number):Void {
var radians:Number = $n * _DEG2RAD;
var m:Matrix = _target.transform.matrix;
m.rotate(radians - _angle);
_target.transform.matrix = m;
//_target._rotation = $n; //a bug in the Flash Player prevents the transform.matrix edit from updating the actual _rotation value, so this explicitly sets it.
_angle = radians;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
//---- SKEW -------------------------------------------------------------------------------
public function get skewX():Number {
var m:Matrix = _target.transform.matrix;
return (Math.atan2(-m.c, m.d) - _angle) * _RAD2DEG;
}
public function set skewX($n:Number):Void {
var radians:Number = $n * _DEG2RAD;
var m:Matrix = _target.transform.matrix;
var sy:Number = (_scaleY < 0) ? -_scaleY : _scaleY;
m.c = -sy * Math.sin(radians + _angle);
m.d = sy * Math.cos(radians + _angle);
_target.transform.matrix = m;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get skewY():Number {
var m:Matrix = _target.transform.matrix;
return (Math.atan2(m.b, m.a) - _angle) * _RAD2DEG;
}
public function set skewY($n:Number):Void {
var radians:Number = $n * _DEG2RAD;
var m:Matrix = _target.transform.matrix;
var sx:Number = (_scaleX < 0) ? -_scaleX : _scaleX;
m.a = sx * Math.cos(radians + _angle);
m.b = sx * Math.sin(radians + _angle);
_target.transform.matrix = m;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
//---- SKEW2 ----------------------------------------------------------------------------------
public function get skewX2():Number {
return (-Math.atan(_target.transform.matrix.c) - _angle) * _RAD2DEG;
}
public function set skewX2($n:Number):Void {
var m:Matrix = _target.transform.matrix;
m.c = Math.tan((-$n * _DEG2RAD) + _angle);
_target.transform.matrix = m;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get skewY2():Number {
return (Math.atan(_target.transform.matrix.b) - _angle) * _RAD2DEG;
}
public function set skewY2($n:Number):Void {
var m:Matrix = _target.transform.matrix;
m.b = Math.tan(($n * _DEG2RAD) + _angle);
_target.transform.matrix = m;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
//---- SCALE --------------------------------------------------------------------------------------
public function get scaleX():Number {
return _scaleX;
}
public function set scaleX($n:Number):Void {
if ($n == 0) {
$n = 0.0001;
}
var m:Matrix = _target.transform.matrix;
var ratio:Number = $n / _scaleX;
m.a *= ratio;
m.b *= ratio;
_target.transform.matrix = m;
//_target._xscale = $n * 100; //a bug in the Flash Player prevents the transform.matrix edit from updating the actual _xscale value, so this explicitly sets it.
_scaleX = $n;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get scaleY():Number {
return _scaleY;
}
public function set scaleY($n:Number):Void {
if ($n == 0) {
$n = 0.0001;
}
var m:Matrix = _target.transform.matrix;
var ratio:Number = $n / _scaleY;
m.c *= ratio;
m.d *= ratio;
_target.transform.matrix = m;
//_target._yscale = $n * 100; //a bug in the Flash Player prevents the transform.matrix edit from updating the actual _yscale value, so this explicitly sets it.
_scaleY = $n;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get scale():Number {
return (_scaleX + _scaleY) / 2;
}
public function set scale($n:Number):Void {
if ($n == 0) {
$n = 0.0001;
}
var m:Matrix = _target.transform.matrix;
var ratioX:Number = $n / _scaleX;
var ratioY:Number = $n / _scaleY;
m.a *= ratioX;
m.b *= ratioX;
m.c *= ratioY;
m.d *= ratioY;
_target.transform.matrix = m;
_scaleX = _scaleY = $n;
reposition();
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
//---- OTHER PROPERTIES ---------------------------------------------------------------------------------
public function get _x():Number {
return this.x;
}
public function set _x($n:Number):Void {
this.x = $n;
}
public function get _y():Number {
return this.y;
}
public function set _y($n:Number):Void {
this.y = $n;
}
public function get _alpha():Number {
return _target._alpha;
}
public function set _alpha($n:Number):Void {
_target._alpha = $n;
}
public function get _xscale():Number {
return _scaleX * 100;
}
public function set _xscale($n:Number):Void {
this.scaleX = $n / 100;
}
public function get _yscale():Number {
return _scaleY * 100;
}
public function set _yscale($n:Number):Void {
this.scaleY = $n / 100;
}
public function get _width():Number {
return _target._width;
}
public function set _width($n:Number):Void {
_target._width = $n;
if (!_regAt0) {
reposition();
}
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get _height():Number {
return _target._height;
}
public function set _height($n:Number):Void {
_target._height = $n;
if (!_regAt0) {
reposition();
}
if (_proxies.length > 1) { //if there are other proxies controlling the same _target, make sure their _registration variable is updated
updateSiblingProxies();
}
}
public function get _rotation():Number {
return _angle * _RAD2DEG;
}
public function set _rotation($n:Number):Void {
this.rotation = $n;
}
}