1 /* 2 * Copyright © 2009 Apple Inc. All rights reserved. 3 */ 4 5 /* ==================== Constants ==================== */ 6 7 const TKAnimatorLinearType = 0; 8 const TKAnimatorSplinesType = 1; 9 const TKAnimatorInvalidArgsException = 2; 10 11 const TKAnimatorAnimationDidIterate = 'animationDidIterate'; 12 const TKAnimatorAnimationDidEnd = 'animationDidEnd'; 13 14 /* ==================== TKAnimator ==================== */ 15 16 function TKAnimator (duration, delegate, spline) { 17 // check validity of arguments number 18 // if (arguments.length != 2 && arguments.length != 3 && arguments.length != 7) { 19 // throw TKAnimatorInvalidArgsException; 20 // return false; 21 // } 22 // init some base properties 23 this.ready = false; 24 this.animating = false; 25 this.timer = null; 26 // handle arguments 27 this.duration = duration; // ms 28 this.delegate = delegate; 29 // check we have the required delegation method 30 // if (!TKUtils.objectHasMethod(this.delegate, TKAnimatorAnimationDidIterate)) { 31 // return; 32 // } 33 // handle splines arguments, if available 34 if (arguments.length >= 3) { 35 this.type = TKAnimatorSplinesType; 36 this.x1 = spline[0]; 37 this.y1 = spline[1]; 38 this.x2 = spline[2]; 39 this.y2 = spline[3]; 40 this.init(); 41 } 42 else { // linear animation 43 this.type = TKAnimatorLinearType; 44 } 45 this.ready = true; 46 }; 47 48 TKAnimator.prototype.init = function () { 49 // calculate the polynomial coefficients 50 this.cx = 3 * this.x1; 51 this.bx = 3 * (this.x2 - this.x1) - this.cx; 52 this.ax = 1 - this.cx - this.bx; 53 this.cy = 3 * this.y1; 54 this.by = 3 * (this.y2 - this.y1) - this.cy; 55 this.ay = 1 - this.cy - this.by; 56 // compute points 57 var numberOfPoints = (this.duration / 1000) * 240; 58 this.curve = new Array(numberOfPoints); 59 var dt = 1.0 / ( numberOfPoints - 1 ); 60 for (var i = 0; i < numberOfPoints; i++) { 61 var t = i * dt; 62 this.curve[i] = { 63 x : (this.ax * Math.pow(t, 3)) + (this.bx * Math.pow(t, 2)) + (this.cx * t), 64 y : (this.ay * Math.pow(t, 3)) + (this.by * Math.pow(t, 2)) + (this.cy * t) 65 }; 66 } 67 }; 68 69 TKAnimator.prototype.start = function () { 70 if (!this.ready) { 71 var _this = this; 72 this.timer = setTimeout(function () { _this.start() }, 0); 73 return; 74 } 75 this.animating = true; 76 this.lastIndex = 0; 77 this.startTime = (new Date()).getTime(); 78 this.iterate(); 79 }; 80 81 TKAnimator.prototype.stop = function () { 82 this.animating = false; 83 clearTimeout(this.timer); 84 }; 85 86 TKAnimator.prototype.iterate = function () { 87 var ellapsedTime = (new Date()).getTime() - this.startTime; 88 if (ellapsedTime < this.duration) { 89 var x = ellapsedTime / this.duration; 90 // handle splines case 91 if (this.type == TKAnimatorSplinesType) { 92 var y = 0; 93 for (var i = this.lastIndex; i < this.curve.length; i++) { 94 var point = this.curve[i]; 95 if (point.x >= x && i > 0) { 96 var previous_point = this.curve[i - 1]; 97 if ((x - previous_point.x) < (point.x - x)) { 98 this.lastIndex = i - 1; 99 y = previous_point.y; 100 } 101 else { 102 this.lastIndex = i; 103 y = point.y; 104 } 105 break; 106 } 107 } 108 } 109 this.delegate[TKAnimatorAnimationDidIterate]((this.type == TKAnimatorSplinesType) ? y : x); 110 var _this = this; 111 this.timer = setTimeout(function () { _this.iterate() }, 0); 112 } 113 else { 114 this.delegate[TKAnimatorAnimationDidIterate](1); 115 if (TKUtils.objectHasMethod(this.delegate, TKAnimatorAnimationDidEnd)) { 116 this.delegate[TKAnimatorAnimationDidEnd](); 117 } 118 this.animating = false; 119 } 120 }; 121 122 /* ==================== CLASS CREATION ==================== */ 123 124 TKClass(TKAnimator); 125