// /* class tweenManager for tweening prototypes version 1.2.0 Ladislav Zigo,lacoz@web.de Moses Gunesch pause unpause fixed stop tween growing of ints array Updates by Moses Gunesch - www.MosesSupposes.com - May 2005 [all updates marked with search string: -(MosesSupposes)- ] - Added all extensions to - Added sizeTo, tintTo(rgb,percent) and invertColorTo(percent) extensions - Pause individual tweens: MovieClip.pauseTween(), MovieClip.unpauseTween(), MovieClip.isTweenPaused() [calls new $tweenManager methods: pauseTween(mc), unpauseTween(mc), isTweenPaused(mc)] - Pause/stop all tweens globally from any mc: MovieClip.stopAllTweens(), MovieClip.pauseAllTweens(), MovieClip.unpauseAllTweens() - Added fast-fwd & rewind: MovieClip.ffTween(), MovieClip.rewTween() [calls new $tweenManager methods: ffTween(mc), rewTween(mc)] - Pass a string instead of a number for value. (Except colorTransform methods) [i.e. scaleTo('-20') meaning 20 less than current scale.] Pass a comma-delimited string instead of an array to .tween(), .pauseTween(), several others. - Pass a single end value to .tween() with multiple properties for similar end value. - All broadcasts now send an object with target and props params (props is array of properties being affected). - Added onTweenInterrupt event. Occurs at overwrite or removeTween (called if autoStop is true). Cannot occur if clip goes missing. - Modified autoStop to stop all running tweens in a target. (Was targeting just the new props tweened, which happens anyway). - Added cleanUp routine - auto-delete tweens on missing targets - fixes re-test during local publish */ class zigo.tweenManager{ private var tweenList:Array; private var tweenHolder:MovieClip; private var playing:Boolean; private var now:Number; private var ints:Array; private var lockedTweens:Object; private var updateIntId:Number; private var updateTime:Number; private var pauseCount:Number; // -(MosesSupposes)- added pauseCount, removed vars pausedTime, isPaused private var isPaused:Boolean; private var _th_depth:Number = 6789; public var broadcastEvents:Boolean; public var autoStop:Boolean; public var autoOverwrite:Boolean; function tweenManager(){ playing = false; autoStop = false; broadcastEvents = false; autoOverwrite = true; ints = new Array(); lockedTweens = new Object(); tweenList = new Array(); } // -(MosesSupposes)- cleanUp searches for missing targets and clears those tweens out. // removeMovieClip or timeline keyframes can knock out a clip. Also when "re-testing" // an already-published swf this method successfully reboots the manager. function cleanUp() { if (!(tweenList instanceof Array && tweenList.length > 0)) return; for (var i in tweenList){ if(tweenList[i].mc._x == undefined) { tweenList.splice(Number(i),1); } } if(tweenList.length==0) { tweenList = []; deinit(); } for (var i in ints) { if (ints[i] != undefined && ints[i].mc._x == undefined) { removeDelayedTween(Number(i)); } } } // function set updateInterval(time:Number):Void{ if (playing){ deinit() updateTime = time init() }else{ updateTime = time } } function get updateInterval():Number{ return updateTime; } // function set controllerDepth(v:Number)// -(MosesSupposes)- change depth of broadcasting clip { if (_global.isNaN(v)==true) return; if(tweenHolder._name!=undefined){ tweenHolder.swapDepths(v); }else{ _th_depth = v; } } function get controllerDepth():Number { return _th_depth; } // private methods private function init():Void{ if(updateTime > 0){ clearInterval(updateIntId); //-(MosesSupposes)- safety updateIntId = setInterval(this,"update",updateTime); }else{ // fix bug with "Simulate Download" // tweenHolder is still movieclip, but not on the stage if(tweenHolder._name == undefined){ // tweenHolder = _root.createEmptyMovieClip("_th_",_th_depth); } var tm = this; tweenHolder.onEnterFrame = function(){ // this is faster because it eliminates usage of keyword "with" in update function tm.update.call(tm); } } playing = true; now = getTimer(); } private function deinit():Void{ playing = false; clearInterval(updateIntId); delete tweenHolder.onEnterFrame; } private function update():Void{ // loop all tween objects var t, i, j; var missing:Boolean = false; //-(MosesSupposes)- for cleanUp() i = tweenList.length; // broadcasting events if(broadcastEvents){ var ut, et, up, ep; ut = {};// list of updated mcs et = {};// list of ending mcs up = {};// -(MosesSupposes)- list of updated props ep = {};// -(MosesSupposes)- list of ending props } while (i--){ t = tweenList[i]; if (t.mc._x == undefined) { //-(MosesSupposes)- for cleanUp() missing = true; continue; } if (t.pt != -1) continue; //-(MosesSupposes)- skip processing paused tween if(t.ts + t.d > now){ // compute value using equation function if(t.ctm == undefined){ // compute primitive value t.mc[t.pp] = t.ef(now-t.ts,t.ps,t.ch,t.d,t.e1,t.e2); }else{ // compute color transform matrix // stm is starting transform matrix, // ctm is change in start & destination matrix // ttm is computed (temporary) transform matrix // c is color object var ttm = {}; for(j in t.ctm){ ttm[j] = t.ef(now-t.ts,t.stm[j],t.ctm[j],t.d,t.e1,t.e2) } t.c.setTransform(ttm); } if(broadcastEvents){ if(ut[targetpath(t.mc)] == undefined){ ut[targetpath(t.mc)] = t.mc; } if(up[targetpath(t.mc)] == undefined){// -(MosesSupposes)- up[targetpath(t.mc)] = []; } up[targetpath(t.mc)].push(t.ctm!=undefined ? '_ct_' : t.pp); } // if(t.cb.updfunc != undefined){ var f = t.cb.updfunc; if (typeof f=='string' && t.cb.updscope!=undefined) f = t.cb.updscope[f]; f.apply(t.cb.updscope,t.cb.updargs); } } else { // end , set up the property to end value; if(t.ctm == undefined){ t.mc[t.pp] = t.ps + t.ch; } else { var ttm = {}; for(j in t.ctm){ ttm[j] = t.stm[j]+t.ctm[j]; } t.c.setTransform(ttm); } if(broadcastEvents){ if(ut[targetpath(t.mc)] == undefined){ ut[targetpath(t.mc)] = t.mc; } if(et[targetpath(t.mc)] == undefined){ et[targetpath(t.mc)] = t.mc; } if(up[targetpath(t.mc)] == undefined){// -(MosesSupposes)- up[targetpath(t.mc)] = []; } up[targetpath(t.mc)].push(t.ctm!=undefined ? '_ct_' : t.pp); if(ep[targetpath(t.mc)] == undefined){// -(MosesSupposes)- ep[targetpath(t.mc)] = []; } ep[targetpath(t.mc)].push(t.ctm!=undefined ? '_ct_' : t.pp); } // last update call if(t.cb.updfunc != undefined){ var f = t.cb.updfunc; if (typeof f=='string' && t.cb.updscope!=undefined) f = t.cb.updscope[f]; f.updfunc.apply(t.cb.updscope,t.cb.updargs); } // end tweens if (endt == undefined){ var endt = new Array(); } endt.push(i); } } if (missing) cleanUp();// -(MosesSupposes)- // broadcast events (only 1 time for every mc) for (j in ut){ ut[j].broadcastMessage('onTweenUpdate', {target:ut[j], props:up[j]});// -(MosesSupposes)- send array of updated props } if(endt != undefined){ endTweens(endt); } for (j in et){ et[j].broadcastMessage('onTweenEnd', {target:et[j], props:ep[j]});// -(MosesSupposes)- send array of ending props } // update timer now = getTimer(); // updatedisplay if in setinterval mode if (updateTime > 0){ updateAfterEvent(); } } private function endTweens(tid_arr:Array):Void{ var cb_arr, tl, i, cb, j cb_arr = [] // splice tweens from tweenlist tl = tid_arr.length for (i = 0; i0) { mc.broadcastMessage('onTweenInterrupt', {target:mc, props:ip}); // -(MosesSupposes)- pass array of props interrupted } mc.broadcastMessage('onTweenStart', {target:mc, props:props}); // -(MosesSupposes)- pass array of props starting } // execute start function (may be usefull with delayed tweens) if(callback.startfunc != undefined){ var f = callback.startfunc; if (typeof f=='string' && callback.startscope!=undefined) f = callback.startscope[f]; f.apply(callback.startscope,callback.startargs) } if (sec==0) update(); // -(MosesSupposes)- fire 0-second tweens immediately instead of waiting for enterframe callback. } public function addTweenWithDelay(delay:Number,mc,props:Array, pEnd:Array, sec:Number,eqFunc:Function,callback:Object, extra1:Object,extra2:Object){ // var il, intid; il = ints.length; intid = setInterval(function(obj){ //-(MosesSupposes)- modified to use removeDelayedTween obj.removeDelayedTween(il); if (mc._x!=undefined) { //-(MosesSupposes)- check if clip still exists; otherwise cleanup is already done. obj.addTween(mc, props, pEnd, sec, eqFunc, callback, extra1, extra2); } },delay*1000,this); // array of waiting tweens, mc reference to movieclip, ..., intid setInterval function identifier // -(MosesSupposes)- added pt (paused time) prop- ints[il] = {mc: mc, props: props, pend:pEnd, intid:intid, st: getTimer(), delay:delay*1000, args: arguments.slice(1), pt:-1} if(!playing){ init();// -(MosesSupposes)- may be first item called, pause routines need this to be called. } } public function removeTween(mc:MovieClip,props:Array):Void{ var all, i, j; all = false; if(props == undefined && broadcastEvents!=true){// -(MosesSupposes)- added second condition for ip, below // props are undefined, remove all tweens all = true; } i = tweenList.length; var ip = {}; // -(MosesSupposes)- interrupted properties while (i--){ if(tweenList[i].mc == mc){ if(all) { tweenList.splice(i,1); }else{ // removing tweening of properties for(j in props){ if(tweenList[i].pp == props[j]){ tweenList.splice(i,1); if(ip[targetpath(mc)] == undefined){// -(MosesSupposes)- ip[targetpath(mc)] = {t:mc,p:[]}; } ip[targetpath(mc)].p.push(props[j]); // props.splice(j,1) // (because allows add same properties for same mc, // all tweens must be checked) } else if (props[j] == "_ct_" && tweenList[i].ctm != undefined && tweenList[i].mc == mc){ // removing of colorTransform tweens tweenList.splice(i,1); if(ip[targetpath(mc)] == undefined){// -(MosesSupposes)- ip[targetpath(mc)] = {t:mc,p:[]}; } ip[targetpath(mc)].p.push('_ct_'); } } } } } i = ints.length; // delayed tweens while(i--){ if(ints[i].mc == mc) { if(all){ // REMOVE ALL removeDelayedTween(Number(i)); //-(MosesSupposes)- } else { // REMOVE PROPERTIES for(j in props){ for(var k in ints[i].props){ if(ints[i].props[k] == props[j]) { // remove tween properties + property end values ints[i].props.splice(k,1); ints[i].pend.splice(k,1); if(ip[targetpath(mc)] == undefined){// -(MosesSupposes)- ip[targetpath(mc)] = {t:mc,p:[]}; } ip[targetpath(mc)].p.push(props[j]); } } if(ints[i].props.length == 0){ clearInterval(ints[i].intid) // no properties to tween } } } } } if(broadcastEvents){ for (var k in ip) { if (ip[k].p.length>0) { ip[k].t.broadcastMessage('onTweenInterrupt', {target:ip[k].t, props:ip[k].p}); // -(MosesSupposes)- pass array of props interrupted } } } if(tweenList.length==0){ // last tween removed, erase onenterframe function deinit(); } } public function isTweening(mc:MovieClip, prop:String):Boolean{ //-(MosesSupposes)- added prop param var allprops:Boolean = (prop==undefined); for (var i in tweenList){ var t = tweenList[i]; if(tweenList[i].mc == mc && tweenList[i].pt == -1 /*-(MosesSupposes)- tween is not paused*/ && (allprops || prop==t.pp || (prop=='_ct_' && t.ctm!=undefined))) { // mc found, so break loop return true; } } return false; } public function getTweens(mc:MovieClip):Number{ var count = 0; for (var i in tweenList){ if(tweenList[i].mc == mc){ // found, increase count count++; } } return count; } public function lockTween(mc:MovieClip,bool:Boolean):Void{ lockedTweens[targetpath(mc)] = bool; } public function isTweenLocked(mc:MovieClip):Boolean{ if(lockedTweens[targetpath(mc)] == undefined){ return false; }else{ return lockedTweens[targetpath(mc)]; } } public function ffTween(mc:MovieClip, propsObj:Object):Void { var all:Boolean = (mc==undefined); var allprops:Boolean = (propsObj==undefined); for (var i in tweenList){ var t = tweenList[i]; if((t.mc == mc || all) && (allprops || propsObj[t.pp]==true)) { if (t.pt != -1) { t.pt = -1; } t.ts = now - t.d; // back up start time so update will think it's done. } } // calling ffTween during a delay will affect all properties. for (var i in ints){ if(ints[i] != undefined) { if ((ints[i].mc == mc || all)) { if (ints[i].mc._x!=undefined) { // be sure clip still exists var args = ints[i].args; args[3] = 0; // set tween time to none addTween.apply(this, args); } removeDelayedTween(Number(i)); } } } update(); } public function rewTween(mc:MovieClip, propsObj:Object):Void { var all:Boolean = (mc==undefined); var allprops:Boolean = (propsObj==undefined); for (var i in tweenList){ var t = tweenList[i]; if((t.mc == mc || all) && (allprops || propsObj[t.pp]==true)) { if (t.pt != -1) { t.pt = -1; } t.ts = now; // reset start time } } // rewind will kill a delay. for (var i in ints){ if(ints[i] != undefined) { if ((ints[i].mc == mc || all)) { if (ints[i].mc._x!=undefined) { // be sure clip still exists addTween.apply(this, ints[i].args); } removeDelayedTween(Number(i)); } } } update(); } public function isTweenPaused(mc:MovieClip, prop:String):Boolean { // -(MosesSupposes)- Returns false if mc/prop is not tweening. if (mc==undefined) return null; var allprops:Boolean = (prop==undefined); for (var i in tweenList){ var t = tweenList[i]; if(tweenList[i].mc == mc && (allprops || prop==t.pp || (prop=='_ct_' && t.ctm!=undefined))) { return Boolean(tweenList[i].pt != -1); } } // if pause was called during a delay prop string is ignored. for (var i in ints) { if (ints[i] != undefined && ints[i].mc == mc) { return Boolean(ints[i].pt != -1) } } return false; } public function pauseTween(mc:MovieClip, propsObj:Object):Void { //-(MosesSupposes)- var all:Boolean = (mc==undefined); if (all==false && isTweenPaused(mc)==true) return; var allprops:Boolean = (propsObj==undefined); for (var i in tweenList){ var t = tweenList[i]; if(t.pt == -1 && (t.mc == mc || all) && (allprops || propsObj[t.pp]==true || (propsObj._ct_!=undefined && t.ctm!=undefined))) { t.pt = now; } } // you can pause a tween during a delay, but not pause/unpause individual props. for (var i in ints){ if(ints[i] != undefined) { if (ints[i].pt == -1 && (ints[i].mc == mc || all)) { ints[i].pt = now; } } } } public function unpauseTween(mc:MovieClip, propsObj:Object):Void { //-(MosesSupposes)- var all:Boolean = (mc==undefined); if (all==false && isTweenPaused(mc)===false) return; var allprops:Boolean = (propsObj==undefined); if (!playing) init(); for (var i in tweenList){ var t = tweenList[i]; if(t.pt != -1 && (t.mc == mc || all) && (allprops || propsObj[t.pp]==true) || (propsObj._ct_!=undefined && t.ctm!=undefined)) { // update start times t.ts = now-(t.pt-t.ts); t.pt = -1; } } // you can pause a tween during a delay, but not pause/unpause individual props. for (i in ints) { if(ints[i] != undefined) { if (ints[i].pt != -1 && (ints[i].mc == mc || all)) { // update start times ints[i].delay -= (ints[i].pt - ints[i].st); ints[i].st = now; ints[i].intid = setInterval(function(obj,id){ obj.addTween.apply(obj, obj.ints[id].args); clearInterval(obj.ints[id].intid); obj.ints[id] = undefined; },ints[i].delay,this,i); } } } } public function pauseAll():Void { pauseTween(); // -(MosesSupposes)- modified this method. Original LZ code preserved in comment- /*if (isPaused){ return } isPaused = true pausedTime = now; // pause delayed for (var i in ints){ clearInterval(ints[i].intid) } deinit()*/ } public function unpauseAll():Void { unpauseTween(); // -(MosesSupposes)- modified this method. Original LZ code preserved in comment- /*if (!isPaused){ return } var i, t; isPaused = false init(); for (i in tweenList) { t = tweenList[i]; // update start times t.ts = now-(pausedTime-t.ts); } for (i in ints){ if (ints[i] == undefined){ continue } // var delay = ints[i].delay - (pausedTime - ints[i].st); var intid = setInterval(function(obj,id){ obj.addTween.apply(obj, obj.ints[id].args); clearInterval(obj.ints[id].intid); obj.ints[id] = undefined; },delay,this,i); // ints[i].intid = intid; ints[i].st = now; ints[i].delay = delay; // }*/ } public function stopAll():Void{ for (var i in ints){ removeDelayedTween(Number(i)); //-(MosesSupposes)- } // stop all running tweens tweenList = new Array(); deinit(); } public function toString():String{ return "[AS2 tweenManager 1.2.0]"; } }