package com { import flash.display.Shape; import flash.events.Event; import flash.utils.getTimer; public class TweenNano { protected static var _time:Number; protected static var _frame:uint; public static var ticker:Shape = new Shape(); public static var defaultEase:Object = function (t:Number, b:Number, c:Number, d:Number):Number { return -1 * (t /= d) * (t - 2); } protected static var _reservedProps:Object; protected static var _tickEvent:Event = new Event("tick"); protected static var _first:TweenNano; protected static var _last:TweenNano; public var _duration:Number; public var vars:Object; public var _startTime:Number; public var target:Object; public var _gc:Boolean; public var _useFrames:Boolean; public var ratio:Number = 0; protected var _ease:Function; protected var _rawEase:Object; protected var _initted:Boolean; protected var _firstPT:Object; public var _next:TweenNano; public var _prev:TweenNano; public var _targets:Array; public function TweenNano(target:Object, duration:Number, vars:Object) { if (!_reservedProps) { _reservedProps = {ease:1, delay:1, useFrames:1, overwrite:1, onComplete:1, onCompleteParams:1, runBackwards:1, immediateRender:1, onUpdate:1, onUpdateParams:1, startAt:1}; _time = getTimer() / 1000; _frame = 0; ticker.addEventListener(Event.ENTER_FRAME, _updateRoot, false, 0, true); } this.vars = vars; _duration = duration; this.target = target; if (target is Array && typeof(target[0]) === "object") { _targets = target.concat(); } _rawEase = this.vars.ease || defaultEase; _ease = (typeof(_rawEase) == "function") ? _rawEase as Function : _rawEase.getRatio; _useFrames = Boolean(vars.useFrames == true); _startTime = (_useFrames ? _frame : _time) + (this.vars.delay || 0); if (this.vars.overwrite == "all" || int(this.vars.overwrite) == 1) { killTweensOf(this.target); } _prev = _last; if (_last) { _last._next = this; } else { _first = this; } _last = this; if (this.vars.immediateRender == true || (duration == 0 && this.vars.delay == 0 && this.vars.immediateRender != false)) { _render(0); } } public function _init():void { if (vars.startAt) { vars.startAt.immediateRender = true; TweenNano.to(target, 0, vars.startAt); } var i:int, pt:Object; if (_targets != null) { i = _targets.length; while (--i > -1) { _initProps(_targets[i]); } } else { _initProps(target); } if (vars.runBackwards) { pt = _firstPT; while (pt) { pt.s += pt.c; pt.c = -pt.c; pt = pt._next; } } _initted = true; } protected function _initProps(target:*):void { if (target != null) { for (var p:String in vars) { if (!(p in _reservedProps)) { _firstPT = {_next:_firstPT, t:target, p:p, f:(typeof(target[p]) === "function")}; _firstPT.s = (!_firstPT.f) ? Number(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ](); _firstPT.c = (typeof(vars[p]) === "number") ? Number(vars[p]) - _firstPT.s : (typeof(vars[p]) === "string" && vars[p].charAt(1) === "=") ? int(vars[p].charAt(0)+"1") * Number(vars[p].substr(2)) : Number(vars[p]) || 0; if (_firstPT._next) { _firstPT._next._prev = _firstPT; } } } } } public function _render(time:Number):void { if (!_initted) { _init(); } if (time >= _duration) { time = _duration; this.ratio = (_ease != _rawEase && _rawEase._calcEnd) ? _ease.call(_rawEase, 1) : 1; } else if (time <= 0) { this.ratio = (_ease != _rawEase && _rawEase._calcEnd) ? _ease.call(_rawEase, 0) : 0; } else { this.ratio = (_ease == _rawEase) ? _ease(time, 0, 1, _duration) : _ease.call(_rawEase, time / _duration); } var pt:Object = _firstPT; while (pt) { if (pt.f) { pt.t[pt.p](pt.c * ratio + pt.s); } else { pt.t[pt.p] = pt.c * ratio + pt.s; } pt = pt._next; } if (vars.onUpdate) { vars.onUpdate.apply(null, vars.onUpdateParams); } if (time == _duration) { kill(); if (vars.onComplete) { vars.onComplete.apply(null, vars.onCompleteParams); } } } public function kill(target:*=null):void { var i:int, pt:Object = _firstPT; target = target || _targets || this.target; if (target is Array && typeof(target[0]) === "object") { i = target.length; while (--i > -1) { kill(target[i]); } return; } else if (_targets != null) { i = _targets.length; while (--i > -1) { if (target == _targets[i]) { _targets.splice(i, 1); } } while (pt) { if (pt.t == target) { if (pt._next) { pt._next._prev = pt._prev; } if (pt._prev) { pt._prev._next = pt._next; } else { _firstPT = pt._next; } } pt = pt._next; } } if (_targets == null || _targets.length == 0) { _gc = true; if (_prev) { _prev._next = _next; } else if (this == _first) { _first = _next; } if (_next) { _next._prev = _prev; } else if (this == _last) { _last = _prev; } _next = _prev = null; } } public static function to(target:Object, duration:Number, vars:Object):TweenNano { return new TweenNano(target, duration, vars); } public static function from(target:Object, duration:Number, vars:Object):TweenNano { vars.runBackwards = true; if (!("immediateRender" in vars)) { vars.immediateRender = true; } return new TweenNano(target, duration, vars); } public static function delayedCall(delay:Number, callback:Function, params:Array=null, useFrames:Boolean=false):TweenNano { return new TweenNano(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, useFrames:useFrames}); } public static function _updateRoot(e:Event=null):void { _frame += 1; _time = getTimer() * 0.001; var tween:TweenNano = _first, next:TweenNano, t:Number; while (tween) { next = tween._next; t = (tween._useFrames) ? _frame : _time; if (t >= tween._startTime && !tween._gc) { tween._render(t - tween._startTime); } tween = next; } ticker.dispatchEvent(_tickEvent); } public static function killTweensOf(target:Object):void { var t:TweenNano = _first, next:TweenNano; while (t) { next = t._next; if (t.target == target) { t.kill(); } else if (t._targets != null) { t.kill(target); } t = next; } } } }