6 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
\r
8 return k * ( 2 - k );
\r
12 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
\r
14 return Math.sqrt( 1 - ( --k * k ) );
\r
18 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
\r
21 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
\r
27 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
\r
28 return 7.5625 * k * k;
\r
29 } else if ( k < ( 2 / 2.75 ) ) {
\r
30 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
\r
31 } else if ( k < ( 2.5 / 2.75 ) ) {
\r
32 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
\r
34 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
\r
44 if ( k === 0 ) { return 0; }
\r
45 if ( k == 1 ) { return 1; }
\r
47 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
\r
52 // 新規アニメーションが追加された場合、
\r
53 // tree が dirty なら AFTER_COMMIT を待つ
\r
54 // 1) xnode の既存アニメーションとの親子関係の調査
\r
55 // 親なら -> 既存アニメーションの GPU レイヤー解除
\r
56 // 子なら -> GPU レイヤーを設定しない
\r
58 // 3) アニメーション完了後も GPU レイヤーはしばらく解除しない スクロール等の連続アニメーション時に GPU 転送時間で画面ががたつくから
\r
61 var X_Node_ANIMATIONS = [],
\r
62 X_Node_Anime_updateTimerID = 0,
\r
63 X_Node_Anime_needsDetection = false,
\r
64 X_Node_Anime_hasTransform = !!X_Node_CSS_VENDER_PREFIX[ 'transform' ],
\r
65 X_Node_Anime_translateZ = X_Node_CSS_VENDER_PREFIX[ 'perspective' ] && !X.UA.OperaMobile && !X.UA.OperaTablet ? ' translateZ(0)' : '',
\r
66 X_Node_Anime_hasTransition = !!X_Node_CSS_VENDER_PREFIX[ 'transitionDelay' ] && !X.UA.Opera, // Opera12(XP,8.1) 切った方がスムース
\r
67 X_Node_Anime_transitionProps = X_Node_Anime_hasTransform ? X_Node_CSS_VENDER_PREFIX[ 'transform' ] : 'left,top';
\r
69 Node.prototype.animate = function( start, dest, duration, easing, wait ){
\r
70 var obj = this._anime || ( this._anime = {} );
\r
72 obj.duration = X.Type.isFinite( duration ) && 0 <= duration ? duration : 500;
\r
73 obj.easing = ease[ easing ] || ease.circular;
\r
74 // 現在 GPUレイヤーのtop になっているか?将来については phase で判定
\r
75 obj.gpuParent = obj.gpuParent || false;
\r
76 obj.phase = duration === 0 ? 9 : 0; //
\r
77 obj.wait = X.Type.isFinite( wait ) ? wait : 1000;
\r
79 obj.startTime = X_Timer_now();
\r
80 obj.startX = start.x || 0;
\r
81 obj.startY = start.y || 0;
\r
82 obj.startA = 0 <= start.opacity && start.opacity <= 1 ? start.opacity : 1;
\r
84 obj.destTime = obj.startTime + obj.duration;
\r
85 obj.destX = dest.x || 0;
\r
86 obj.destY = dest.y || 0;
\r
87 obj.destA = 0 <= dest.opacity && dest.opacity <= 1 ? dest.opacity : 1;
\r
90 if( obj.gpuTimerID ){
\r
91 X.Timer.remove( obj.gpuTimerID );
\r
92 delete obj.gpuTimerID;
\r
95 X_Node_Anime_needsDetection = true;
\r
96 if( X_Node_Anime_hasTransition ){
\r
97 X_Node_Anime_reserveUpdate();
\r
99 X_Node_Anime_updateTimerID || ( X_Node_Anime_updateTimerID = X.Timer.requestFrame( X_Node_Anime_updateAnimationsNoTransition ) );
\r
102 X_Node_ANIMATIONS.indexOf( this ) === -1 &&
\r
103 ( X_Node_ANIMATIONS[ X_Node_ANIMATIONS.length ] = this );
\r
108 Node.prototype.stop = function(){
\r
109 var obj = this._anime;
\r
111 if( X_Node_Anime_hasTransition ){
\r
113 X_Node_Anime_needsDetection = true;
\r
114 X_Node_Anime_reserveUpdate();
\r
116 X_Node_ANIMATIONS.splice( X_Node_ANIMATIONS.indexOf( this ), 1 );
\r
117 obj.gpuTimerID && X.Timer.remove( obj.gpuTimerID );
\r
118 delete this._anime;
\r
123 function X_Node_Anime_reserveUpdate(){
\r
124 if( !X_Node_Anime_updateTimerID ){
\r
125 // Opera12 requestAnimationFrame では transition が動かない、、、
\r
126 X_Node_Anime_updateTimerID =
\r
128 X.Timer.once( 0, X_Node_Anime_updateAnimations ) :
\r
129 X.Timer.requestFrame( X_Node_Anime_updateAnimations );
\r
133 function X_Node_Anime_updateAnimations(){
\r
134 var i = X_Node_ANIMATIONS.length, ret, c = false;
\r
136 if( X_Node_Anime_needsDetection ) X_Node_Anime_detectAnimationlayers();
\r
139 xnode = X_Node_ANIMATIONS[ --i ];
\r
140 ret = X_Node_Anime_updateAnimation( xnode );
\r
141 if( ret === true ){
\r
142 X_Node_ANIMATIONS.splice( i, 1 );
\r
143 xnode._anime.gpuTimerID && X.Timer.remove( xnode._anime.gpuTimerID );
\r
144 delete xnode._anime;
\r
146 if( ret !== false ){
\r
151 X_Node_Anime_updateTimerID = 0;
\r
153 X_Node_Anime_reserveUpdate();
\r
157 // TODO X.Timer.requestFrame 経由の BEFORE_UPDATE で更新を行う
\r
158 function X_Node_Anime_detectAnimationlayers(){
\r
159 var i = X_Node_ANIMATIONS.length,
\r
161 j, xnode, parent, hasGPUChild, changed, remove;
\r
164 xnode = X_Node_ANIMATIONS[ --i ];
\r
165 parent = hasGPUChild = false;
\r
168 _xnode = X_Node_ANIMATIONS[ --j ];
\r
170 if( xnode.parent === _xnode.parent ){
\r
173 if( _xnode.contains( xnode ) ){
\r
174 if( _xnode._anime.phase === 3 || _xnode._anime.phase === 10 ){
\r
175 _xnode._anime.phase = 15;
\r
177 if( xnode._anime.gpuParent ){
\r
178 changed = parent = true;
\r
179 xnode._anime.phase = xnode._anime.phase === 2 ? 6 : 15;// GPU レイヤーの解除 > アニメーションは継続, すでに終了フェイズなら破棄
\r
181 if( [ 7, 8, 9, 13, 14 ].indexOf( xnode._anime.phase ) !== -1 ){// GPU レイヤーの中止
\r
182 changed = parent = true;
\r
183 xnode._anime.phase -= 8;
\r
187 if( xnode.contains( _xnode ) ){
\r
188 if( xnode._anime.phase === 3 || xnode._anime.phase === 10 ){
\r
189 xnode._anime.phase = 15;
\r
191 if( _xnode._anime.gpuParent ){
\r
192 changed = hasGPUChild = true;
\r
193 _xnode._anime.phase = _xnode._anime.phase === 2 ? 6 : 15;// GPU レイヤーの解除 > アニメーションは継続, すでに終了フェイズなら破棄
\r
195 if( [ 7, 8, 9, 13, 14 ].indexOf( _xnode._anime.phase ) !== -1 ){// GPU レイヤーの中止
\r
196 changed = hasGPUChild = true;
\r
197 _xnode._anime.phase -= 8;
\r
202 if( !parent && xnode._anime.phase !== 15 ){
\r
203 if( xnode._anime.phase === 0 ){
\r
205 changed = changed || !xnode._anime.gpuParent;
\r
206 xnode._anime.phase = hasGPUChild ? 7 : 8;// 非GPU -> GPU 子に GPU アニメをもつなら、タイミングをずらす。
\r
209 changed = changed || !xnode._anime.gpuParent;
\r
210 xnode._anime.phase = hasGPUChild ? 13 : 14;// 非GPU -> GPU 子に GPU アニメをもつなら、タイミングをずらす。
\r
215 X_Node_Anime_needsDetection = false;
\r
218 function X_Node_Anime_updateAnimation( xnode ){
\r
219 var obj = xnode._anime,
\r
223 case -1 :// 子の GPU レイヤー解除待ち
\r
227 case 0 : // 開始位置+アニメーションの設定
\r
229 X_Node_Anime_updatePosition( xnode, obj.startX, obj.startY, obj.startA, phase === 8 );
\r
233 case 9 : // 終了位置の設定
\r
234 obj.gpuParent = phase === 9;
\r
235 X_Node_Anime_updateTransition( xnode, obj.duration, obj.easing );
\r
236 X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, obj.gpuParent );
\r
244 case 3 : // アニメーションの解除
\r
245 X_Node_Anime_updateTransition( xnode, 0 );
\r
246 obj.phase = obj.gpuParent ? 10 : 4;
\r
250 // アニメーションは停止・GPU = false -> リストから削除
\r
251 obj.gpuParent = false;
\r
255 // アニメーションは停止・GPUレイヤーは解除していない(再アニメーションに備えて待機)
\r
256 if( !obj.gpuTimerID ){
\r
257 obj.gpuTimerID = X.Timer.once( obj.wait, xnode, X_Node_Anime_releaseGPULayer );
\r
267 // GPU レイヤーの変更> アニメーションは継続,但し残り時間が短ければ停止
\r
270 now = X_Timer_now();
\r
271 time = obj.duration - now + obj.startTime;
\r
273 X_Node_Anime_updateTransition( xnode, 0 );
\r
274 X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, phase === 14 );
\r
275 obj.phase = phase === 14 ? 10 : 4;
\r
277 current = X_Node_Anime_getComputedPosition( xnode );
\r
278 obj.startX = current.x;
\r
279 obj.startY = current.y;
\r
280 obj.startA = current.a;
\r
281 obj.duration = time;
\r
282 obj.startTime = now;
\r
283 //X_Node_Anime_updateTransition( xnode, time, obj.easing );
\r
284 X_Node_Anime_updatePosition( xnode, current.x, current.y, current.a, phase === 14 );
\r
285 obj.phase = phase === 14 ? 9 : 1;
\r
290 // GPU有効で停止(待機)している xnode の解除
\r
291 console.log( 'GPU有効で停止(待機)している xnode の解除' + xnode._tag + xnode.getOrder() );
\r
292 X_Node_Anime_updateTransition( xnode, 0 );
\r
293 X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, false );
\r
294 obj.gpuTimerID && X.Timer.remove( obj.gpuTimerID );
\r
297 case 99 : // stop() : アニメーションの中断して削除
\r
298 current = X_Node_Anime_getComputedPosition( xnode );
\r
300 X_Node_Anime_updateTransition( xnode, 0 );
\r
301 X_Node_Anime_updatePosition( xnode, current.x, current.y, current.a, obj.gpuParent );
\r
302 obj.phase = obj.gpuParent ? 10 : 4;
\r
308 function X_Node_Anime_getComputedPosition( that ) {
\r
309 var matrix = X_node_CSS_getComputedStyle( that._rawObject, null ),
\r
312 if ( X_Node_Anime_hasTransform ) {
\r
313 matrix = matrix[ X_Node_CSS_VENDER_PREFIX[ 'transform' ] ].split( ')' )[ 0 ].split( ', ' );
\r
314 x = + ( matrix[ 12 ] || matrix[ 4 ] );
\r
315 y = + ( matrix[ 13 ] || matrix[ 5 ] );
\r
317 x = + parseInt( matrix.left );
\r
318 y = + parseInt( matrix.top );
\r
321 return { x: x, y: y, a : matrix[ X_Node_CSS_Support[ 'opacity' ] ] };
\r
324 function X_Node_Anime_onTransitionEnd(){
\r
325 this._anime.phase = 3;
\r
326 X_Node_Anime_needsDetection = true;
\r
327 X_Node_Anime_reserveUpdate();
\r
329 return X.Callback.UN_LISTEN | X.Callback.PREVENT_DEFAULT;
\r
332 function X_Node_Anime_releaseGPULayer(){
\r
333 var obj = this._anime;
\r
334 X_Node_Anime_updatePosition( this, obj.destX, obj.destY, obj.destA, false );
\r
335 X_Node_ANIMATIONS.splice( X_Node_ANIMATIONS.indexOf( this ), 1 );
\r
336 delete obj.gpuTimerID;
\r
337 delete this._anime;
\r
338 console.log( 'GPUレイヤーの破棄' );
\r
341 function X_Node_Anime_updateTransition( xnode, time, easing ){
\r
343 // アニメーション指定のセット(または解除)(対象のみ)
\r
346 xnode.listenOnce( 'transitionend', X_Node_Anime_onTransitionEnd );
\r
348 xnode.unlisten( 'transitionend', X_Node_Anime_onTransitionEnd );
\r
351 transitionProperty : X_Node_Anime_transitionProps + ',opacity',
\r
352 willChange : time ? X_Node_Anime_transitionProps + ',opacity' : '',
\r
353 backfaceVisibility : time ? 'hidden' : '',
\r
354 transitionTimingFunction : time ? easing.style : '',
\r
355 transitionDelay : '0s',
\r
356 transitionDuration : time ? time + 'ms' : ''
\r
360 function X_Node_Anime_updatePosition( xnode, x, y, opacity, useGPU ){
\r
361 if( X_Node_Anime_hasTransform ){
\r
363 transform : 'translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)' + ( useGPU ? X_Node_Anime_translateZ : '' ),
\r
368 left : ( x | 0 ) + 'px',
\r
369 top : ( y | 0 ) + 'px',
\r
373 // xnode._anime.x, y
\r
376 function X_Node_Anime_updateAnimationsNoTransition(){
\r
377 var i = X_Node_ANIMATIONS.length,
\r
378 now = X_Timer_now(),
\r
380 newX, newY, newA, easing,
\r
384 xnode = X_Node_ANIMATIONS[ --i ];
\r
385 obj = xnode._anime;
\r
387 if( obj.destTime <= now ){
\r
388 X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, false );
\r
389 xnode.asyncDispatch( 'transitionend' );
\r
391 X_Node_ANIMATIONS.splice( i, 1 );
\r
392 delete xnode._anime;
\r
394 easing = obj.easing.fn( ( now - obj.startTime ) / obj.duration );
\r
395 newX = ( obj.destX - obj.startX ) * easing + obj.startX;
\r
396 newY = ( obj.destY - obj.startY ) * easing + obj.startY;
\r
397 newA = ( obj.destA - obj.startA ) * easing + obj.startA;
\r
398 X_Node_Anime_updatePosition( xnode, newX, newY, newA, false );
\r
405 X_Node_Anime_updateTimerID = X.Timer.requestFrame( X_Node_Anime_updateAnimationsNoTransition );
\r
407 X_Node_Anime_updateTimerID = 0;
\r