Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / docs / source / ext-base-anim.html
1 <html>\r
2 <head>\r
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    \r
4   <title>The source code</title>\r
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
7 </head>\r
8 <body  onload="prettyPrint();">\r
9     <pre class="prettyprint lang-js">(function(){    \r
10     var EXTLIB = Ext.lib,\r
11         noNegatives = /width|height|opacity|padding/i,\r
12         offsetAttribute = /^((width|height)|(top|left))$/,\r
13         defaultUnit = /width|height|top$|bottom$|left$|right$/i,\r
14         offsetUnit =  /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i,\r
15         isset = function(v){\r
16             return typeof v !== 'undefined';\r
17         },\r
18         now = function(){\r
19             return new Date();    \r
20         };\r
21         \r
22     EXTLIB.Anim = {\r
23         motion : function(el, args, duration, easing, cb, scope) {\r
24             return this.run(el, args, duration, easing, cb, scope, Ext.lib.Motion);\r
25         },\r
26 \r
27         run : function(el, args, duration, easing, cb, scope, type) {\r
28             type = type || Ext.lib.AnimBase;\r
29             if (typeof easing == "string") {\r
30                 easing = Ext.lib.Easing[easing];\r
31             }\r
32             var anim = new type(el, args, duration, easing);\r
33             anim.animateX(function() {\r
34                 if(Ext.isFunction(cb)){\r
35                     cb.call(scope);\r
36                 }\r
37             });\r
38             return anim;\r
39         }\r
40     };\r
41     \r
42     EXTLIB.AnimBase = function(el, attributes, duration, method) {\r
43         if (el) {\r
44             this.init(el, attributes, duration, method);\r
45         }\r
46     };\r
47 \r
48     EXTLIB.AnimBase.prototype = {\r
49         doMethod: function(attr, start, end) {\r
50             var me = this;\r
51             return me.method(me.curFrame, start, end - start, me.totalFrames);\r
52         },\r
53 \r
54 \r
55         setAttr: function(attr, val, unit) {\r
56             if (noNegatives.test(attr) && val < 0) {\r
57                 val = 0;\r
58             }\r
59             Ext.fly(this.el, '_anim').setStyle(attr, val + unit);\r
60         },\r
61 \r
62 \r
63         getAttr: function(attr) {\r
64             var el = Ext.fly(this.el),\r
65                 val = el.getStyle(attr),\r
66                 a = offsetAttribute.exec(attr) || []\r
67 \r
68             if (val !== 'auto' && !offsetUnit.test(val)) {\r
69                 return parseFloat(val);\r
70             }\r
71 \r
72             return (!!(a[2]) || (el.getStyle('position') == 'absolute' && !!(a[3]))) ? el.dom['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)] : 0;\r
73         },\r
74 \r
75 \r
76         getDefaultUnit: function(attr) {\r
77             return defaultUnit.test(attr) ? 'px' : '';\r
78         },\r
79 \r
80         animateX : function(callback, scope) {\r
81             var me = this,\r
82                 f = function() {\r
83                 me.onComplete.removeListener(f);\r
84                 if (Ext.isFunction(callback)) {\r
85                     callback.call(scope || me, me);\r
86                 }\r
87             };\r
88             me.onComplete.addListener(f, me);\r
89             me.animate();\r
90         },\r
91 \r
92 \r
93         setRunAttr: function(attr) {            \r
94             var me = this,\r
95                 a = this.attributes[attr],\r
96                 to = a.to,\r
97                 by = a.by,\r
98                 from = a.from,\r
99                 unit = a.unit,\r
100                 ra = (this.runAttrs[attr] = {}),\r
101                 end;\r
102 \r
103             if (!isset(to) && !isset(by)){\r
104                 return false;\r
105             }\r
106 \r
107             var start = isset(from) ? from : me.getAttr(attr);\r
108             if (isset(to)) {\r
109                 end = to;\r
110             }else if(isset(by)) {\r
111                 if (Ext.isArray(start)){\r
112                     end = [];\r
113                                         for(var i=0,len=start.length; i<len; i++) {\r
114                                                 end[i] = start[i] + by[i];\r
115                                         }\r
116                 }else{\r
117                     end = start + by;\r
118                 }\r
119             }\r
120 \r
121             Ext.apply(ra, {\r
122                 start: start,\r
123                 end: end,\r
124                 unit: isset(unit) ? unit : me.getDefaultUnit(attr)\r
125             });\r
126         },\r
127 \r
128 \r
129         init: function(el, attributes, duration, method) {\r
130             var me = this,\r
131                 actualFrames = 0,\r
132                 mgr = EXTLIB.AnimMgr;\r
133                 \r
134             Ext.apply(me, {\r
135                 isAnimated: false,\r
136                 startTime: null,\r
137                 el: Ext.getDom(el),\r
138                 attributes: attributes || {},\r
139                 duration: duration || 1,\r
140                 method: method || EXTLIB.Easing.easeNone,\r
141                 useSec: true,\r
142                 curFrame: 0,\r
143                 totalFrames: mgr.fps,\r
144                 runAttrs: {},\r
145                 animate: function(){\r
146                     var me = this,\r
147                         d = me.duration;\r
148                     \r
149                     if(me.isAnimated){\r
150                         return false;\r
151                     }\r
152 \r
153                     me.curFrame = 0;\r
154                     me.totalFrames = me.useSec ? Math.ceil(mgr.fps * d) : d;\r
155                     mgr.registerElement(me); \r
156                 },\r
157                 \r
158                 stop: function(finish){\r
159                     var me = this;\r
160                 \r
161                     if(finish){\r
162                         me.curFrame = me.totalFrames;\r
163                         me._onTween.fire();\r
164                     }\r
165                     mgr.stop(me);\r
166                 }\r
167             });\r
168 \r
169             var onStart = function(){\r
170                 var me = this,\r
171                     attr;\r
172                 \r
173                 me.onStart.fire();\r
174                 me.runAttrs = {};\r
175                 for(attr in this.attributes){\r
176                     this.setRunAttr(attr);\r
177                 }\r
178 \r
179                 me.isAnimated = true;\r
180                 me.startTime = now();\r
181                 actualFrames = 0;\r
182             };\r
183 \r
184 \r
185             var onTween = function(){\r
186                 var me = this;\r
187 \r
188                 me.onTween.fire({\r
189                     duration: now() - me.startTime,\r
190                     curFrame: me.curFrame\r
191                 });\r
192 \r
193                 var ra = me.runAttrs;\r
194                 for (var attr in ra) {\r
195                     this.setAttr(attr, me.doMethod(attr, ra[attr].start, ra[attr].end), ra[attr].unit);\r
196                 }\r
197 \r
198                 ++actualFrames;\r
199             };\r
200 \r
201             var onComplete = function() {\r
202                 var me = this,\r
203                     actual = (now() - me.startTime) / 1000,\r
204                     data = {\r
205                         duration: actual,\r
206                         frames: actualFrames,\r
207                         fps: actualFrames / actual\r
208                     };\r
209 \r
210                 me.isAnimated = false;\r
211                 actualFrames = 0;\r
212                 me.onComplete.fire(data);\r
213             };\r
214 \r
215             me.onStart = new Ext.util.Event(me);\r
216             me.onTween = new Ext.util.Event(me);            \r
217             me.onComplete = new Ext.util.Event(me);\r
218             (me._onStart = new Ext.util.Event(me)).addListener(onStart);\r
219             (me._onTween = new Ext.util.Event(me)).addListener(onTween);\r
220             (me._onComplete = new Ext.util.Event(me)).addListener(onComplete); \r
221         }\r
222     };\r
223 \r
224 \r
225     Ext.lib.AnimMgr = new function() {\r
226         var me = this,\r
227             thread = null,\r
228             queue = [],\r
229             tweenCount = 0;\r
230 \r
231 \r
232         Ext.apply(me, {\r
233             fps: 1000,\r
234             delay: 1,\r
235             registerElement: function(tween){\r
236                 queue.push(tween);\r
237                 ++tweenCount;\r
238                 tween._onStart.fire();\r
239                 me.start();\r
240             },\r
241             \r
242             unRegister: function(tween, index){\r
243                 tween._onComplete.fire();\r
244                 index = index || getIndex(tween);\r
245                 if (index != -1) {\r
246                     queue.splice(index, 1);\r
247                 }\r
248 \r
249                 if (--tweenCount <= 0) {\r
250                     me.stop();\r
251                 }\r
252             },\r
253             \r
254             start: function(){\r
255                 if(thread === null){\r
256                     thread = setInterval(me.run, me.delay);\r
257                 }\r
258             },\r
259             \r
260             stop: function(tween){\r
261                 if(!tween){\r
262                     clearInterval(thread);\r
263                     for(var i = 0, len = queue.length; i < len; ++i){\r
264                         if(queue[0].isAnimated){\r
265                             me.unRegister(queue[0], 0);\r
266                         }\r
267                     }\r
268 \r
269                     queue = [];\r
270                     thread = null;\r
271                     tweenCount = 0;\r
272                 }else{\r
273                     me.unRegister(tween);\r
274                 }\r
275             },\r
276             \r
277             run: function(){\r
278                 var tf, i, len, tween;\r
279                 for(i = 0, len = queue.length; i<len; i++) {\r
280                     tween = queue[i];\r
281                     if(tween && tween.isAnimated){\r
282                         tf = tween.totalFrames;\r
283                         if(tween.curFrame < tf || tf === null){\r
284                             ++tween.curFrame;\r
285                             if(tween.useSec){\r
286                                 correctFrame(tween);\r
287                             }\r
288                             tween._onTween.fire();\r
289                         }else{\r
290                             me.stop(tween);\r
291                         }\r
292                     }                   \r
293                 }\r
294             }\r
295         });\r
296 \r
297         var getIndex = function(anim) {\r
298             var i, len;\r
299             for(i = 0, len = queue.length; i<len; i++) {\r
300                 if(queue[i] === anim) {\r
301                     return i;\r
302                 }\r
303             }\r
304             return -1;\r
305         };\r
306 \r
307         var correctFrame = function(tween) {\r
308             var frames = tween.totalFrames,\r
309                 frame = tween.curFrame,\r
310                 duration = tween.duration,\r
311                 expected = (frame * duration * 1000 / frames),\r
312                 elapsed = (now() - tween.startTime),\r
313                 tweak = 0;\r
314 \r
315             if(elapsed < duration * 1000){\r
316                 tweak = Math.round((elapsed / expected - 1) * frame);\r
317             }else{\r
318                 tweak = frames - (frame + 1);\r
319             }\r
320             if(tweak > 0 && isFinite(tweak)){\r
321                 if(tween.curFrame + tweak >= frames){\r
322                     tweak = frames - (frame + 1);\r
323                 }\r
324                 tween.curFrame += tweak;\r
325             }\r
326         };\r
327     };\r
328 \r
329     EXTLIB.Bezier = new function() {\r
330 \r
331         this.getPosition = function(points, t) {\r
332             var n = points.length,\r
333                 tmp = [],\r
334                 c = 1 - t, \r
335                 i,\r
336                 j;\r
337 \r
338             for (i = 0; i < n; ++i) {\r
339                 tmp[i] = [points[i][0], points[i][1]];\r
340             }\r
341 \r
342             for (j = 1; j < n; ++j) {\r
343                 for (i = 0; i < n - j; ++i) {\r
344                     tmp[i][0] = c * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];\r
345                     tmp[i][1] = c * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];\r
346                 }\r
347             }\r
348 \r
349             return [ tmp[0][0], tmp[0][1] ];\r
350 \r
351         };\r
352     };\r
353 \r
354 \r
355     EXTLIB.Easing = {\r
356         easeNone: function (t, b, c, d) {\r
357             return c * t / d + b;\r
358         },\r
359 \r
360 \r
361         easeIn: function (t, b, c, d) {\r
362             return c * (t /= d) * t + b;\r
363         },\r
364 \r
365 \r
366         easeOut: function (t, b, c, d) {\r
367             return -c * (t /= d) * (t - 2) + b;\r
368         }\r
369     };\r
370 \r
371     (function() {\r
372         EXTLIB.Motion = function(el, attributes, duration, method) {\r
373             if (el) {\r
374                 EXTLIB.Motion.superclass.constructor.call(this, el, attributes, duration, method);\r
375             }\r
376         };\r
377 \r
378         Ext.extend(EXTLIB.Motion, Ext.lib.AnimBase);\r
379 \r
380         var superclass = EXTLIB.Motion.superclass,\r
381             proto = EXTLIB.Motion.prototype,\r
382             pointsRe = /^points$/i;\r
383 \r
384         Ext.apply(EXTLIB.Motion.prototype, {\r
385             setAttr: function(attr, val, unit){\r
386                 var me = this,\r
387                     setAttr = superclass.setAttr;\r
388                     \r
389                 if (pointsRe.test(attr)) {\r
390                     unit = unit || 'px';\r
391                     setAttr.call(me, 'left', val[0], unit);\r
392                     setAttr.call(me, 'top', val[1], unit);\r
393                 } else {\r
394                     setAttr.call(me, attr, val, unit);\r
395                 }\r
396             },\r
397             \r
398             getAttr: function(attr){\r
399                 var me = this,\r
400                     getAttr = superclass.getAttr;\r
401                     \r
402                 return pointsRe.test(attr) ? [getAttr.call(me, 'left'), getAttr.call(me, 'top')] : getAttr.call(me, attr);\r
403             },\r
404             \r
405             doMethod: function(attr, start, end){\r
406                 var me = this;\r
407                 \r
408                 return pointsRe.test(attr)\r
409                         ? EXTLIB.Bezier.getPosition(me.runAttrs[attr], me.method(me.curFrame, 0, 100, me.totalFrames) / 100)\r
410                         : superclass.doMethod.call(me, attr, start, end);\r
411             },\r
412             \r
413             setRunAttr: function(attr){\r
414                 if(pointsRe.test(attr)){\r
415                     \r
416                     var me = this,\r
417                         el = this.el,\r
418                         points = this.attributes.points,\r
419                         control = points.control || [],\r
420                         from = points.from,\r
421                         to = points.to,\r
422                         by = points.by,\r
423                         DOM = EXTLIB.Dom,\r
424                         start,\r
425                         i,\r
426                         end,\r
427                         len,\r
428                         ra;\r
429                   \r
430 \r
431                     if(control.length > 0 && !Ext.isArray(control[0])){\r
432                         control = [control];\r
433                     }else{\r
434                         /*\r
435                         var tmp = [];\r
436                         for (i = 0,len = control.length; i < len; ++i) {\r
437                             tmp[i] = control[i];\r
438                         }\r
439                         control = tmp;\r
440                         */\r
441                     }\r
442 \r
443                     Ext.fly(el, '_anim').position();\r
444                     DOM.setXY(el, isset(from) ? from : DOM.getXY(el));\r
445                     start = me.getAttr('points');\r
446 \r
447 \r
448                     if(isset(to)){\r
449                         end = translateValues.call(me, to, start);\r
450                         for (i = 0,len = control.length; i < len; ++i) {\r
451                             control[i] = translateValues.call(me, control[i], start);\r
452                         }\r
453                     } else if (isset(by)) {\r
454                         end = [start[0] + by[0], start[1] + by[1]];\r
455 \r
456                         for (i = 0,len = control.length; i < len; ++i) {\r
457                             control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];\r
458                         }\r
459                     }\r
460 \r
461                     ra = this.runAttrs[attr] = [start];\r
462                     if (control.length > 0) {\r
463                         ra = ra.concat(control);\r
464                     }\r
465 \r
466                     ra[ra.length] = end;\r
467                 }else{\r
468                     superclass.setRunAttr.call(this, attr);\r
469                 }\r
470             }\r
471         });\r
472 \r
473         var translateValues = function(val, start) {\r
474             var pageXY = EXTLIB.Dom.getXY(this.el);\r
475             return [val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1]];\r
476         };\r
477     })();\r
478 })();</pre>    \r
479 </body>\r
480 </html>