source: code/Website/open-flash-chart/caurina/transitions/Tweener.as@ 7849

Last change on this file since 7849 was 7849, checked in by dennisw, 15 years ago
File size: 40.8 KB
Line 
1/**
2 * Tweener
3 * Transition controller for movieclips, sounds, textfields and other objects
4 *
5 * @author Zeh Fernando, Nate Chatellier, Arthur Debert
6 * @version 1.26.62
7 */
8
9/*
10Licensed under the MIT License
11
12Copyright (c) 2006-2007 Zeh Fernando and Nate Chatellier
13
14Permission is hereby granted, free of charge, to any person obtaining a copy of
15this software and associated documentation files (the "Software"), to deal in
16the Software without restriction, including without limitation the rights to
17use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
18the Software, and to permit persons to whom the Software is furnished to do so,
19subject to the following conditions:
20
21The above copyright notice and this permission notice shall be included in all
22copies or substantial portions of the Software.
23
24THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
26FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
27COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
28IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
31http://code.google.com/p/tweener/
32http://code.google.com/p/tweener/wiki/License
33*/
34
35package caurina.transitions {
36
37 import flash.display.*;
38 import flash.events.Event;
39 import flash.utils.getTimer;
40
41 public class Tweener {
42
43 private static var __tweener_controller__:MovieClip; // Used to ensure the stage copy is always accessible (garbage collection)
44
45 private static var _engineExists:Boolean = false; // Whether or not the engine is currently running
46 private static var _inited:Boolean = false; // Whether or not the class has been initiated
47 private static var _currentTime:Number; // The current time. This is generic for all tweenings for a "time grid" based update
48
49 private static var _tweenList:Array; // List of active tweens
50
51 private static var _timeScale:Number = 1; // Time scale (default = 1)
52
53 private static var _transitionList:Object; // List of "pre-fetched" transition functions
54 private static var _specialPropertyList:Object; // List of special properties
55 private static var _specialPropertyModifierList:Object; // List of special property modifiers
56 private static var _specialPropertySplitterList:Object; // List of special property splitters
57
58
59 /**
60 * There's no constructor.
61 * @private
62 */
63 public function Tweener () {
64 trace ("Tweener is a static class and should not be instantiated.")
65 }
66
67 // ==================================================================================================================================
68 // TWEENING CONTROL functions -------------------------------------------------------------------------------------------------------
69
70 /**
71 * Adds a new tweening.
72 *
73 * @param (first-n param) Object Object that should be tweened: a movieclip, textfield, etc.. OR an array of objects
74 * @param (last param) Object Object containing the specified parameters in any order, as well as the properties that should be tweened and their values
75 * @param .time Number Time in seconds or frames for the tweening to take (defaults 2)
76 * @param .delay Number Delay time (defaults 0)
77 * @param .useFrames Boolean Whether to use frames instead of seconds for time control (defaults false)
78 * @param .transition String/Function Type of transition equation... (defaults to "easeoutexpo")
79 * @param .onStart Function * Direct property, See the TweenListObj class
80 * @param .onUpdate Function * Direct property, See the TweenListObj class
81 * @param .onComplete Function * Direct property, See the TweenListObj class
82 * @param .onOverwrite Function * Direct property, See the TweenListObj class
83 * @param .onStartParams Array * Direct property, See the TweenListObj class
84 * @param .onUpdateParams Array * Direct property, See the TweenListObj class
85 * @param .onCompleteParams Array * Direct property, See the TweenListObj class
86 * @param .onOverwriteParams Array * Direct property, See the TweenListObj class
87 * @param .rounded Boolean * Direct property, See the TweenListObj class
88 * @param .skipUpdates Number * Direct property, See the TweenListObj class
89 * @return Boolean TRUE if the tween was successfully added, FALSE if otherwise
90 */
91 public static function addTween (p_arg1:Object = null, p_arg2:Object = null):Boolean {
92 if (arguments.length < 2 || arguments[0] == undefined) return false;
93
94 var rScopes:Array = new Array(); // List of objects to tween
95 var i:Number, j:Number, istr:String, jstr:String;
96
97 if (arguments[0] is Array) {
98 // The first argument is an array
99 for (i = 0; i<arguments[0].length; i++) rScopes.push(arguments[0][i]);
100 } else {
101 // The first argument(s) is(are) object(s)
102 for (i = 0; i<arguments.length-1; i++) rScopes.push(arguments[i]);
103 }
104 // rScopes = arguments.concat().splice(1); // Alternate (should be tested for speed later)
105
106 // make properties chain ("inheritance")
107 var p_obj:Object = TweenListObj.makePropertiesChain(arguments[arguments.length-1]);
108
109 // Creates the main engine if it isn't active
110 if (!_inited) init();
111 if (!_engineExists || !Boolean(__tweener_controller__)) startEngine(); // Quick fix for Flash not resetting the vars on double ctrl+enter...
112
113 // Creates a "safer", more strict tweening object
114 var rTime:Number = (isNaN(p_obj.time) ? 0 : p_obj.time); // Real time
115 var rDelay:Number = (isNaN(p_obj.delay) ? 0 : p_obj.delay); // Real delay
116
117 // Creates the property list; everything that isn't a hardcoded variable
118 var rProperties:Array = new Array(); // array containing object { .name, .valueStart, .valueComplete }
119 var restrictedWords:Object = {time:true, delay:true, useFrames:true, skipUpdates:true, transition:true, onStart:true, onUpdate:true, onComplete:true, onOverwrite:true, rounded:true, onStartParams:true, onUpdateParams:true, onCompleteParams:true, onOverwriteParams:true};
120 var modifiedProperties:Object = new Object();
121 for (istr in p_obj) {
122 if (!restrictedWords[istr]) {
123 // It's an additional pair, so adds
124 if (_specialPropertySplitterList[istr]) {
125 // Special property splitter
126 var splitProperties:Array = _specialPropertySplitterList[istr].splitValues(p_obj[istr], _specialPropertySplitterList[istr].parameters);
127 for (i = 0; i < splitProperties.length; i++) {
128 rProperties[splitProperties[i].name] = {valueStart:undefined, valueComplete:splitProperties[i].value};
129 }
130 } else if (_specialPropertyModifierList[istr] != undefined) {
131 // Special property modifier
132 var tempModifiedProperties:Array = _specialPropertyModifierList[istr].modifyValues(p_obj[istr]);
133 for (i = 0; i < tempModifiedProperties.length; i++) {
134 modifiedProperties[tempModifiedProperties[i].name] = {modifierParameters:tempModifiedProperties[i].parameters, modifierFunction:_specialPropertyModifierList[istr].getValue};
135 }
136 } else {
137 // Regular property or special property, just add the property normally
138 rProperties[istr] = {valueStart:undefined, valueComplete:p_obj[istr]};
139 }
140 }
141 }
142
143 // Adds the modifiers to the list of properties
144 for (istr in modifiedProperties) {
145 if (rProperties[istr] != undefined) {
146 rProperties[istr].modifierParameters = modifiedProperties[istr].modifierParameters;
147 rProperties[istr].modifierFunction = modifiedProperties[istr].modifierFunction;
148 }
149
150 }
151
152 var rTransition:Function; // Real transition
153
154 if (typeof p_obj.transition == "string") {
155 // String parameter, transition names
156 var trans:String = p_obj.transition.toLowerCase();
157 rTransition = _transitionList[trans];
158 } else {
159 // Proper transition function
160 rTransition = p_obj.transition;
161 }
162 if (!Boolean(rTransition)) rTransition = _transitionList["easeoutexpo"];
163
164 var nProperties:Object;
165 var nTween:TweenListObj;
166 var myT:Number;
167
168 for (i = 0; i < rScopes.length; i++) {
169 // Makes a copy of the properties
170 nProperties = new Object();
171 for (istr in rProperties) {
172 nProperties[istr] = new PropertyInfoObj(rProperties[istr].valueStart, rProperties[istr].valueComplete, rProperties[istr].modifierFunction, rProperties[istr].modifierParameters);
173 }
174
175 nTween = new TweenListObj(
176 /* scope */ rScopes[i],
177 /* timeStart */ _currentTime + ((rDelay * 1000) / _timeScale),
178 /* timeComplete */ _currentTime + (((rDelay * 1000) + (rTime * 1000)) / _timeScale),
179 /* useFrames */ (p_obj.useFrames == true),
180 /* transition */ rTransition
181 );
182
183 nTween.properties = nProperties;
184 nTween.onStart = p_obj.onStart;
185 nTween.onUpdate = p_obj.onUpdate;
186 nTween.onComplete = p_obj.onComplete;
187 nTween.onOverwrite = p_obj.onOverwrite;
188 nTween.onError = p_obj.onError;
189 nTween.onStartParams = p_obj.onStartParams;
190 nTween.onUpdateParams = p_obj.onUpdateParams;
191 nTween.onCompleteParams = p_obj.onCompleteParams;
192 nTween.onOverwriteParams = p_obj.onOverwriteParams;
193 nTween.rounded = p_obj.rounded;
194 nTween.skipUpdates = p_obj.skipUpdates;
195
196 // Remove other tweenings that occur at the same time
197 removeTweensByTime(nTween.scope, nTween.properties, nTween.timeStart, nTween.timeComplete);
198
199 // And finally adds it to the list
200 _tweenList.push(nTween);
201
202 // Immediate update and removal if it's an immediate tween -- if not deleted, it executes at the end of this frame execution
203 if (rTime == 0 && rDelay == 0) {
204 myT = _tweenList.length-1;
205 updateTweenByIndex(myT);
206 removeTweenByIndex(myT);
207 }
208 }
209
210 return true;
211 }
212
213 // A "caller" is like this: [ | | | ||] got it? :)
214 // this function is crap - should be fixed later/extend on addTween()
215
216 /**
217 * Adds a new caller tweening.
218 *
219 * @param (first-n param) Object that should be tweened: a movieclip, textfield, etc.. OR an array of objects
220 * @param (last param) Object containing the specified parameters in any order, as well as the properties that should be tweened and their values
221 * @param .time Number Time in seconds or frames for the tweening to take (defaults 2)
222 * @param .delay Number Delay time (defaults 0)
223 * @param .count Number Number of times this caller should be called
224 * @param .transition String/Function Type of transition equation... (defaults to "easeoutexpo")
225 * @param .onStart Function Event called when tween starts
226 * @param .onUpdate Function Event called when tween updates
227 * @param .onComplete Function Event called when tween ends
228 * @param .waitFrames Boolean Whether to wait (or not) one frame for each call
229 * @return <code>true</code> if the tween was successfully added, <code>false</code> if otherwise.
230 */
231 public static function addCaller (p_arg1:Object = null, p_arg2:Object = null):Boolean {
232 if (arguments.length < 2 || arguments[0] == undefined) return false;
233
234 var rScopes:Array = new Array(); // List of objects to tween
235 var i:Number, j:Number;
236
237 if (arguments[0] is Array) {
238 // The first argument is an array
239 for (i = 0; i<arguments[0].length; i++) rScopes.push(arguments[0][i]);
240 } else {
241 // The first argument(s) is(are) object(s)
242 for (i = 0; i<arguments.length-1; i++) rScopes.push(arguments[i]);
243 }
244 // rScopes = arguments.concat().splice(1); // Alternate (should be tested for speed later)
245
246 var p_obj:Object = arguments[arguments.length-1];
247
248 // Creates the main engine if it isn't active
249 if (!_inited) init();
250 if (!_engineExists || !Boolean(__tweener_controller__)) startEngine(); // Quick fix for Flash not resetting the vars on double ctrl+enter...
251
252 // Creates a "safer", more strict tweening object
253 var rTime:Number = (isNaN(p_obj.time) ? 0 : p_obj.time); // Real time
254 var rDelay:Number = (isNaN(p_obj.delay) ? 0 : p_obj.delay); // Real delay
255
256 var rTransition:Function; // Real transition
257 if (typeof p_obj.transition == "string") {
258 // String parameter, transition names
259 var trans:String = p_obj.transition.toLowerCase();
260 rTransition = _transitionList[trans];
261 } else {
262 // Proper transition function
263 rTransition = p_obj.transition;
264 }
265 if (!Boolean(rTransition)) rTransition = _transitionList["easeoutexpo"];
266
267 var nTween:TweenListObj;
268 var myT:Number;
269 for (i = 0; i < rScopes.length; i++) {
270
271 nTween = new TweenListObj(
272 /* Scope */ rScopes[i],
273 /* TimeStart */ _currentTime + ((rDelay * 1000) / _timeScale),
274 /* TimeComplete */ _currentTime + (((rDelay * 1000) + (rTime * 1000)) / _timeScale),
275 /* UseFrames */ (p_obj.useFrames == true),
276 /* Transition */ rTransition
277 );
278
279 nTween.properties = null;
280 nTween.onStart = p_obj.onStart;
281 nTween.onUpdate = p_obj.onUpdate;
282 nTween.onComplete = p_obj.onComplete;
283 nTween.onOverwrite = p_obj.onOverwrite;
284 nTween.onStartParams = p_obj.onStartParams;
285 nTween.onUpdateParams = p_obj.onUpdateParams;
286 nTween.onCompleteParams = p_obj.onCompleteParams;
287 nTween.onOverwriteParams = p_obj.onOverwriteParams;
288 nTween.isCaller = true;
289 nTween.count = p_obj.count;
290 nTween.waitFrames = p_obj.waitFrames;
291
292 // And finally adds it to the list
293 _tweenList.push(nTween);
294
295 // Immediate update and removal if it's an immediate tween -- if not deleted, it executes at the end of this frame execution
296 if (rTime == 0 && rDelay == 0) {
297 myT = _tweenList.length-1;
298 updateTweenByIndex(myT);
299 removeTweenByIndex(myT);
300 }
301 }
302
303 return true;
304 }
305
306 /**
307 * Remove an specified tweening of a specified object the tweening list, if it conflicts with the given time.
308 *
309 * @param p_scope Object List of objects affected
310 * @param p_properties Object List of properties affected (PropertyInfoObj instances)
311 * @param p_timeStart Number Time when the new tween starts
312 * @param p_timeComplete Number Time when the new tween ends
313 * @return Boolean Whether or not it actually deleted something
314 */
315 public static function removeTweensByTime (p_scope:Object, p_properties:Object, p_timeStart:Number, p_timeComplete:Number):Boolean {
316 var removed:Boolean = false;
317 var removedLocally:Boolean;
318
319 var i:uint;
320 var tl:uint = _tweenList.length;
321 var pName:String;
322
323 for (i = 0; i < tl; i++) {
324 if (Boolean(_tweenList[i]) && p_scope == _tweenList[i].scope) {
325 // Same object...
326 if (p_timeComplete > _tweenList[i].timeStart && p_timeStart < _tweenList[i].timeComplete) {
327 // New time should override the old one...
328 removedLocally = false;
329 for (pName in _tweenList[i].properties) {
330 if (Boolean(p_properties[pName])) {
331 // Same object, same property
332 // Finally, remove this old tweening and use the new one
333 if (Boolean(_tweenList[i].onOverwrite)) {
334 try {
335 _tweenList[i].onOverwrite.apply(_tweenList[i].scope, _tweenList[i].onOverwriteParams);
336 } catch(e:Error) {
337 handleError(_tweenList[i], e, "onOverwrite");
338 }
339 }
340 _tweenList[i].properties[pName] = undefined;
341 delete _tweenList[i].properties[pName];
342 removedLocally = true;
343 removed = true;
344 }
345 }
346 if (removedLocally) {
347 // Verify if this can be deleted
348 if (AuxFunctions.getObjectLength(_tweenList[i].properties) == 0) removeTweenByIndex(i);
349 }
350 }
351 }
352 }
353
354 return removed;
355 }
356
357 /**
358 * Remove tweenings from a given object from the tweening list.
359 *
360 * @param p_tween Object Object that must have its tweens removed
361 * @param (2nd-last params) Object Property(ies) that must be removed
362 * @return Boolean Whether or not it successfully removed this tweening
363 */
364 public static function removeTweens (p_scope:Object, ...args):Boolean {
365 // Create the property list
366 var properties:Array = new Array();
367 var i:uint;
368 for (i = 0; i < args.length; i++) {
369 if (typeof(args[i]) == "string" && !AuxFunctions.isInArray(args[i], properties)) properties.push(args[i]);
370 }
371 // Call the affect function on the specified properties
372 return affectTweens(removeTweenByIndex, p_scope, properties);
373 }
374
375
376 /**
377 * Remove all tweenings from the engine.
378 *
379 * @return <code>true</code> if it successfully removed any tweening, <code>false</code> if otherwise.
380 */
381 public static function removeAllTweens ():Boolean {
382 if (!Boolean(_tweenList)) return false;
383 var removed:Boolean = false;
384 var i:uint;
385 for (i = 0; i<_tweenList.length; i++) {
386 removeTweenByIndex(i);
387 removed = true;
388 }
389 return removed;
390 }
391
392 /**
393 * Pause tweenings for a given object.
394 *
395 * @param p_scope Object that must have its tweens paused
396 * @param (2nd-last params) Property(ies) that must be paused
397 * @return <code>true</code> if it successfully paused any tweening, <code>false</code> if otherwise.
398 */
399 public static function pauseTweens (p_scope:Object, ...args):Boolean {
400 // Create the property list
401 var properties:Array = new Array();
402 var i:uint;
403 for (i = 0; i < args.length; i++) {
404 if (typeof(args[i]) == "string" && !AuxFunctions.isInArray(args[i], properties)) properties.push(args[i]);
405 }
406 // Call the affect function on the specified properties
407 return affectTweens(pauseTweenByIndex, p_scope, properties);
408 }
409
410 /**
411 * Pause all tweenings on the engine.
412 *
413 * @return <code>true</code> if it successfully paused any tweening, <code>false</code> if otherwise.
414 * @see #resumeAllTweens()
415 */
416 public static function pauseAllTweens ():Boolean {
417 if (!Boolean(_tweenList)) return false;
418 var paused:Boolean = false;
419 var i:uint;
420 for (i = 0; i < _tweenList.length; i++) {
421 pauseTweenByIndex(i);
422 paused = true;
423 }
424 return paused;
425 }
426
427 /**
428 * Resume tweenings from a given object.
429 *
430 * @param p_scope Object Object that must have its tweens resumed
431 * @param (2nd-last params) Object Property(ies) that must be resumed
432 * @return Boolean Whether or not it successfully resumed something
433 */
434 public static function resumeTweens (p_scope:Object, ...args):Boolean {
435 // Create the property list
436 var properties:Array = new Array();
437 var i:uint;
438 for (i = 0; i < args.length; i++) {
439 if (typeof(args[i]) == "string" && !AuxFunctions.isInArray(args[i], properties)) properties.push(args[i]);
440 }
441 // Call the affect function on the specified properties
442 return affectTweens(resumeTweenByIndex, p_scope, properties);
443 }
444
445 /**
446 * Resume all tweenings on the engine.
447 *
448 * @return <code>true</code> if it successfully resumed any tweening, <code>false</code> if otherwise.
449 * @see #pauseAllTweens()
450 */
451 public static function resumeAllTweens ():Boolean {
452 if (!Boolean(_tweenList)) return false;
453 var resumed:Boolean = false;
454 var i:uint;
455 for (i = 0; i < _tweenList.length; i++) {
456 resumeTweenByIndex(i);
457 resumed = true;
458 }
459 return resumed;
460 }
461
462 /**
463 * Do some generic action on specific tweenings (pause, resume, remove, more?)
464 *
465 * @param p_function Function Function to run on the tweenings that match
466 * @param p_scope Object Object that must have its tweens affected by the function
467 * @param p_properties Array Array of strings that must be affected
468 * @return Boolean Whether or not it successfully affected something
469 */
470 private static function affectTweens (p_affectFunction:Function, p_scope:Object, p_properties:Array):Boolean {
471 var affected:Boolean = false;
472 var i:uint;
473
474 if (!Boolean(_tweenList)) return false;
475
476 for (i = 0; i < _tweenList.length; i++) {
477 if (_tweenList[i] && _tweenList[i].scope == p_scope) {
478 if (p_properties.length == 0) {
479 // Can affect everything
480 p_affectFunction(i);
481 affected = true;
482 } else {
483 // Must check whether this tween must have specific properties affected
484 var affectedProperties:Array = new Array();
485 var j:uint;
486 for (j = 0; j < p_properties.length; j++) {
487 if (Boolean(_tweenList[i].properties[p_properties[j]])) {
488 affectedProperties.push(p_properties[j]);
489 }
490 }
491 if (affectedProperties.length > 0) {
492 // This tween has some properties that need to be affected
493 var objectProperties:uint = AuxFunctions.getObjectLength(_tweenList[i].properties);
494 if (objectProperties == affectedProperties.length) {
495 // The list of properties is the same as all properties, so affect it all
496 p_affectFunction(i);
497 affected = true;
498 } else {
499 // The properties are mixed, so split the tween and affect only certain specific properties
500 var slicedTweenIndex:uint = splitTweens(i, affectedProperties);
501 p_affectFunction(slicedTweenIndex);
502 affected = true;
503 }
504 }
505 }
506 }
507 }
508 return affected;
509 }
510
511 /**
512 * Splits a tweening in two
513 *
514 * @param p_tween Number Object that must have its tweens split
515 * @param p_properties Array Array of strings containing the list of properties that must be separated
516 * @return Number The index number of the new tween
517 */
518 public static function splitTweens (p_tween:Number, p_properties:Array):uint {
519 // First, duplicates
520 var originalTween:TweenListObj = _tweenList[p_tween];
521 var newTween:TweenListObj = originalTween.clone(false);
522
523 // Now, removes tweenings where needed
524 var i:uint;
525 var pName:String;
526
527 // Removes the specified properties from the old one
528 for (i = 0; i < p_properties.length; i++) {
529 pName = p_properties[i];
530 if (Boolean(originalTween.properties[pName])) {
531 originalTween.properties[pName] = undefined;
532 delete originalTween.properties[pName];
533 }
534 }
535
536 // Removes the unspecified properties from the new one
537 var found:Boolean;
538 for (pName in newTween.properties) {
539 found = false;
540 for (i = 0; i < p_properties.length; i++) {
541 if (p_properties[i] == pName) {
542 found = true;
543 break;
544 }
545 }
546 if (!found) {
547 newTween.properties[pName] = undefined;
548 delete newTween.properties[pName];
549 }
550 }
551
552 // If there are empty property lists, a cleanup is done on the next updateTweens() cycle
553 _tweenList.push(newTween);
554 return (_tweenList.length - 1);
555
556 }
557
558 // ==================================================================================================================================
559 // ENGINE functions -----------------------------------------------------------------------------------------------------------------
560
561 /**
562 * Updates all existing tweenings.
563 *
564 * @return Boolean FALSE if no update was made because there's no tweening (even delayed ones)
565 */
566 private static function updateTweens ():Boolean {
567 if (_tweenList.length == 0) return false;
568 var i:int;
569 for (i = 0; i < _tweenList.length; i++) {
570 // Looping throught each Tweening and updating the values accordingly
571 if (_tweenList[i] == undefined || !_tweenList[i].isPaused) {
572 if (!updateTweenByIndex(i)) removeTweenByIndex(i);
573 if (_tweenList[i] == null) {
574 removeTweenByIndex(i, true);
575 i--;
576 }
577 }
578 }
579
580 return true;
581 }
582
583 /**
584 * Remove a specific tweening from the tweening list.
585 *
586 * @param p_tween Number Index of the tween to be removed on the tweenings list
587 * @return Boolean Whether or not it successfully removed this tweening
588 */
589 public static function removeTweenByIndex (i:Number, p_finalRemoval:Boolean = false):Boolean {
590 _tweenList[i] = null;
591 if (p_finalRemoval) _tweenList.splice(i, 1);
592 return true;
593 }
594
595 /**
596 * Pauses a specific tween.
597 *
598 * @param p_tween Number Index of the tween to be paused
599 * @return Boolean Whether or not it successfully paused this tweening
600 */
601 public static function pauseTweenByIndex (p_tween:Number):Boolean {
602 var tTweening:TweenListObj = _tweenList[p_tween]; // Shortcut to this tweening
603 if (tTweening == null || tTweening.isPaused) return false;
604 tTweening.timePaused = _currentTime;
605 tTweening.isPaused = true;
606
607 return true;
608 }
609
610 /**
611 * Resumes a specific tween.
612 *
613 * @param p_tween Number Index of the tween to be resumed
614 * @return Boolean Whether or not it successfully resumed this tweening
615 */
616 public static function resumeTweenByIndex (p_tween:Number):Boolean {
617 var tTweening:TweenListObj = _tweenList[p_tween]; // Shortcut to this tweening
618 if (tTweening == null || !tTweening.isPaused) return false;
619 tTweening.timeStart += _currentTime - tTweening.timePaused;
620 tTweening.timeComplete += _currentTime - tTweening.timePaused;
621 tTweening.timePaused = undefined;
622 tTweening.isPaused = false;
623
624 return true;
625 }
626
627 /**
628 * Updates a specific tween.
629 *
630 * @param i Number Index (from the tween list) of the tween that should be updated
631 * @return Boolean FALSE if it's already finished and should be deleted, TRUE if otherwise
632 */
633 private static function updateTweenByIndex (i:Number):Boolean {
634
635 var tTweening:TweenListObj = _tweenList[i]; // Shortcut to this tweening
636
637 if (tTweening == null || !Boolean(tTweening.scope)) return false;
638
639 var isOver:Boolean = false; // Whether or not it's over the update time
640 var mustUpdate:Boolean; // Whether or not it should be updated (skipped if false)
641
642 var nv:Number; // New value for each property
643
644 var t:Number; // current time (frames, seconds)
645 var b:Number; // beginning value
646 var c:Number; // change in value
647 var d:Number; // duration (frames, seconds)
648
649 var pName:String; // Property name, used in loops
650
651 // Shortcut stuff for speed
652 var tScope:Object; // Current scope
653 var tProperty:Object; // Property being checked
654
655 if (_currentTime >= tTweening.timeStart) {
656 // Can already start
657
658 tScope = tTweening.scope;
659
660 if (tTweening.isCaller) {
661 // It's a 'caller' tween
662 do {
663 t = ((tTweening.timeComplete - tTweening.timeStart)/tTweening.count) * (tTweening.timesCalled+1);
664 b = tTweening.timeStart;
665 c = tTweening.timeComplete - tTweening.timeStart;
666 d = tTweening.timeComplete - tTweening.timeStart;
667 nv = tTweening.transition(t, b, c, d);
668
669 if (_currentTime >= nv) {
670 if (Boolean(tTweening.onUpdate)) {
671 try {
672 tTweening.onUpdate.apply(tScope, tTweening.onUpdateParams);
673 } catch(e:Error) {
674 handleError(tTweening, e, "onUpdate");
675 }
676 }
677
678 tTweening.timesCalled++;
679 if (tTweening.timesCalled >= tTweening.count) {
680 isOver = true;
681 break;
682 }
683 if (tTweening.waitFrames) break;
684 }
685
686 } while (_currentTime >= nv);
687 } else {
688 // It's a normal transition tween
689
690 mustUpdate = tTweening.skipUpdates < 1 || !tTweening.skipUpdates || tTweening.updatesSkipped >= tTweening.skipUpdates;
691
692 if (_currentTime >= tTweening.timeComplete) {
693 isOver = true;
694 mustUpdate = true;
695 }
696
697 if (!tTweening.hasStarted) {
698 // First update, read all default values (for proper filter tweening)
699 if (Boolean(tTweening.onStart)) {
700 try {
701 tTweening.onStart.apply(tScope, tTweening.onStartParams);
702 } catch(e:Error) {
703 handleError(tTweening, e, "onStart");
704 }
705 }
706 for (pName in tTweening.properties) {
707 var pv:Number = getPropertyValue (tScope, pName);
708 tTweening.properties[pName].valueStart = isNaN(pv) ? tTweening.properties[pName].valueComplete : pv;
709 }
710 mustUpdate = true;
711 tTweening.hasStarted = true;
712 }
713
714 if (mustUpdate) {
715 for (pName in tTweening.properties) {
716 tProperty = tTweening.properties[pName];
717
718 if (isOver) {
719 // Tweening time has finished, just set it to the final value
720 nv = tProperty.valueComplete;
721 } else {
722 if (tProperty.hasModifier) {
723 // Modified
724 t = _currentTime - tTweening.timeStart;
725 d = tTweening.timeComplete - tTweening.timeStart;
726 nv = tTweening.transition(t, 0, 1, d);
727 nv = tProperty.modifierFunction(tProperty.valueStart, tProperty.valueComplete, nv, tProperty.modifierParameters);
728 } else {
729 // Normal update
730 t = _currentTime - tTweening.timeStart;
731 b = tProperty.valueStart;
732 c = tProperty.valueComplete - tProperty.valueStart;
733 d = tTweening.timeComplete - tTweening.timeStart;
734 nv = tTweening.transition(t, b, c, d);
735 }
736 }
737
738 if (tTweening.rounded) nv = Math.round(nv);
739 setPropertyValue(tScope, pName, nv);
740 }
741
742 tTweening.updatesSkipped = 0;
743
744 if (Boolean(tTweening.onUpdate)) {
745 try {
746 tTweening.onUpdate.apply(tScope, tTweening.onUpdateParams);
747 } catch(e:Error) {
748 handleError(tTweening, e, "onUpdate");
749 }
750 }
751 } else {
752 tTweening.updatesSkipped++;
753 }
754 }
755
756 if (isOver && Boolean(tTweening.onComplete)) {
757 try {
758 tTweening.onComplete.apply(tScope, tTweening.onCompleteParams);
759 } catch(e:Error) {
760 handleError(tTweening, e, "onComplete");
761 }
762 }
763
764 return (!isOver);
765 }
766
767 // On delay, hasn't started, so returns true
768 return (true);
769
770 }
771
772 /**
773 * Initiates the Tweener--should only be ran once.
774 */
775 public static function init(p_object:* = null):void {
776 _inited = true;
777
778 // Registers all default equations
779 _transitionList = new Object();
780 Equations.init();
781
782 // Registers all default special properties
783 _specialPropertyList = new Object();
784 _specialPropertyModifierList = new Object();
785 _specialPropertySplitterList = new Object();
786 SpecialPropertiesDefault.init();
787 }
788
789 /**
790 * Adds a new function to the available transition list "shortcuts".
791 *
792 * @param p_name String Shorthand transition name
793 * @param p_function Function The proper equation function
794 */
795 public static function registerTransition(p_name:String, p_function:Function): void {
796 if (!_inited) init();
797 _transitionList[p_name] = p_function;
798 }
799
800 /**
801 * Adds a new special property to the available special property list.
802 *
803 * @param p_name Name of the "special" property.
804 * @param p_getFunction Function that gets the value.
805 * @param p_setFunction Function that sets the value.
806 */
807 public static function registerSpecialProperty(p_name:String, p_getFunction:Function, p_setFunction:Function, p_parameters:Array = null): void {
808 if (!_inited) init();
809 var sp:SpecialProperty = new SpecialProperty(p_getFunction, p_setFunction, p_parameters);
810 _specialPropertyList[p_name] = sp;
811 }
812
813 /**
814 * Adds a new special property modifier to the available modifier list.
815 *
816 * @param p_name Name of the "special" property modifier.
817 * @param p_modifyFunction Function that modifies the value.
818 * @param p_getFunction Function that gets the value.
819 */
820 public static function registerSpecialPropertyModifier(p_name:String, p_modifyFunction:Function, p_getFunction:Function): void {
821 if (!_inited) init();
822 var spm:SpecialPropertyModifier = new SpecialPropertyModifier(p_modifyFunction, p_getFunction);
823 _specialPropertyModifierList[p_name] = spm;
824 }
825
826 /**
827 * Adds a new special property splitter to the available splitter list.
828 *
829 * @param p_name Name of the "special" property splitter.
830 * @param p_splitFunction Function that splits the value.
831 */
832 public static function registerSpecialPropertySplitter(p_name:String, p_splitFunction:Function, p_parameters:Array = null): void {
833 if (!_inited) init();
834 var sps:SpecialPropertySplitter = new SpecialPropertySplitter(p_splitFunction, p_parameters);
835 _specialPropertySplitterList[p_name] = sps;
836 }
837
838 /**
839 * Starts the Tweener class engine. It is supposed to be running every time a tween exists.
840 */
841 private static function startEngine():void {
842 _engineExists = true;
843 _tweenList = new Array();
844
845 __tweener_controller__ = new MovieClip();
846 __tweener_controller__.addEventListener(Event.ENTER_FRAME, Tweener.onEnterFrame);
847
848 updateTime();
849 }
850
851 /**
852 * Stops the Tweener class engine.
853 */
854 private static function stopEngine():void {
855 _engineExists = false;
856 _tweenList = null;
857 _currentTime = 0;
858 __tweener_controller__.removeEventListener(Event.ENTER_FRAME, Tweener.onEnterFrame);
859 __tweener_controller__ = null;
860 }
861
862 /**
863 * Gets a property value from an object.
864 *
865 * @param p_obj Object Any given object
866 * @param p_prop String The property name
867 * @return Number The value
868 */
869 private static function getPropertyValue(p_obj:Object, p_prop:String):Number {
870 if (_specialPropertyList[p_prop] != undefined) {
871 // Special property
872 if (Boolean(_specialPropertyList[p_prop].parameters)) {
873 // Uses additional parameters
874 return _specialPropertyList[p_prop].getValue(p_obj, _specialPropertyList[p_prop].parameters);
875 } else {
876 // Doesn't use additional parameters
877 return _specialPropertyList[p_prop].getValue(p_obj);
878 }
879 } else {
880 // Regular property
881 return p_obj[p_prop];
882 }
883 }
884
885 /**
886 * Sets the value of an object property.
887 *
888 * @param p_obj Object Any given object
889 * @param p_prop String The property name
890 * @param p_value Number The new value
891 */
892 private static function setPropertyValue(p_obj:Object, p_prop:String, p_value:Number): void {
893 if (_specialPropertyList[p_prop] != undefined) {
894 // Special property
895 if (Boolean(_specialPropertyList[p_prop].parameters)) {
896 // Uses additional parameters
897 _specialPropertyList[p_prop].setValue(p_obj, p_value, _specialPropertyList[p_prop].parameters);
898 } else {
899 // Doesn't use additional parameters
900 _specialPropertyList[p_prop].setValue(p_obj, p_value);
901 }
902 } else {
903 // Regular property
904 p_obj[p_prop] = p_value;
905 }
906 }
907
908 /**
909 * Updates the time to enforce time grid-based updates.
910 */
911 public static function updateTime():void {
912 _currentTime = getTimer();
913 }
914
915 /**
916 * Ran once every frame. It's the main engine; updates all existing tweenings.
917 */
918 public static function onEnterFrame(e:Event):void {
919 updateTime();
920 var hasUpdated:Boolean = false;
921 hasUpdated = updateTweens();
922 if (!hasUpdated) stopEngine(); // There's no tweening to update or wait, so it's better to stop the engine
923 }
924
925 /**
926 * Sets the new time scale.
927 *
928 * @param p_time Number New time scale (0.5 = slow, 1 = normal, 2 = 2x fast forward, etc)
929 */
930 public static function setTimeScale(p_time:Number):void {
931 var i:Number;
932
933 if (isNaN(p_time)) p_time = 1;
934 if (p_time < 0.00001) p_time = 0.00001;
935 if (p_time != _timeScale) {
936 if (_tweenList != null) {
937 // Multiplies all existing tween times accordingly
938 for (i = 0; i<_tweenList.length; i++) {
939 _tweenList[i].timeStart = _currentTime - ((_currentTime - _tweenList[i].timeStart) * _timeScale / p_time);
940 _tweenList[i].timeComplete = _currentTime - ((_currentTime - _tweenList[i].timeComplete) * _timeScale / p_time);
941 if (_tweenList[i].timePaused != undefined) _tweenList[i].timePaused = _currentTime - ((_currentTime - _tweenList[i].timePaused) * _timeScale / p_time);
942 }
943 }
944 // Sets the new timescale value (for new tweenings)
945 _timeScale = p_time;
946 }
947 }
948
949
950 // ==================================================================================================================================
951 // AUXILIARY functions --------------------------------------------------------------------------------------------------------------
952
953 /**
954 * Finds whether or not an object has any tweening.
955 *
956 * @param p_scope Target object.
957 * @return <code>true</code> if there's a tweening occuring on this object (paused, delayed, or active), <code>false</code> if otherwise.
958 */
959 public static function isTweening (p_scope:Object):Boolean {
960 if (!Boolean(_tweenList)) return false;
961 var i:uint;
962
963 for (i = 0; i<_tweenList.length; i++) {
964 if (_tweenList[i].scope == p_scope) {
965 return true;
966 }
967 }
968 return false;
969 }
970
971 /**
972 * Returns an array containing a list of the properties being tweened for this object.
973 *
974 * @param p_scope Target object.
975 * @return Total number of properties being tweened (including delayed or paused tweens).
976 */
977 public static function getTweens (p_scope:Object):Array {
978 if (!Boolean(_tweenList)) return [];
979 var i:uint;
980 var pName:String;
981 var tList:Array = new Array();
982
983 for (i = 0; i<_tweenList.length; i++) {
984 if (_tweenList[i].scope == p_scope) {
985 for (pName in _tweenList[i].properties) tList.push(pName);
986 }
987 }
988 return tList;
989 }
990
991 /**
992 * Returns the number of properties being tweened for a given object.
993 *
994 * @param p_scope Target object.
995 * @return Total number of properties being tweened (including delayed or paused tweens).
996 */
997 public static function getTweenCount (p_scope:Object):Number {
998 if (!Boolean(_tweenList)) return 0;
999 var i:uint;
1000 var c:Number = 0;
1001
1002 for (i = 0; i<_tweenList.length; i++) {
1003 if (_tweenList[i].scope == p_scope) {
1004 c += AuxFunctions.getObjectLength(_tweenList[i].properties);
1005 }
1006 }
1007 return c;
1008 }
1009
1010
1011 /* Handles errors when Tweener executes any callbacks (onStart, onUpdate, etc)
1012 * If the TweenListObj specifies an <code>onError</code> callback it well get called, passing the <code>Error</code> object and the current scope as parameters. If no <code>onError</code> callback is specified, it will trace a stackTrace.
1013 */
1014 private static function handleError(pTweening : TweenListObj, pError : Error, pCallBackName : String) : void{
1015 // do we have an error handler?
1016 if (Boolean(pTweening.onError) && (pTweening.onError is Function)){
1017 // yup, there's a handler. Wrap this in a try catch in case the onError throws an error itself.
1018 try{
1019 pTweening.onError.apply(pTweening.scope, [pTweening.scope, pError]);
1020 }catch (metaError : Error){
1021 trace("## [Tweener] Error:", pTweening.scope, "raised an error while executing the 'onError' handler. Original error:\n", pError.getStackTrace() , "\nonError error:", metaError.getStackTrace());
1022 }
1023 }else{
1024 // o handler, simply trace the stack trace:
1025 if (!Boolean(pTweening.onError)){
1026 trace("## [Tweener] Error: :", pTweening.scope, "raised an error while executing the'" + pCallBackName + "'handler. \n", pError.getStackTrace() );
1027 }
1028 }
1029 }
1030
1031
1032 /**
1033 * Returns the current tweener version.
1034 * @return The identification string of the current Tweener version, composed of an identification of the platform version ("AS2", "AS2_FL7", or "AS3") followed by space and then the version number.
1035 * @example The following code returns the current used version of Tweener:
1036 * <listing version="3.0">
1037 * import caurina.transitions.Tweener;
1038 *
1039 * var tVersion:String = Tweener.getVersion();
1040 * trace ("Using Tweener version " + tVersion + "."); // Outputs: "Using Tweener version AS3 1.24.47."</listing>
1041 */
1042 public static function getVersion ():String {
1043 return "AS3 1.26.62";
1044 }
1045
1046
1047 // ==================================================================================================================================
1048 // DEBUG functions ------------------------------------------------------------------------------------------------------------------
1049
1050 /**
1051 * Lists all existing tweenings.
1052 *
1053 * @return A string containing the list of all tweenings that currently exist inside the engine.
1054 */
1055 public static function debug_getList():String {
1056 var ttl:String = "";
1057 var i:uint, k:uint;
1058 for (i = 0; i<_tweenList.length; i++) {
1059 ttl += "["+i+"] ::\n";
1060 for (k = 0; k<_tweenList[i].properties.length; k++) {
1061 ttl += " " + _tweenList[i].properties[k].name +" -> " + _tweenList[i].properties[k].valueComplete + "\n";
1062 }
1063 }
1064 return ttl;
1065 }
1066
1067 }
1068}
Note: See TracBrowser for help on using the repository browser.