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