/** * * VersatileTween.as * * A better Tween. Sample usage: * new VersatileTween(mySprite, {prop: 'x', finish: 100, duration: 5, delay: 1, useSeconds: true}); * * version history: * 2007.07.20 * - improved garbage-collection-prevention mechanism and moved it * into GCSafeTween class. * 2007.07.19 * - added some safeguards to prevent the Tween from being garbage * collected. * 2007.06.07 * - added easeDuration param so that you can set how long the * easing function will take, not counting delay. * - delay obeys useSeconds again * - cleanup, additional error reporting. * 2007.05.31 * - as3 version. doesn't include speed or frame delays. * 2006.10.27 * - func removed from options object * 2006.10.24 * - finish is now part of options object too * 2006.10.19 * - incorporated delay, speed * 2006.10.13 * - first draft * * @author matthew at exanimo dot com * @author Ryan Sprake (rsprake@sunkingig.com) * @version 2007.07.20 * */ package com.exanimo.transitions { import ArgumentError; import com.exanimo.transitions.GCSafeTween; import com.exanimo.transitions.VersatileTweenParams; import flash.utils.Dictionary; public class VersatileTween extends GCSafeTween { private static var _activeTweens:Dictionary = new Dictionary(true); private var _inConstructor:Boolean; public var autoPlay:Boolean; public var cancelActive:Boolean; public var cancelable:Boolean; public var delay:Number; /** * * Constructs a tween. * * @param object the object whose property you want to tween * @param params an object containing animation options. see * VersatileTweenParams. * */ public function VersatileTween(obj:Object, params:Object) { if (!(params is VersatileTweenParams)) { params = new VersatileTweenParams(params); } var throwBeginFinishError:Boolean = false; var throwDeltaError:Boolean = false; var throwPropError:Boolean = !(this.prop = params.prop); this.obj = obj; this.func = params.func || this.func; this.autoPlay = !(params.autoPlay == false); var hasDelta:Boolean = !isNaN(params.delta); var hasBegin:Boolean = !isNaN(params.begin); var hasFinish:Boolean = !isNaN(params.finish); if (!throwPropError) { if (hasDelta) { if (hasFinish && !hasBegin) { // Calculate the begin value from finish and delta. this.begin = params.finish - params.delta; this.finish = params.finish; } else if (!hasFinish) { // Calculate the finish value from begin and delta. If begin is not // provided, assume the current property value. this.begin = hasBegin ? params.begin : obj[prop]; this.finish = this.begin + params.delta; } else if (params.begin + params.delta != params.finish) { // The user has provided a value for begin, finish, and delta, but the // values don't jive. throwDeltaError = true; } } else if (!hasBegin && !hasFinish) { throwBeginFinishError = true; } else { // The user has not provided a delta. Start at begin and end at finish. If // either is not provided, VersatileTween will use the current property // value in its place. this.begin = hasBegin ? params.begin : obj[prop]; this.finish = hasFinish ? params.finish: obj[prop]; } this.useSeconds = params.useSeconds || false; this.delay = params.delay || 0; this.cancelable = params.cancelable != false; this.cancelActive = params.cancelActive || false; this.duration = params.duration || params.easeDuration + this.delay; // Add the tween to the list of active tweens. if (this.cancelable) { VersatileTween._activeTweens[this] = true; } // If this property is already being tweened, and this VersatileTween is set // to cancelActive, stop the active VersatileTween(s). if (this.cancelActive) { this._cancelActiveTweens(); } // Create the Tween. this._inConstructor = true; super(obj, this.prop, this.func, this.begin, this.finish, this.duration, params.useSeconds); this._inConstructor = false; } if (throwPropError) { throw new ArgumentError('A VersatileTween can not be created without a prop value.'); } if (throwBeginFinishError) { throw new ArgumentError('A VersatileTween requires either a begin, finish, or delta value.'); } if (throwDeltaError) { throw new ArgumentError('Incompatible begin, finish, and delta values. (Why are you providing all three anyway?)'); } } // // accessors // public function get easeDuration():Number { return this.duration - this.delay; } // // public methods // /** * * Overriden to allow delay. * */ public override function getPosition(t:Number = NaN):Number { if (isNaN(t)) { return super.getPosition(t); } else if (t < this.delay) { return this.begin; } else { return this.func(t - this.delay, this.begin, this.change, this.duration - this.delay); } } /** * * * */ public override function start():void { if (this._inConstructor && !this.autoPlay) return; super.start(); } // // private methods // /** * * Cancels all the tweens already active on this property. * */ private function _cancelActiveTweens():void { for (var t:Object in VersatileTween._activeTweens) { if ((t.obj == this.obj) && (t.prop == this.prop) && t.isPlaying) { t.stop(); } } } } }