OSDN Git Service

Version 0.6.80, bugfix for .instanceOf().
[pettanr/clientJs.git] / 0.6.x / js / 00_core / 05_XTimer.js
1 /**\r
2  * use X.Callback\r
3  */\r
4 \r
5 var _enterFrame =\r
6                 window.requestAnimationFrame ||\r
7                 window.webkitRequestAnimationFrame ||\r
8                 window.mozRequestAnimationFrame ||\r
9                 window.oRequestAnimationFrame ||\r
10                 window.msRequestAnimationFrame ||\r
11                 false,\r
12         _cancelFrame =\r
13                 window.cancelRequestAnimationFrame ||\r
14                 window.webkitCancelAnimationFrame ||\r
15                 window.webkitCancelRequestAnimationFrame ||\r
16                 window.mozCancelRequestAnimationFrame ||\r
17                 window.oCancelRequestAnimationFrame ||\r
18                 window.msCancelRequestAnimationFrame ||\r
19                 false;\r
20 \r
21 /*\r
22  * \r
23  * http://please-sleep.cou929.nu/script-yielding-with-setimmediate.html\r
24  * setImmediate での script yielding\r
25  * \r
26  * http://ie.microsoft.com/testdrive/Performance/setImmediateSorting/Default.html\r
27  * setImmediate API\r
28  * \r
29  * if( timer < 4ms ) useSetImmediate\r
30  * \r
31  *         if (window.msSetImmediate)\r
32         {\r
33             this.timer = msSetImmediate(function () { t.stepper(); });        \r
34         }\r
35         else if (window.MozSetImmediate)\r
36         {\r
37             this.timer = MozSetImmediate(function () { t.stepper(); });        \r
38         }\r
39         else if (window.WebkitSetImmediate) {\r
40             this.timer = WebkitSetImmediate(function () { t.stepper(); });\r
41         }\r
42         else if (window.OSetImmediate)\r
43         {\r
44             this.timer = OSetImmediate(function () { t.stepper(); });        \r
45         }\r
46  */\r
47 \r
48 X.Timer = {\r
49         INTERVAL_TIME  : 16,\r
50         TICKET_LIST    : [],\r
51         uid            : 0,\r
52         timerId        : 0,\r
53         endTime        : 0, // iOS\r
54         next           : 0,\r
55         busy           : false, // for Opera7\r
56         \r
57         REQ_FRAME_LIST : [],\r
58         requestID      : 0,\r
59         \r
60         _loop : function(){\r
61                 var next  = X.Timer.next,\r
62                         list  = X.Timer.TICKET_LIST,\r
63                         i     = 0,\r
64                         l     = list.length,\r
65                         limit = X.getTime() + X.Timer.INTERVAL_TIME / 2,\r
66                         heavy,\r
67                         q, f, c, r;\r
68                 \r
69                 if( X.Timer.busy ){\r
70                         alert( 'busy!' );\r
71                 };\r
72                 \r
73                 X.Timer.busy = true;\r
74                 \r
75             for( ; i < l; ++i ){\r
76                 q = list[ i ];\r
77                         if( 0 < ( q.last -= next ) ) continue;\r
78                         if( heavy ){\r
79                                 if( q.last <= 0 ) q.last = 1;\r
80                                 continue;\r
81                         };\r
82                         c = q.count;\r
83                         \r
84                         if( q.k ){\r
85                                 q.a = [];\r
86                                 r = X.Callback._proxyCallback( q );\r
87                         } else {\r
88                                 r = q.f();\r
89                         };\r
90                         \r
91                         console.log( 'fire....' );\r
92                         \r
93                         if( limit <= X.getTime() ){\r
94                                 console.log( 'heavy' );\r
95                                 // 関数の実行に時間が係る場合、次のタイミングに\r
96                                 heavy = true;\r
97                         };                      \r
98                         \r
99                         if( r & X.Callback.UN_LISTEN || c === 1 ){\r
100                                 list.splice( i, 1 );\r
101                                 --i;\r
102                                 --l;\r
103                                 continue;\r
104                         } else\r
105                         if( 1 < c ) --q.count;\r
106                         q.last = q.time;\r
107             };\r
108             X.Timer.timerId = 0;\r
109             X.Timer.busy = false;\r
110             X.Timer._update();\r
111         },\r
112         _update : function(){\r
113                 var list = X.Timer.TICKET_LIST,\r
114                         i    = list.length,\r
115                         n;\r
116                 if( i === 0 ){\r
117                         X.Timer.timerId && window.clearTimeout( X.Timer.timerId );\r
118                         X.Timer.timerId = 0;\r
119                         return;\r
120                 };\r
121                 \r
122                 1 < i && list.sort( x_timer_compareQueue );\r
123                 \r
124             n = list[ i - 1 ].last;\r
125             \r
126             if( n < X.Timer.next || X.Timer.timerId === 0 ){\r
127                 X.Timer.timerId && window.clearTimeout( X.Timer.timerId );\r
128                 X.Timer.timerId = window.setTimeout( X.Timer._loop, X.Timer.INTERVAL_TIME * n );\r
129                 X.Timer.endTime = X.getTime() + X.Timer.INTERVAL_TIME * n; // iOS\r
130                 X.Timer.next = n;\r
131             };\r
132         },\r
133         \r
134         // ページを読み込んでからの時間\r
135         _onEnterFrame : function ( time ){\r
136                 var list = X.Timer.REQ_FRAME_LIST,\r
137                         l    = list.length,\r
138                         i    = 0, q;\r
139 \r
140                 time = time || X.getTime();\r
141                 // console.log( X.getTime() + ' , ' + time );\r
142             for( ; i < l; ++i ){\r
143                 q = list[ i ];\r
144                 \r
145                         if( q.k ){\r
146                                 q.a = [ time ];\r
147                                 X.Callback._proxyCallback( q );\r
148                         } else {\r
149                                 q( time );\r
150                         };\r
151             };\r
152 \r
153             list.splice( 0, l );\r
154             if( list.length ){\r
155                 X.Timer.requestID = _enterFrame ? _enterFrame( X.Timer._onEnterFrame ) : X.Timer.add( 0, 1, X.Timer._onEnterFrame );\r
156             };\r
157         },\r
158         \r
159         add : function( time, opt_count, args1, args2, args3 ){\r
160                 var list = X.Timer.TICKET_LIST,\r
161                         hash, obj;\r
162                 time = time < X.Timer.INTERVAL_TIME ? 1 : time / X.Timer.INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;\r
163                 \r
164                 if( !X.Type.isNumber( opt_count ) ){\r
165                         args3 = args2;\r
166                         args2 = args1;\r
167                         args1 = opt_count;\r
168                         opt_count = 0;\r
169                 };\r
170                 \r
171                 hash = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
172                 if( !hash ) return -1; // dev only\r
173                 \r
174                 if( !hash.k ) hash = { f : hash };\r
175                 hash.time  = time;\r
176                 hash.last  = time;\r
177                 hash.count = opt_count;\r
178                 hash.uid   = ++X.Timer.uid;\r
179                 list[ list.length ] = hash;\r
180                 \r
181             !X.Timer.busy && X.Timer._update();\r
182             return X.Timer.uid;\r
183         },\r
184         once : function( time, args1, args2, args3 ){\r
185                 return X.Timer.add( time, 1, args1, args2, args3 );\r
186         },\r
187         remove : function( uid ){\r
188                 var list = X.Timer.TICKET_LIST,\r
189                         i    = list.length,\r
190                         l    = i,\r
191                         f, q;\r
192                 for( ; i; ){\r
193                         // TODO\r
194                         // fire 中の cancel\r
195                         if( ( q = list[ --i ] ).uid === uid ){\r
196                                 list.splice( i, 1 );\r
197                                 !X.Timer.busy && ( /* q[ INDEX_COUNT ] <= next  || */ l === 1 ) && X.Timer._update();\r
198                                 break;\r
199                         };\r
200                 };\r
201         },\r
202         \r
203         requestFrame : _enterFrame ?\r
204                 (function( args1, args2, args3 ){\r
205                         var i = X.Timer.REQ_FRAME_LIST.length,\r
206                                 f;\r
207                         i === 0 && ( X.Timer.requestID = _enterFrame( X.Timer._onEnterFrame ) );\r
208                         f = X.Timer.REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
209                         return f.uid = ++X.Timer.uid;\r
210                 }) :\r
211                 (function( args1, args2, args3 ){\r
212                         var i = X.Timer.REQ_FRAME_LIST.length,\r
213                                 f;\r
214                         i === 0 && ( X.Timer.requestID = X.Timer.add( 0, 1, X.Timer._onEnterFrame ) );\r
215                         f = X.Timer.REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
216                         return f.uid = ++X.Timer.uid;\r
217                 }),\r
218         \r
219         cancelFrame : _cancelFrame ?\r
220                 (function( uid ){\r
221                         var list = X.Timer.REQ_FRAME_LIST,\r
222                                 l    = list.length,\r
223                                 i    = l,\r
224                                 f;\r
225                         for( ; i; ){\r
226                                 if( ( f = list[ --i ] ).uid < uid ) break;\r
227                                 if( f.uid === uid ){\r
228                                         // TODO\r
229                                         // fire 中の cancel\r
230                                         list.splice( i, 1 );\r
231                                         l === 1 && _cancelFrame( X.Timer.requestID );\r
232                                         break;\r
233                                 };\r
234                         };\r
235                 }) :\r
236                 (function( uid ){\r
237                         var list = X.Timer.REQ_FRAME_LIST,\r
238                                 l    = list.length,\r
239                                 i    = l,\r
240                                 f;\r
241                         for( ; i; ){\r
242                                 if( ( f = list[ --i ] ).uid < uid ) break;\r
243                                 if( f.uid === uid ){\r
244                                         list.splice( i, 1 );\r
245                                         l === 1 && X.Timer.remove( X.Timer.requestID );\r
246                                         break;\r
247                                 };\r
248                         };\r
249                 })\r
250         \r
251 };\r
252 \r
253 // 大きい -> 小さい\r
254 function x_timer_compareQueue( a, b ){\r
255         return a.last < b.last ? 1 : a.last === b.last ? 0 : -1;\r
256 };\r
257 \r
258 \r
259 // http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html\r
260 // iOS6 スクロール中のタイマー発火絡みのバグ備忘\r
261 if( X.UA.iOS ){\r
262         window.addEventListener( 'scroll', function(){\r
263                 if( X.Timer.timerId ){\r
264                         window.clearTimeout( X.Timer.timerId );\r
265                         X.Timer.timerId = window.setTimeout( X.Timer._loop, Math.max( 0, X.Timer.endTime - X.getTime() ) );\r
266                 };\r
267         });\r
268 };\r
269 \r
270 if( X.UA.IE < 5 || X.UA.MacIE ){\r
271         X.Timer[ '_ie_loop' ] = X.Timer._loop;\r
272         X.Timer._loop = 'X.Timer._ie_loop()';\r
273 };\r
274 \r
275 console.log( 'X.Core.Timer' );\r