2 var X_NodeAnime_QUEUE = [],
\r
4 X_NodeAnime_reserved = false,
\r
5 X_NodeAnime_updateTimerID = 0,
\r
6 X_NodeAnime_needsDetection = false,
\r
8 X_NodeAnime_hasTransform = !!X_Node_CSS_VENDER_PREFIX[ 'transform' ],
\r
10 X_NodeAnime_hasDXTransform = 5.5 <= X_UA[ 'IE' ] && X_UA[ 'IE' ] < 9 && X_UA[ 'ActiveX' ], // IEHost が 11 の場合不可
\r
12 /* Opera mobile で translateZ(0) が有効だと XY が 0 0 になる */
\r
13 /* GPUレイヤーにいる間に要素のコンテンツを変更をすると transitionend が動かなくなるっぽい Mac safari と firefox */
\r
14 X_NodeAnime_translateZ = X_Node_CSS_VENDER_PREFIX[ 'perspective' ] &&
\r
15 !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] &&
\r
16 !( X_UA[ 'IE' ] === 11 ) && !( X_UA[ 'IEHost' ] === 11 ) ? ' translateZ(0)' : '',
\r
30 X_NODE_ANIME_RESET = 1,
\r
31 X_NODE_ANIME_STAY_GPU = 2,
\r
33 X_NodeAnime_DEFAULT = {
\r
40 rotate : NaN, fromRotate : NaN, toRotate : NaN,
\r
41 skewX : NaN, fromSkewX : NaN, toSkewX : NaN,
\r
42 skewY : NaN, fromSkewY : NaN, toSkewY : NaN,
\r
43 scaleX : 1, fromScaleX : 1, toScaleX : 1,
\r
44 scaleY : 1, fromScaleY : 1, toScaleY : 1,
\r
46 scrollX : NaN, fromScrollX : NaN, toScrollX : NaN,
\r
47 scrollY : NaN, fromScrollY : NaN, toScrollY : NaN //,
\r
48 //doScroll : false//,
\r
50 //phase, lazyRelease, easing, follower, releaseNow, inited, progress, fallback
\r
55 * GPU サポートの効いたアニメーションの設定
\r
56 * <a href="https://outcloud.blogspot.jp/2015/12/pettanR-Node-Anime.html">ぺったんRフレームワークのアニメーションメソッド</a>
\r
57 * @alias Node.prototype.animate
\r
58 * @param {object} obj
\r
59 * @return {Node} メソッドチェーン
\r
65 * opacity : 0.0, //~1.0
\r
76 * to : {}, // from と同じ
\r
79 * easing : 'quadratic', // function, 'circular', 'back', 'bounce', 'elastic'
\r
80 * fallback : bitFlag // 16:DXTransform, 8:css-p, 4:zoom(s) > 2:fontSize(s) > 1:width&height(vh,s)
\r
81 * ** tree にいなくてもアニメーションを行いイベントを発生
\r
83 * fallbackWidth, fallbackHeight, transformOrigin( 0.5, 0.5 )
\r
86 function X_Node_animate( obj ){
\r
87 var list = X_NodeAnime_QUEUE,
\r
88 from = obj[ 'from' ] || {},
\r
89 dest = obj[ 'to' ] || {},
\r
90 duration = obj[ 'duration' ],
\r
91 lazyRelease = obj[ 'lazyRelease' ],
\r
92 easing = obj[ 'easing' ],
\r
93 fallback = obj[ 'fallback' ],
\r
96 obj = this[ '_anime' ];
\r
98 if( !( this[ '_flags' ] & X_NodeFlags_IN_TREE ) ){
\r
99 alert( '@animate 要素はツリーに追加されていません!' );
\r
100 // それでもアニメーションしてタイマー代わりにするとか、、、?
\r
105 this[ '_anime' ] = obj = X_Object_copy( X_NodeAnime_DEFAULT );
\r
106 a = this[ '_css' ] && parseFloat( this[ '_css' ].opacity );
\r
107 if( 0 <= a ) obj.alpha = a;
\r
111 obj.fromX = obj.x = X_NodeAnime_getFinite( from[ 'x' ], obj.x );
\r
112 obj.fromY = obj.y = X_NodeAnime_getFinite( from[ 'y' ], obj.y );
\r
113 obj.fromRotate = obj.rotate = X_NodeAnime_getFinite( from[ 'rotate' ], obj.rotate );
\r
114 obj.fromSkewX = obj.skewX = X_NodeAnime_getFinite( from[ 'skewX' ], from[ 'skew' ], obj.skewX );
\r
115 obj.fromSkewY = obj.skewY = X_NodeAnime_getFinite( from[ 'skewY' ], from[ 'skew' ], obj.skewY );
\r
116 obj.fromScaleX = obj.scaleX = X_NodeAnime_getFinite( from[ 'scaleX' ], from[ 'scale' ], obj.scaleX );
\r
117 obj.fromScaleY = obj.scaleY = X_NodeAnime_getFinite( from[ 'scaleY' ], from[ 'scale' ], obj.scaleY );
\r
118 obj.fromAlpha = obj.alpha = X_NodeAnime_getFinite( from[ 'opacity' ], obj.alpha );
\r
119 obj.fromScrollX = obj.scrollX = X_NodeAnime_getFinite( from[ 'scrollX' ], obj.scrollX );
\r
120 obj.fromScrollY = obj.scrollY = X_NodeAnime_getFinite( from[ 'scrollY' ], obj.scrollY );
\r
122 obj.toX = X_NodeAnime_getFinite( dest[ 'x' ], obj.x );
\r
123 obj.toY = X_NodeAnime_getFinite( dest[ 'y' ], obj.y );
\r
124 obj.toRotate = X_NodeAnime_getFinite( dest[ 'rotate' ], obj.rotate );
\r
125 obj.toSkewX = X_NodeAnime_getFinite( dest[ 'skewX' ], dest[ 'skew' ], obj.skewX );
\r
126 obj.toSkewY = X_NodeAnime_getFinite( dest[ 'skewY' ], dest[ 'skew' ], obj.skewY );
\r
127 obj.toScaleX = X_NodeAnime_getFinite( dest[ 'scaleX' ], dest[ 'scale' ], obj.scaleX );
\r
128 obj.toScaleY = X_NodeAnime_getFinite( dest[ 'scaleY' ], dest[ 'scale' ], obj.scaleY );
\r
129 obj.toAlpha = X_NodeAnime_getFinite( dest[ 'opacity' ], obj.alpha );
\r
130 obj.toScrollX = X_NodeAnime_getFinite( dest[ 'scrollX' ], obj.scrollX );
\r
131 obj.toScrollY = X_NodeAnime_getFinite( dest[ 'scrollY' ], obj.scrollY );
\r
133 if( X_Type_isFinite( obj.toX ) && X_Type_isNaN( obj.x ) ) obj.x = obj.fromX = 0;
\r
134 if( X_Type_isFinite( obj.toY ) && X_Type_isNaN( obj.y ) ) obj.y = obj.fromY = 0;
\r
136 if( obj.toRotate && X_Type_isNaN( obj.rotate ) ) obj.rotate = obj.fromRotate = 0;
\r
137 if( obj.toSkewX && X_Type_isNaN( obj.skewX ) ) obj.skewX = obj.fromSkewX = 0;
\r
138 if( obj.toSkewY && X_Type_isNaN( obj.skewY ) ) obj.skewY = obj.fromSkewY = 0;
\r
140 obj.duration = 0 <= duration && X_Type_isFinite( duration ) ? duration : 0;
\r
141 obj.lazyRelease = 0 <= lazyRelease && X_Type_isFinite( lazyRelease ) ? lazyRelease : 0;
\r
142 obj.easing = X_Type_isFunction( easing ) ? easing : X_NodeAnime_ease[ easing ] || X_NodeAnime_ease[ 'circular' ];
\r
143 obj.inited = false;
\r
144 obj.transform = ( X_Type_isFinite( obj.x ) || X_Type_isFinite( obj.y ) || obj.lazyRelease ) && X_NodeAnime_hasTransform;
\r
145 obj.doScroll = 0 <= obj.toScrollX || 0 <= obj.toScrollY;
\r
147 obj.altX = fallback & 8 ? 'right' : 'left';
\r
148 obj.altY = fallback & 16 ? 'bottom' : 'top';
\r
151 if( obj.toScaleX !== 1 || obj.fromScaleX !== 1 || obj.toScaleY !== 1 || obj.fromScaleY !== 1 ){
\r
152 sameRate = obj.fromScaleX === obj.fromScaleY && obj.toScaleX === obj.toScaleY;
\r
154 if( X_NodeAnime_hasTransform ){
\r
155 obj.transform = true;
\r
157 if( X_NodeAnime_hasDXTransform && ( fallback & 32 ) ){ // DX Transform
\r
160 if( ( fallback & 4 ) && sameRate ){ // zoom
\r
163 if( ( fallback & 2 ) && sameRate ){ // fontSize
\r
166 if( fallback & 1 ){ // width & height
\r
172 if( X_Type_isFinite( obj.rotate ) || X_Type_isFinite( obj.skewX ) || X_Type_isFinite( obj.skewY ) ){
\r
173 if( X_NodeAnime_hasTransform ){
\r
174 obj.transform = true;
\r
176 if( X_NodeAnime_hasDXTransform && ( fallback & 32 ) ){ // DX Transform
\r
181 if( !obj.duration && 6 <= obj.phase ){
\r
182 this[ 'stop' ](); // 現在値で停止
\r
185 list[ list.length ] = this;
\r
187 obj.uid = ++X_NodeAnime_uid;
\r
188 X_NodeAnime_needsDetection = true;
\r
190 if( obj.phase < 4 ){
\r
191 list.splice( list.indexOf( this ), 1 );
\r
192 list[ list.length ] = this;
\r
193 obj.uid = ++X_NodeAnime_uid;
\r
194 X_NodeAnime_needsDetection = true;
\r
196 if( obj.duration ){
\r
197 // リストの先頭にいるため検査不要でアニメーション開始可能 4, 5, 6, 7
\r
200 // GPU 転送予約、または transform や opacity の値のみ設定
\r
201 if( obj.phase !== 5 ){ // GPU解除待ち ではない -> 4. 6, 7
\r
202 obj.phase = 4; // 強制停止(GPU転送予約)または値のみ更新
\r
203 obj.releaseNow = false; // TODO folower がいるため GPU 転送できないケースあり
\r
204 X_NodeAnime_needsDetection = true;
\r
207 X_NodeAnime_needsDetection = true;
\r
210 if( !X_NodeAnime_reserved ){
\r
211 X_NodeAnime_reserved = true;
\r
213 if( X_Node_updateTimerID ){
\r
214 if( X_NodeAnime_updateTimerID ) X_NodeAnime_updateTimerID = X_Timer_cancelFrame( X_NodeAnime_updateTimerID );
\r
216 X_System[ 'listen' ]( X_EVENT_UPDATED, X_NodeAnime_updateAnimations );
\r
218 X_System[ 'unlisten' ]( X_EVENT_UPDATED, X_NodeAnime_updateAnimations );
\r
219 X_NodeAnime_updateTimerID = X_Timer_requestFrame( X_NodeAnime_updateAnimations );
\r
227 function X_NodeAnime_getFinite( a, b, c ){
\r
228 if( a || a === 0 ) return a;
\r
229 if( b || b === 0 ) return b;
\r
230 if( c || c === 0 ) return c;
\r
235 * 1.アニメーション中の要素の停止 ->後続アニメーションの開始
\r
236 * 2.アニメーション待機中の要素の停止 -> 後続アニメーションの再調査
\r
240 * @alias Node.prototype.stop
\r
241 * @return {Node} メソッドチェーン
\r
243 function X_Node_stop( option ){
\r
244 var obj = this[ '_anime' ],
\r
245 list = X_NodeAnime_QUEUE,
\r
248 if( !obj || !obj.phase ) return this;
\r
250 switch( obj.phase ){
\r
251 case 6 : // アニメーション開始可能 ??
\r
253 case 3 : // アニメーション待機中
\r
254 X_NodeAnime_needsDetection = true;
\r
258 case 4 : // 強制停止(GPU転送予約)
\r
259 case 7 : // アニメーション中
\r
260 if( option & X_NODE_ANIME_RESET ){
\r
261 X_Object_override( obj, X_NodeAnime_DEFAULT );
\r
262 }; // TODO 終了値で停止も,,,
\r
264 // obj.canceled = true;
\r
266 if( rm ) break; // 1,2,3,6 の場合ここまで
\r
270 obj.toRotate = obj.rotate;
\r
271 obj.toSkewX = obj.skewX;
\r
272 obj.toSkewY = obj.skewY;
\r
273 obj.toScaleX = obj.scaleX;
\r
274 obj.toScaleY = obj.scaleY;
\r
275 obj.toAlpha = obj.alpha;
\r
276 obj.toScrollX = obj.scrollX;
\r
277 obj.toScrollY = obj.scrollY;
\r
279 obj.phase = 4; // 強制解除
\r
280 X_NodeAnime_needsDetection = true;
\r
282 case 5 : // GPU解除待ち
\r
283 obj.releaseNow = !( option & X_NODE_ANIME_STAY_GPU );
\r
288 list.splice( list.indexOf( this ), 1 );
\r
295 * remove(append swap 等でない部的に呼ばれている場合も), kill 時に
\r
297 function X_NodeAnime_stopNow( xnode ){
\r
298 var obj = xnode[ '_anime' ],
\r
299 flags = xnode[ '_flags' ],
\r
300 list = X_NodeAnime_QUEUE,
\r
303 // if( !obj || !obj.phase ) return; 呼び出し側で検証済
\r
305 X_NodeAnime_needsDetection = true;
\r
306 list.splice( list.indexOf( xnode ), 1 );
\r
309 // この部分 startUpdate へ?
\r
310 if( flags & ~X_Node_BitMask_RESET_GPU ){
\r
311 skipUpdate = flags & X_NodeFlags_GPU_RESERVED;
\r
312 ( flags & X_NodeFlags_GPU_RELEASE_RESERVED ) || X_NodeAnime_updatePosition( xnode, obj, 0.5, false );
\r
313 skipUpdate || ( xnode[ '_rawObject' ].style.cssText = X_Node_CSS_objToCssText( xnode ) );
\r
314 xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
\r
319 * 1. 新規アニメーションが現在アニメーション中の要素の親か子であればアニメーションを待機
\r
321 function X_NodeAnime_detectWaitAnimation( xnode, duration, isTest ){
\r
322 var list = X_NodeAnime_QUEUE,
\r
323 i = 0, _xnode, obj;
\r
325 for( ; _xnode = list[ i ]; ++i ){
\r
326 if( _xnode === xnode ) break;
\r
328 // アニメーションの優先度はリストにいる順
\r
329 // まず先行する後続待機要素の中に、親子関係のものがいないか?探す
\r
330 if( _xnode[ '_anime' ].phase <= 3 ){
\r
331 if( xnode[ 'contains' ]( _xnode ) || _xnode[ 'contains' ]( xnode ) ){ // 祖先か?見た方が早そう
\r
332 // -> いる、このような要素が複数いる場合、誰に後続すればいいか?判然としないため、準待機フラグを立てる
\r
338 // -> いない、アニメーション中(開始可能も)の要素の中に、親子関係のものがいないか?探す
\r
340 // -> いない、アニメーションが可能
\r
341 for( i = 0; _xnode = list[ i ]; ++i ){
\r
342 if( _xnode === xnode ) break;
\r
343 obj = _xnode[ '_anime' ];
\r
344 if( 6 <= obj.phase ){
\r
345 if( xnode[ 'contains' ]( _xnode ) || _xnode[ 'contains' ]( xnode ) ){
\r
346 return isTest ? 3 : _xnode;
\r
351 return duration ? 6 : 4; // duration がない場合は、アニメーション強制停止へ進みそこから GPU 解除待ちへ
\r
354 function X_NodeAnime_updateAnimations( e ){
\r
355 var list = X_NodeAnime_QUEUE,
\r
356 now = X_Timer_now(),
\r
358 i, xnode, obj, _xnode,
\r
359 rm, progress, easing, lazy;
\r
361 if( X_NodeAnime_needsDetection ){
\r
362 X_NodeAnime_needsDetection = false;
\r
365 list.sort( X_NodeAnime_sortAnimationNode );
\r
367 for( i = 0; xnode = list[ i ]; ++i ){
\r
368 obj = xnode[ '_anime' ];
\r
370 if( obj.phase <= 3 ){
\r
371 if( !X_Type_isNumber( obj.phase = _xnode = X_NodeAnime_detectWaitAnimation( xnode, obj.duration ) ) ){
\r
372 _xnode[ '_anime' ].follower = true;
\r
373 obj.phase = 3; // 後続待機
\r
376 obj.follower = false;
\r
381 for( i = list.length; i; ){
\r
383 xnode = list[ --i ];
\r
384 obj = xnode[ '_anime' ];
\r
386 switch( obj.phase ){
\r
387 case 7 : // アニメーション中
\r
388 if( now < obj.toTime ){
\r
389 obj.progress = progress = ( now - obj.fromTime ) / obj.duration;
\r
390 easing = obj.easing( progress );
\r
391 obj.x = ( obj.toX - obj.fromX ) * easing + obj.fromX;
\r
392 obj.y = ( obj.toY - obj.fromY ) * easing + obj.fromY;
\r
393 obj.rotate = ( obj.toRotate - obj.fromRotate ) * easing + obj.fromRotate;
\r
394 obj.skewX = ( obj.toSkewX - obj.fromSkewX ) * easing + obj.fromSkewX;
\r
395 obj.skewY = ( obj.toSkewY - obj.fromSkewY ) * easing + obj.fromSkewY;
\r
396 obj.scaleX = ( obj.toScaleX - obj.fromScaleX ) * easing + obj.fromScaleX;
\r
397 obj.scaleY = ( obj.toScaleY - obj.fromScaleY ) * easing + obj.fromScaleY;
\r
398 obj.alpha = ( obj.toAlpha - obj.fromAlpha ) * easing + obj.fromAlpha;
\r
399 obj.scrollX = ( obj.toScrollX - obj.fromScrollX ) * easing + obj.fromScrollX;
\r
400 obj.scrollY = ( obj.toScrollY - obj.fromScrollY ) * easing + obj.fromScrollY;
\r
401 X_NodeAnime_updatePosition( xnode, obj, progress, true );
\r
406 xnode[ 'asyncDispatch' ]( X_EVENT_ANIME_END );
\r
408 case 4 : // 強制停止(GPU転送予約)または transform や opacity の値のみ設定
\r
409 lazy = !obj.follower && !obj.releaseNow && obj.lazyRelease;
\r
410 X_NodeAnime_updatePosition( xnode, obj, 1, !!lazy );
\r
412 //if( obj.canceled ){
\r
413 // xnode[ 'asyncDispatch' ]( X_EVENT_CANCELED );
\r
419 console.log( 'アニメーション終了(' + obj.phase + ') -> GPU 解除待機 ' + lazy );
\r
420 obj.toTime = now + lazy;
\r
421 obj.phase = 5; // GPU解除待ち
\r
424 console.log( 'アニメーション終了(' + obj.phase + ') -> ' );
\r
429 case 6 : // アニメーション開始可能
\r
430 obj.fromTime = now;
\r
431 obj.toTime = now + obj.duration;
\r
432 obj.phase = 7; // アニメーション中
\r
434 xnode[ 'asyncDispatch' ]( X_EVENT_ANIME_START );
\r
436 //obj.canceled = false;
\r
437 ( !obj.inited || X_NodeAnime_translateZ ) && X_NodeAnime_updatePosition( xnode, obj, 0, true );
\r
440 case 5 : // GPU解除待ち
\r
441 if( obj.toTime <= now || obj.follower || obj.releaseNow ){
\r
442 X_NodeAnime_translateZ && X_NodeAnime_updatePosition( xnode, obj, 1, false );
\r
449 default : // 2 or 3
\r
450 // 待機状態でも親要素が GPU 化していなければ、開始値をセットすることは可能
\r
451 obj.inited || X_NodeAnime_updatePosition( xnode, obj, 0, false );
\r
456 obj.releaseNow = false;
\r
459 X_NodeAnime_translateZ && xnode[ 'asyncDispatch' ]( X_EVENT_GPU_RELEASED );
\r
461 if( obj.follower ) X_NodeAnime_needsDetection = c = true;
\r
462 list.splice( i, 1 );
\r
467 //c && console.log( 'anime... ' + X_Node_updateTimerID );
\r
469 if( X_NodeAnime_reserved = c ){
\r
470 if( X_Node_updateTimerID ){
\r
471 // scrollbox では X_System X_EVENT_UPDATED は不可。。。
\r
472 !e || e.type !== X_EVENT_UPDATED ?
\r
473 X_System[ 'listen' ]( X_EVENT_UPDATED, X_NodeAnime_updateAnimations ) :
\r
474 X_NodeAnime_updateTimerID && X_Timer_cancelFrame( X_NodeAnime_updateTimerID );
\r
475 X_NodeAnime_updateTimerID = 0;
\r
477 X_System[ 'unlisten' ]( X_EVENT_UPDATED, X_NodeAnime_updateAnimations );
\r
478 X_NodeAnime_updateTimerID = X_Timer_requestFrame( X_NodeAnime_updateAnimations );
\r
481 X_System[ 'unlisten' ]( X_EVENT_UPDATED, X_NodeAnime_updateAnimations );
\r
482 X_NodeAnime_updateTimerID = 0;
\r
487 * アニメーション開始、アニメーション中、強制停止(GPU転送予約)、GPU解除待ち の要素をリストの先頭に
\r
489 function X_NodeAnime_sortAnimationNode( xnode1, xnode2 ){
\r
490 var a = 4 <= xnode1[ '_anime' ].phase,
\r
491 b = 4 <= xnode2[ '_anime' ].phase;
\r
493 if( ( a && b ) && ( !a && !b ) ){ // Chrome のみ
\r
494 return xnode1[ '_anime' ].uid - xnode2[ '_anime' ].uid;
\r
499 function X_NodeAnime_updatePosition( xnode, obj, ratio, useGPU ){
\r
501 x, y, rotate, skewX, skewY, scaleX, scaleY, alpha,
\r
505 x = obj.x = obj.toX;
\r
506 y = obj.y = obj.toY;
\r
507 rotate = X_Node_CSS_ieMathRangeFix( obj.rotate = obj.toRotate );
\r
508 skewX = X_Node_CSS_ieMathRangeFix( obj.skewX = obj.toSkewX );
\r
509 skewY = X_Node_CSS_ieMathRangeFix( obj.skewY = obj.toSkewY );
\r
510 scaleX = obj.scaleX = obj.toScaleX;
\r
511 scaleY = obj.scaleY = obj.toScaleY;
\r
512 alpha = obj.alpha = obj.toAlpha;
\r
513 obj.scrollX = obj.toScrollX;
\r
514 obj.scrollY = obj.toScrollY;
\r
518 rotate = X_Node_CSS_ieMathRangeFix( obj.rotate );
\r
519 skewX = X_Node_CSS_ieMathRangeFix( obj.skewX );
\r
520 skewY = X_Node_CSS_ieMathRangeFix( obj.skewY );
\r
521 scaleX = obj.scaleX;
\r
522 scaleY = obj.scaleY;
\r
526 //console.log( 'updatePosition x:' + x + ' gpu:' + !!useGPU );
\r
527 if( obj.transform ){
\r
528 if( ( x === x || y === y ) && ( x !== 0 || y !== 0 ) ){
\r
529 if( X_UA[ 'Safari' ] && X_UA[ 'Windows' ] ){
\r
530 // http://shinimae.hatenablog.com/entry/2016/01/13/151748
\r
531 str = ' -webkit-translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)';
\r
533 str = ' translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)';
\r
536 if( rotate < 0 || 0 < rotate ) str += ' rotate(' + rotate + 'deg)'; // opera は rad?
\r
537 if( skewX < 0 || 0 < skewX ) str += ' skewX(' + skewX + 'deg)';
\r
538 if( skewY < 0 || 0 < skewY ) str += ' skewY(' + skewY + 'deg)';
\r
539 if( scaleX < 1 || 1 < scaleX ) str += ' scaleX(' + scaleX + ')';
\r
540 if( scaleY < 1 || 1 < scaleY ) str += ' scaleY(' + scaleY + ')';
\r
542 xnode[ 'css' ]( 'transform', ( str ? str.substr( 1 ) : '' ) + ( useGPU ? X_NodeAnime_translateZ : '' ) );
\r
543 console.log( xnode.className() + ' ' + str + ' ' + (xnode[ '_flags' ] & X_NodeFlags_DIRTY_CSS) );
\r
545 if( X_NodeAnime_translateZ ){
\r
547 if( xnode[ '_flags' ] & X_NodeFlags_GPU_RELEASE_RESERVED ){
\r
548 xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
\r
549 xnode[ '_flags' ] |= X_NodeFlags_GPU_NOW;
\r
551 if( !( xnode[ '_flags' ] & X_NodeFlags_GPU_NOW ) ){
\r
552 xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
\r
553 xnode[ '_flags' ] |= X_NodeFlags_GPU_RESERVED;
\r
556 if( xnode[ '_flags' ] & X_NodeFlags_GPU_NOW ){
\r
557 xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
\r
558 xnode[ '_flags' ] |= X_NodeFlags_GPU_RELEASE_RESERVED;
\r
560 if( xnode[ '_flags' ] & X_NodeFlags_GPU_RESERVED ){
\r
561 xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
\r
566 if( obj.fallback === 32 ){
\r
567 xnode[ 'css' ]( 'dxtransform', [ x | 0, y | 0, rotate || 0, skewX || 0, skewY || 0, scaleX, scaleY, obj.altX, obj.altY ] );
\r
569 x === x && xnode[ 'css' ]( obj.altX, ( x | 0 ) + 'px' );
\r
570 y === y && xnode[ 'css' ]( obj.altY, ( y | 0 ) + 'px' );
\r
572 switch( obj.fallback ){
\r
574 xnode[ 'css' ]( 'zoom', scaleX );
\r
577 xnode[ 'css' ]( 'fontSize', scaleX + 'em' );
\r
585 if( obj.doScroll && xnode[ '_rawObject' ] ){
\r
586 console.log( 'ok ' + ratio );
\r
587 xnode[ '_rawObject' ].scrollLeft = obj.scrollX | 0;
\r
588 xnode[ '_rawObject' ].scrollTop = obj.scrollY | 0;
\r
589 //X_Node_reserveUpdate();
\r
592 alpha === alpha && xnode[ 'css' ]( 'opacity', alpha );
\r
597 X_NodeAnime_ease = {
\r
598 'quadratic' : function (k) {
\r
599 return k * ( 2 - k );
\r
601 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
\r
603 return k * ( 2 - k );
\r
606 'circular' : function (k) {
\r
607 return Math.sqrt( 1 - ( --k * k ) );
\r
608 /*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
610 return Math.sqrt( 1 - ( --k * k ) );
\r
613 'back' : function (k) {
\r
614 return --k * k * ( 5 * k + 4 ) + 1;
\r
615 /*style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
\r
618 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
\r
621 'bounce' : function (k, X) {
\r
623 if ( k < ( 1 / 2.75 ) ) {
\r
626 if ( k < ( 2 / 2.75 ) ) {
\r
627 return X * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
\r
629 if ( k < ( 2.5 / 2.75 ) ) {
\r
630 return X * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
\r
632 return X * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
\r
636 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
\r
637 return 7.5625 * k * k;
\r
638 } else if ( k < ( 2 / 2.75 ) ) {
\r
639 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
\r
640 } else if ( k < ( 2.5 / 2.75 ) ) {
\r
641 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
\r
643 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
\r
647 'elastic' : function (k) {
\r
648 return k === 0 ? 0 : k === 1 ? 1 : ( 0.4 * Math.pow( 2, - 10 * k ) * Math.sin( ( k - 0.055 ) * 28.56 ) + 1 );
\r
654 if ( k === 0 ) { return 0; }
\r
655 if ( k == 1 ) { return 1; }
\r
657 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
\r