*/\r
function X_Node_animate( start, dest, duration, easing, lazyRelease, option ){\r
var list = X_NodeAnime_QUEUE,\r
- obj = this[ '_anime' ],\r
- isNew = !obj,\r
- now, stop;\r
+ obj = this[ '_anime' ];\r
\r
if( !( this[ '_flags' ] & X_NodeFlags_IN_TREE ) ){\r
alert( '@animate 要素はツリーに追加されていません!' );\r
return this;\r
};\r
\r
- if( isNew ){\r
+ if( !obj ){\r
this[ '_anime' ] = obj = {\r
x : 0, y : 0, a : 1,\r
- destX : 0, destY : 0, destA : 1,\r
duration : 0\r
//phase, lazyRelease, easing, follower, releaseNow\r
};\r
\r
if( 0 <= duration && X_Type_isFinite( duration ) ){\r
obj.duration = duration;\r
- stop = !duration;\r
};\r
\r
- if( obj.phase !== 7 ){\r
- // アニメーション中は easing の変更ができない\r
- obj.easing = X_Type_isFunction( easing ) ? easing : X_NodeAnime_ease[ easing ] || X_NodeAnime_ease[ 'circular' ];\r
- };\r
+ obj.easing = X_Type_isFunction( easing ) ? easing : X_NodeAnime_ease[ easing ] || X_NodeAnime_ease[ 'circular' ];\r
+ \r
// form :\r
obj.startX = obj.x = X_NodeAnime_getFinite( start[ 'x' ], obj.x );\r
obj.startY = obj.y = X_NodeAnime_getFinite( start[ 'y' ], obj.y );\r
obj.startA = obj.a = X_NodeAnime_getFinite( start[ 'opacity' ], obj.a );\r
\r
// to :\r
- obj.destX = X_NodeAnime_getFinite( dest[ 'x' ], obj.destX );\r
- obj.destY = X_NodeAnime_getFinite( dest[ 'y' ], obj.destY );\r
- obj.destA = X_NodeAnime_getFinite( dest[ 'opacity' ], obj.destA );\r
+ obj.destX = X_NodeAnime_getFinite( dest[ 'x' ], obj.x );\r
+ obj.destY = X_NodeAnime_getFinite( dest[ 'y' ], obj.y );\r
+ obj.destA = X_NodeAnime_getFinite( dest[ 'opacity' ], obj.a );\r
\r
obj.lazyRelease = 0 <= lazyRelease && X_Type_isFinite( lazyRelease ) ? lazyRelease : 0;\r
+ obj.inited = false;\r
\r
- if( stop && 6 <= obj.phase ){\r
+ if( !obj.duration && 6 <= obj.phase ){\r
this[ 'stop' ](); // 現在値で停止\r
- } else\r
- if( !stop || obj.lazyRelease ){\r
- if( isNew || !obj.phase ){\r
+ } else {\r
+ if( !obj.phase ){\r
list[ list.length ] = this;\r
obj.phase = 1;\r
obj.uid = ++X_NodeAnime_uid;\r
obj.uid = ++X_NodeAnime_uid;\r
X_NodeAnime_needsDetection = true;\r
} else\r
- if( !stop ){\r
+ if( obj.duration ){\r
// リストの先頭にいるため検査不要でアニメーション開始可能 4, 5, 6, 7\r
obj.phase = 6;\r
} else\r
- // obj.lazyRelease はあり\r
+ // GPU 転送予約、または transform や opacity の値のみ設定\r
if( obj.phase !== 5 ){ // GPU解除待ち ではない -> 4. 6, 7\r
- obj.phase = 4; // 強制停止(GPU転送予約)\r
- obj.releaseNow = false; // TODO folower が要るため GPU 転送できないケースあり\r
+ obj.phase = 4; // 強制停止(GPU転送予約)または値のみ更新\r
+ obj.releaseNow = false; // TODO folower がいるため GPU 転送できないケースあり\r
X_NodeAnime_needsDetection = true;\r
};\r
\r
X_NodeAnime_updateTimerID = X_Timer_requestFrame( X_NodeAnime_updateAnimations );\r
};\r
}; \r
- } else {\r
- if( obj.phase ){\r
- this[ 'stop' ](); // リストから外す\r
- };\r
- console.log( 'リストに加えない!' );\r
};\r
\r
return this;\r
obj.startA = obj.destA = obj.a = 1;\r
}; // TODO 終了値で停止も,,,\r
\r
+ // obj.canceled = true;\r
+ \r
if( rm ) break; // 1,2,3,6 の場合ここまで\r
\r
obj.destX = obj.x;\r
\r
return this;\r
};\r
+/*\r
+ * remove(append swap 等でない部的に呼ばれている場合も), kill 時に\r
+ */\r
+function X_NodeAnime_stopNow( xnode ){\r
+ var obj = xnode[ '_anime' ],\r
+ flags = xnode[ '_flags' ],\r
+ list = X_NodeAnime_QUEUE,\r
+ skipUpdate;\r
+ \r
+ // if( !obj || !obj.phase ) return; 呼び出し側で検証済\r
+\r
+ X_NodeAnime_needsDetection = true;\r
+ list.splice( list.indexOf( xnode ), 1 );\r
+ obj.phase = 0;\r
+\r
+ // この部分 startUpdate へ?\r
+ if( flags & ~X_Node_BitMask_RESET_GPU ){\r
+ skipUpdate = flags & X_NodeFlags_GPU_RESERVED;\r
+ ( flags & X_NodeFlags_GPU_RELEASE_RESERVED ) || X_NodeAnime_updatePosition( xnode, obj.x, obj.y, obj.a, false );\r
+ skipUpdate || ( xnode[ '_rawObject' ].style.cssText = X_Node_CSS_objToCssText( xnode ) );\r
+ xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU;\r
+ };\r
+};\r
\r
/*\r
* 1. 新規アニメーションが現在アニメーション中の要素の親か子であればアニメーションを待機\r
- * 2. \r
*/\r
-function X_NodeAnime_detectWaitAnimation( xnode, duration, isText ){\r
+function X_NodeAnime_detectWaitAnimation( xnode, duration, isTest ){\r
var list = X_NodeAnime_QUEUE,\r
i = 0, _xnode;\r
\r
// アニメーションの優先度はリストにいる順\r
// まず先行する後続待機要素の中に、親子関係のものがいないか?探す\r
if( _xnode[ '_anime' ].phase <= 3 ){\r
- if( xnode[ 'contains' ]( _xnode ) || _xnode[ 'contains' ]( xnode ) ){\r
+ if( xnode[ 'contains' ]( _xnode ) || _xnode[ 'contains' ]( xnode ) ){ // 祖先か?見た方が早そう\r
// -> いる、このような要素が複数いる場合、誰に後続すればいいか?判然としないため、準待機フラグを立てる\r
return 2;\r
};\r
\r
if( 6 <= _xnode[ '_anime' ].phase ){\r
if( xnode[ 'contains' ]( _xnode ) || _xnode[ 'contains' ]( xnode ) ){\r
- return isText ? 3 : _xnode;\r
+ return isTest ? 3 : _xnode;\r
};\r
};\r
};\r
\r
function X_NodeAnime_updateAnimations( e ){\r
var list = X_NodeAnime_QUEUE,\r
- i = list.length,\r
now = X_Timer_now(),\r
- c = false,\r
+ c = false,\r
i, xnode, obj, _xnode,\r
- rm, easing, follower, lazy;\r
+ rm, easing, lazy;\r
\r
if( X_NodeAnime_needsDetection ){\r
X_NodeAnime_needsDetection = false;\r
\r
//\r
- list.sort( X_NodeAnime_sortAnimationNode ); \r
+ list.sort( X_NodeAnime_sortAnimationNode );\r
\r
for( i = 0; xnode = list[ i ]; ++i ){\r
obj = xnode[ '_anime' ];\r
};\r
};\r
\r
- for( ; i; ){\r
+ for( i = list.length; i; ){\r
rm = false;\r
xnode = list[ --i ];\r
obj = xnode[ '_anime' ];\r
break;\r
};\r
// アニメーション終了\r
+ xnode[ 'asyncDispatch' ]( X_EVENT_ANIME_END );\r
+ \r
case 4 : // 強制停止(GPU転送予約)\r
lazy = !obj.follower && !obj.releaseNow && obj.lazyRelease;\r
X_NodeAnime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, !!lazy );\r
\r
- xnode[ 'asyncDispatch' ]( X_EVENT_ANIME_END );\r
+ //if( obj.canceled ){\r
+ // xnode[ 'asyncDispatch' ]( X_EVENT_CANCELED );\r
+ //} else {\r
+ \r
+ //};\r
\r
if( lazy ){\r
console.log( 'アニメーション終了(' + obj.phase + ') -> GPU 解除待機 ' + lazy );\r
obj.startTime = now;\r
obj.destTime = now + obj.duration;\r
obj.phase = 7; // アニメーション中\r
- obj.progress = 0;\r
- X_NodeAnime_updatePosition( xnode, obj.startX, obj.startY, obj.startA, true );\r
+ obj.progress = 0; \r
xnode[ 'asyncDispatch' ]( X_EVENT_ANIME_START );\r
c = true;\r
+ //obj.canceled = false;\r
+ ( obj.inited && !X_NodeAnime_translateZ ) || X_NodeAnime_updatePosition( xnode, obj.startX, obj.startY, obj.startA, true );\r
break;\r
\r
case 5 : // GPU解除待ち\r
} else {\r
c = true;\r
};\r
- break; \r
+ break;\r
+ \r
+ default : // 2 or 3\r
+ // 待機状態でも親要素が GPU 化していなければ、開始値をセットすることは可能\r
+ obj.inited || X_NodeAnime_updatePosition( xnode, obj.startX, obj.startY, obj.startA, false );\r
+ obj.inited = false;\r
+ break;\r
};\r
\r
obj.releaseNow = false;\r
if( !parent ) return this;
- // TODO anime
// stop() ->
if( this[ '_anime' ] && this[ '_anime' ].phase ){
console.log( 'Animation 中の REMOVE' );
- this[ 'stop' ]();
+ X_NodeAnime_stopNow( this );
};
+ // 子孫にアニメーション中の要素が要る
+ // 先祖に GPU 化した要素が要る
delete this.parent;
parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( this ), 1 );
if( X_UA_DOM.IE4 ){
if( elm = this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ){
X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this;
- X_Node_reserveUpdate();
+ X_Node_reserveUpdate();
} else
if( !this[ '_tag' ] && ( ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) ){
parent[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
parent && parent[ '_xnodes' ] && parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( that ), 1 );
- elm = that[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( that );
-
if( xnodes && ( i = xnodes.length ) ){
delete that[ '_xnodes' ];
for( ; i; ){
X_Node_CHASHE[ that[ '_uid' ] ] = null; // array に対して delete X_Node_CHASHE[ uid ] はまずい!
-// TODO anime
if( that[ '_anime' ] && that[ '_anime' ].phase ){
console.log( 'Animation 中の KILL' );
- that[ 'stop' ]();
+ X_NodeAnime_stopNow( that );
};
+ elm = that[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( that );
+
// remove _xnodes
if( X_UA_DOM.IE4 ){
if( elm ){
* @example node.contains( testNode );
*/
function X_Node_contains( v ){
- var elm, type, xnodes, i;
+ var xnodes;
if( !v || !this[ '_tag' ] || this === v ) return false;
-
- // contains ie4+
- /*
- if( ( elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ) ) && document.contains && ( type = X_Node_getType( v ) ) && ( type === X_NodeType_RAW_HTML || type === X_NodeType_RAW_TEXT ) ){
- return elm.contains( v );
- }; */
- //if( document.compareDocumentPosition ){
- //
- //};
-
xnodes = this[ '_xnodes' ];
if( !xnodes || !xnodes.length ) return false;
- if( this === v[ 'parent' ] ) return true; // fast
- if( xnodes.indexOf( v ) !== -1 ) return true; // fast
- for( i = xnodes.length; i; ){
- if( xnodes[ --i ][ 'contains' ]( v ) ) return true;
+
+ while( v = v[ 'parent' ] ){
+ if( this === v ) return true;
};
return false;
};
return this.parent ? X_Node_CSS_getCharSize( this ) : 0;
case 'inGPU' :
return !!( this[ '_flags' ] & ( X_NodeFlags_GPU_NOW | X_NodeFlags_GPU_RELEASE_RESERVED ) );
+ case 'isGPUChild' :
+ if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){
+ parent = this;
+ while( parent = parent.parent ){
+ if( parent[ '_flags' ] & ( X_NodeFlags_GPU_NOW | X_NodeFlags_GPU_RELEASE_RESERVED ) ) return true;
+ };
+ };
+ return false;
+ case 'containGPU' :
+
+ return false;
case 'canAnimateNow' :
return ( this[ '_flags' ] & X_NodeFlags_IN_TREE ) && X_NodeAnime_detectWaitAnimation( this, true, true ) === 6;
case 'animeState' :
console.log( 'GPU 解放 ' );
//X_Node_updateReservedByReleaseGPU = true;
that[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
- //return elm;// TODO もしかしたらこのタイミングで更新できるかも。
+ //return elm;// このタイミングで更新できるっぽい。
};
// 3. GPU予約 -> GPU
if( that[ '_flags' ] & X_NodeFlags_GPU_RESERVED ){
- // TODO size 取得のための update の場合、GPU化を待つ
+ // TODO size 取得のための update の場合、GPU化をスキップ
that[ '_flags' ] &= X_Node_BitMask_RESET_GPU;
that[ '_flags' ] |= X_NodeFlags_GPU_NOW;
};
if( that[ '_flags' ] & X_NodeFlags_IS_SVG ){
elm = document.createElementNS( 'http://www.w3.org/2000/svg', that[ '_tag' ].toLowerCase() );
- // math http://www.w3.org/1998/Math/MathML
+ // TODO math http://www.w3.org/1998/Math/MathML
} else {
elm = document.createElement( that[ '_tag' ] );
};