initial import
[roojs1] / Roo / lib / AnimBase.js
1 /*
2  * Portions of this file are based on pieces of Yahoo User Interface Library
3  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4  * YUI licensed under the BSD License:
5  * http://developer.yahoo.net/yui/license.txt
6  * <script type="text/javascript">
7  *
8  */
9
10 (function() {    
11     var libFlyweight;
12     
13     function fly(el) {
14         if (!libFlyweight) {
15             libFlyweight = new Roo.Element.Flyweight();
16         }
17         libFlyweight.dom = el;
18         return libFlyweight;
19     }
20
21     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
22     
23    
24     
25     Roo.lib.AnimBase = function(el, attributes, duration, method) {
26         if (el) {
27             this.init(el, attributes, duration, method);
28         }
29     };
30
31     Roo.lib.AnimBase.fly = fly;
32     
33     
34     
35     Roo.lib.AnimBase.prototype = {
36
37         toString: function() {
38             var el = this.getEl();
39             var id = el.id || el.tagName;
40             return ("Anim " + id);
41         },
42
43         patterns: {
44             noNegatives:        /width|height|opacity|padding/i,
45             offsetAttribute:  /^((width|height)|(top|left))$/,
46             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
47             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
48         },
49
50
51         doMethod: function(attr, start, end) {
52             return this.method(this.currentFrame, start, end - start, this.totalFrames);
53         },
54
55
56         setAttribute: function(attr, val, unit) {
57             if (this.patterns.noNegatives.test(attr)) {
58                 val = (val > 0) ? val : 0;
59             }
60
61             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
62         },
63
64
65         getAttribute: function(attr) {
66             var el = this.getEl();
67             var val = fly(el).getStyle(attr);
68
69             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
70                 return parseFloat(val);
71             }
72
73             var a = this.patterns.offsetAttribute.exec(attr) || [];
74             var pos = !!( a[3] );
75             var box = !!( a[2] );
76
77
78             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
79                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
80             } else {
81                 val = 0;
82             }
83
84             return val;
85         },
86
87
88         getDefaultUnit: function(attr) {
89             if (this.patterns.defaultUnit.test(attr)) {
90                 return 'px';
91             }
92
93             return '';
94         },
95
96         animateX : function(callback, scope) {
97             var f = function() {
98                 this.onComplete.removeListener(f);
99                 if (typeof callback == "function") {
100                     callback.call(scope || this, this);
101                 }
102             };
103             this.onComplete.addListener(f, this);
104             this.animate();
105         },
106
107
108         setRuntimeAttribute: function(attr) {
109             var start;
110             var end;
111             var attributes = this.attributes;
112
113             this.runtimeAttributes[attr] = {};
114
115             var isset = function(prop) {
116                 return (typeof prop !== 'undefined');
117             };
118
119             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
120                 return false;
121             }
122
123             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
124
125
126             if (isset(attributes[attr]['to'])) {
127                 end = attributes[attr]['to'];
128             } else if (isset(attributes[attr]['by'])) {
129                 if (start.constructor == Array) {
130                     end = [];
131                     for (var i = 0, len = start.length; i < len; ++i) {
132                         end[i] = start[i] + attributes[attr]['by'][i];
133                     }
134                 } else {
135                     end = start + attributes[attr]['by'];
136                 }
137             }
138
139             this.runtimeAttributes[attr].start = start;
140             this.runtimeAttributes[attr].end = end;
141
142
143             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
144         },
145
146
147         init: function(el, attributes, duration, method) {
148
149             var isAnimated = false;
150
151
152             var startTime = null;
153
154
155             var actualFrames = 0;
156
157
158             el = Roo.getDom(el);
159
160
161             this.attributes = attributes || {};
162
163
164             this.duration = duration || 1;
165
166
167             this.method = method || Roo.lib.Easing.easeNone;
168
169
170             this.useSeconds = true;
171
172
173             this.currentFrame = 0;
174
175
176             this.totalFrames = Roo.lib.AnimMgr.fps;
177
178
179             this.getEl = function() {
180                 return el;
181             };
182
183
184             this.isAnimated = function() {
185                 return isAnimated;
186             };
187
188
189             this.getStartTime = function() {
190                 return startTime;
191             };
192
193             this.runtimeAttributes = {};
194
195
196             this.animate = function() {
197                 if (this.isAnimated()) {
198                     return false;
199                 }
200
201                 this.currentFrame = 0;
202
203                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
204
205                 Roo.lib.AnimMgr.registerElement(this);
206             };
207
208
209             this.stop = function(finish) {
210                 if (finish) {
211                     this.currentFrame = this.totalFrames;
212                     this._onTween.fire();
213                 }
214                 Roo.lib.AnimMgr.stop(this);
215             };
216
217             var onStart = function() {
218                 this.onStart.fire();
219
220                 this.runtimeAttributes = {};
221                 for (var attr in this.attributes) {
222                     this.setRuntimeAttribute(attr);
223                 }
224
225                 isAnimated = true;
226                 actualFrames = 0;
227                 startTime = new Date();
228             };
229
230
231             var onTween = function() {
232                 var data = {
233                     duration: new Date() - this.getStartTime(),
234                     currentFrame: this.currentFrame
235                 };
236
237                 data.toString = function() {
238                     return (
239                             'duration: ' + data.duration +
240                             ', currentFrame: ' + data.currentFrame
241                             );
242                 };
243
244                 this.onTween.fire(data);
245
246                 var runtimeAttributes = this.runtimeAttributes;
247
248                 for (var attr in runtimeAttributes) {
249                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
250                 }
251
252                 actualFrames += 1;
253             };
254
255             var onComplete = function() {
256                 var actual_duration = (new Date() - startTime) / 1000 ;
257
258                 var data = {
259                     duration: actual_duration,
260                     frames: actualFrames,
261                     fps: actualFrames / actual_duration
262                 };
263
264                 data.toString = function() {
265                     return (
266                             'duration: ' + data.duration +
267                             ', frames: ' + data.frames +
268                             ', fps: ' + data.fps
269                             );
270                 };
271
272                 isAnimated = false;
273                 actualFrames = 0;
274                 this.onComplete.fire(data);
275             };
276
277
278             this._onStart = new Roo.util.Event(this);
279             this.onStart = new Roo.util.Event(this);
280             this.onTween = new Roo.util.Event(this);
281             this._onTween = new Roo.util.Event(this);
282             this.onComplete = new Roo.util.Event(this);
283             this._onComplete = new Roo.util.Event(this);
284             this._onStart.addListener(onStart);
285             this._onTween.addListener(onTween);
286             this._onComplete.addListener(onComplete);
287         }
288     };
289 })();