1 // ======= ANIMATION ========== // 2 // Regexp used in this file 3 var REGEX_PIXEL = /px\s?$/, 4 ALLOW_TYPES = /padding|margin|height|width|top|left|right|bottom|fontSize/, 5 TIMER_ID; 6 /** 7 * @namespace Simples.Animation 8 * @description Animation controller if provide a standard animation object to this functionality it will execute the animation 9 */ 10 Simples.Animation = { 11 /* animations: currently active animations being run */ 12 animations : {}, 13 /* frameRate: global frame rate for animations */ 14 frameRate : 24, 15 /* length: count of current active animations */ 16 length : 0, 17 /** 18 * @namespace Simples.Animation.tweens 19 * @description default tweens for animation 20 */ 21 tweens : { 22 /** 23 * @param frame: current frame 24 * @param frameCount: total frames for animations 25 * @param start: start value for tween 26 * @param delta: difference to end value 27 */ 28 easing : function( frame, frameCount, start, delta ) { 29 return ((frame /= frameCount / 2) < 1) ? delta / 2 * frame * frame + start : -delta / 2 * ((--frame) * (frame - 2) - 1) + start; 30 }, 31 /** @see Simples.Animation.tweens.easing */ 32 linear : function( frame, frameCount, start, delta ){ 33 return start + ( delta * ( frame/frameCount )); 34 }, 35 /** @see Simples.Animation.tweens.easing */ 36 quadratic : function( frame, frameCount, start, delta ){ 37 return start + (((Math.cos((frame/frameCount)*Math.PI) )/2) * delta ); 38 } 39 }, 40 interval : Math.round( 1000 / this.frameRate ), 41 /** 42 * Simples.Animation.create: used to to create an animation object which can be used by the animation queue runner 43 * @param elem {Element} DOM Element to animate 44 * @param setStyle {Object} CSS to use in animation, final position 45 * @param opts {Object} 46 * @param opts.callback {Function} when animation complete 47 * @param opts.tween {Function} tween to use when animating 48 * @param opts.duration {Object} the time to elapse during animation 49 */ 50 create : function( elem, setStyle, opts ){ 51 opts = opts || {}; 52 if ( !( elem && elem.nodeType ) || Simples.isEmptyObject( setStyle ) ) { 53 if (typeof opts.callback === "function") { 54 opts.callback.call(elem); 55 } 56 return null; 57 } 58 59 var anim = { 60 0 : elem, 61 id : Simples.guid++, 62 callback : ( typeof opts.callback === "function" ) ? opts.callback : Simples.noop, 63 duration : ( typeof opts.duration === "number" && opts.duration > -1 ) ? opts.duration : 600, 64 tween : ( typeof opts.tween === "function" ) ? opts.tween : ( Simples.Animation.tweens[ opts.tween ] || Simples.Animation.tweens.easing ), 65 start : {}, 66 finish : {} 67 }; 68 69 // check for supported css animated features and prep for animation 70 for( var key in setStyle ){ 71 var cKey = key.replace( RDASH_ALPHA, fcamelCase ), 72 opacity = ( cKey === OPACITY && setStyle[ key ] >= 0 && setStyle[ key ] <= 1 ); 73 74 if( opacity || ALLOW_TYPES.test( cKey ) ){ 75 anim.start[ cKey ] = ( Simples.getStyle( elem, cKey ) + "" ).replace(REGEX_PIXEL,"") * 1; 76 anim.finish[ cKey ] = ( setStyle[ key ] + "" ).replace(REGEX_PIXEL,"") * 1; 77 } 78 } 79 80 var data = Simples.data(elem); 81 data.animations = data.animations || {}; 82 data.animations[ anim.id ] = anim; 83 84 if( opts.manualStart !== true ){ 85 Simples.Animation.start( anim ); 86 } 87 return anim; 88 }, 89 /** 90 * Simples.Animation.start: used to add the animation to the animation runner queue 91 * @param animation {Object} animation to perform action on 92 */ 93 start : function( animation ){ 94 95 if( animation && animation.id ){ 96 if( !hasOwn.call( this.animations, animation.id ) ){ 97 this.length++; 98 this.animations[ animation.id ] = animation; 99 if( animation.duration === 0 ){ 100 this.stop( animation ); 101 } else if( !animation.startTime ){ 102 animation.startTime = new Date().getTime(); 103 } 104 } 105 106 if( !TIMER_ID ){ 107 this.interval = Math.round( 1000/ this.frameRate ); 108 TIMER_ID = WIN.setInterval(function(){ Simples.Animation._step(); }, this.interval ); 109 } 110 } 111 }, 112 /** 113 * Simples.Animation.reverse: used to take an animation in its current position and reverse and run 114 * @param animation {Object} animation to perform action on 115 */ 116 reverse : function( animation ){ 117 var start = animation.start, finish = animation.finish; 118 119 animation.start = finish; 120 animation.finish = start; 121 122 if( this.animations[ animation.id ] && animation.startTime ){ 123 var now = new Date().getTime(), 124 diff = now - animation.startTime; 125 126 animation.startTime = now - ( animation.duration - diff ); 127 } else { 128 if( this.animations[ animation.id ] ){ 129 delete this.animations[ animation.id ]; 130 this.length--; 131 } 132 this.start( animation ); 133 } 134 }, 135 /** 136 * Simples.Animation.reset: used to reset an animation to either the start or finish position 137 * @param animation {Object} animation to perform action on 138 * @param resetToEnd {Boolean} whether to reset to finish (true) or start (false||undefined) state 139 */ 140 reset : function( animation, resetToEnd ){ 141 142 var cssObj = resetToEnd ? animation.finish : animation.start, 143 elem = animation[0]; 144 145 for( var name in cssObj ){ 146 Simples.setStyle( elem, name, cssObj[ name ] ); 147 } 148 149 if( animation.startTime ){ 150 this.stop( animation ); 151 } 152 }, 153 /** 154 * @private used by the queue runner to iterate over queued animations and update each postion 155 */ 156 _step : function(){ 157 if( this.length ){ 158 var now = new Date().getTime(); 159 for( var id in this.animations ){ 160 var anim = this.animations[ id ], 161 diff = now - anim.startTime, 162 elem = anim[0], 163 duration = anim.duration; 164 165 if ( diff > duration ) { 166 this.stop( anim, true ); 167 } else { 168 for( var name in anim.start ){ 169 var start = anim.start[ name ]; 170 Simples.setStyle( elem, name, anim.tween( diff, duration, start, anim.finish[ name ] - start ) ); 171 172 } 173 } 174 } 175 } else if( TIMER_ID ){ 176 WIN.clearInterval( TIMER_ID ); 177 TIMER_ID = null; 178 } 179 }, 180 /** 181 * Simples.Animation.stop: used to stop a supplied animation and cleanup after itsef 182 * @param animation {Object} the animation object to use and work on. 183 * @param jumpToEnd {Boolean} whether to leave in current position or set css to finish position 184 */ 185 stop : function( animation, jumpToEnd ){ 186 if( animation && hasOwn.call( this.animations, animation.id ) ){ 187 188 animation.startTime = null; 189 190 if ( jumpToEnd ){ 191 this.reset( animation, true ); 192 } 193 194 var data = Simples.data( animation[0] ); 195 data.animations = data.animations || {}; 196 delete data.animations[ animation.id ]; 197 198 animation.callback.call(animation[0], animation); 199 delete this.animations[ animation.id ]; 200 this.length--; 201 } 202 } 203 }; 204 205 Simples.extend( /** @lends Simples.fn */ { 206 /** 207 * @description From the instance of the Simples object used to bridge to the Simples.Animation functionality 208 * @param action {String} the name of the action to be performed - stop, start, reset, reverse; this is excluding create && _step 209 */ 210 animations: function(action) { 211 if( action != ("create" || "_step") && Simples.Animation[ action ] ){ 212 var i = this.length, 213 action = Simples.Animation[ action ]; 214 if( typeof action === "function" ){ 215 while (i) { 216 var anims = Simples.data( this[--i], "animation" ); 217 Simples.Animation[ action ]( anim, arguments[2] ); 218 } 219 } 220 } 221 return this; 222 }, 223 /** 224 * @description Used to create animations off the elements in the instance of the Simples object 225 * @param action {String} the name of the action to be performed, excluding create && _step 226 * @param css {Object} CSS to use in animation, final position 227 * @param opts {Object} 228 * @param opts.callback {Function} when animation complete 229 * @param opts.tween {Function} tween to use when animating 230 * @param opts.duration {Object} the time to elapse during animation 231 */ 232 animate: function(css, opts) { 233 var i = this.length; 234 while (i) { 235 Simples.Animation.create( this[--i], css, opts ); 236 } 237 return this; 238 } 239 });