Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / fx / PropertyHandler.js
1 /**
2  * @class Ext.fx.PropertyHandler
3  * @ignore
4  */
5 Ext.define('Ext.fx.PropertyHandler', {
6
7     /* Begin Definitions */
8
9     requires: ['Ext.draw.Draw'],
10
11     statics: {
12         defaultHandler: {
13             pixelDefaults: ['width', 'height', 'top', 'left'],
14             unitRE: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/,
15
16             computeDelta: function(from, end, damper, initial, attr) {
17                 damper = (typeof damper == 'number') ? damper : 1;
18                 var match = this.unitRE.exec(from),
19                     start, units;
20                 if (match) {
21                     from = match[1];
22                     units = match[2];
23                     if (!units && Ext.Array.contains(this.pixelDefaults, attr)) {
24                         units = 'px';
25                     }
26                 }
27                 from = +from || 0;
28
29                 match = this.unitRE.exec(end);
30                 if (match) {
31                     end = match[1];
32                     units = match[2] || units;
33                 }
34                 end = +end || 0;
35                 start = (initial != null) ? initial : from;
36                 return {
37                     from: from,
38                     delta: (end - start) * damper,
39                     units: units
40                 };
41             },
42
43             get: function(from, end, damper, initialFrom, attr) {
44                 var ln = from.length,
45                     out = [],
46                     i, initial, res, j, len;
47                 for (i = 0; i < ln; i++) {
48                     if (initialFrom) {
49                         initial = initialFrom[i][1].from;
50                     }
51                     if (Ext.isArray(from[i][1]) && Ext.isArray(end)) {
52                         res = [];
53                         j = 0;
54                         len = from[i][1].length;
55                         for (; j < len; j++) {
56                             res.push(this.computeDelta(from[i][1][j], end[j], damper, initial, attr));
57                         }
58                         out.push([from[i][0], res]);
59                     }
60                     else {
61                         out.push([from[i][0], this.computeDelta(from[i][1], end, damper, initial, attr)]);
62                     }
63                 }
64                 return out;
65             },
66
67             set: function(values, easing) {
68                 var ln = values.length,
69                     out = [],
70                     i, val, res, len, j;
71                 for (i = 0; i < ln; i++) {
72                     val  = values[i][1];
73                     if (Ext.isArray(val)) {
74                         res = [];
75                         j = 0;
76                         len = val.length;
77                         for (; j < len; j++) {
78                             res.push(val[j].from + (val[j].delta * easing) + (val[j].units || 0));
79                         }
80                         out.push([values[i][0], res]);
81                     } else {
82                         out.push([values[i][0], val.from + (val.delta * easing) + (val.units || 0)]);
83                     }
84                 }
85                 return out;
86             }
87         },
88         color: {
89             rgbRE: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
90             hexRE: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
91             hex3RE: /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i,
92
93             parseColor : function(color, damper) {
94                 damper = (typeof damper == 'number') ? damper : 1;
95                 var base,
96                     out = false,
97                     match;
98
99                 Ext.each([this.hexRE, this.rgbRE, this.hex3RE], function(re, idx) {
100                     base = (idx % 2 == 0) ? 16 : 10;
101                     match = re.exec(color);
102                     if (match && match.length == 4) {
103                         if (idx == 2) {
104                             match[1] += match[1];
105                             match[2] += match[2];
106                             match[3] += match[3];
107                         }
108                         out = {
109                             red: parseInt(match[1], base),
110                             green: parseInt(match[2], base),
111                             blue: parseInt(match[3], base)
112                         };
113                         return false;
114                     }
115                 });
116                 return out || color;
117             },
118
119             computeDelta: function(from, end, damper, initial) {
120                 from = this.parseColor(from);
121                 end = this.parseColor(end, damper);
122                 var start = initial ? initial : from,
123                     tfrom = typeof start,
124                     tend = typeof end;
125                 //Extra check for when the color string is not recognized.
126                 if (tfrom == 'string' ||  tfrom == 'undefined' 
127                   || tend == 'string' || tend == 'undefined') {
128                     return end || start;
129                 }
130                 return {
131                     from:  from,
132                     delta: {
133                         red: Math.round((end.red - start.red) * damper),
134                         green: Math.round((end.green - start.green) * damper),
135                         blue: Math.round((end.blue - start.blue) * damper)
136                     }
137                 };
138             },
139
140             get: function(start, end, damper, initialFrom) {
141                 var ln = start.length,
142                     out = [],
143                     i, initial;
144                 for (i = 0; i < ln; i++) {
145                     if (initialFrom) {
146                         initial = initialFrom[i][1].from;
147                     }
148                     out.push([start[i][0], this.computeDelta(start[i][1], end, damper, initial)]);
149                 }
150                 return out;
151             },
152
153             set: function(values, easing) {
154                 var ln = values.length,
155                     out = [],
156                     i, val, parsedString, from, delta;
157                 for (i = 0; i < ln; i++) {
158                     val = values[i][1];
159                     if (val) {
160                         from = val.from;
161                         delta = val.delta;
162                         //multiple checks to reformat the color if it can't recognized by computeDelta.
163                         val = (typeof val == 'object' && 'red' in val)? 
164                                 'rgb(' + val.red + ', ' + val.green + ', ' + val.blue + ')' : val;
165                         val = (typeof val == 'object' && val.length)? val[0] : val;
166                         if (typeof val == 'undefined') {
167                             return [];
168                         }
169                         parsedString = typeof val == 'string'? val :
170                             'rgb(' + [
171                                   (from.red + Math.round(delta.red * easing)) % 256,
172                                   (from.green + Math.round(delta.green * easing)) % 256,
173                                   (from.blue + Math.round(delta.blue * easing)) % 256
174                               ].join(',') + ')';
175                         out.push([
176                             values[i][0],
177                             parsedString
178                         ]);
179                     }
180                 }
181                 return out;
182             }
183         },
184         object: {
185             interpolate: function(prop, damper) {
186                 damper = (typeof damper == 'number') ? damper : 1;
187                 var out = {},
188                     p;
189                 for(p in prop) {
190                     out[p] = parseInt(prop[p], 10) * damper;
191                 }
192                 return out;
193             },
194
195             computeDelta: function(from, end, damper, initial) {
196                 from = this.interpolate(from);
197                 end = this.interpolate(end, damper);
198                 var start = initial ? initial : from,
199                     delta = {},
200                     p;
201
202                 for(p in end) {
203                     delta[p] = end[p] - start[p];
204                 }
205                 return {
206                     from:  from,
207                     delta: delta
208                 };
209             },
210
211             get: function(start, end, damper, initialFrom) {
212                 var ln = start.length,
213                     out = [],
214                     i, initial;
215                 for (i = 0; i < ln; i++) {
216                     if (initialFrom) {
217                         initial = initialFrom[i][1].from;
218                     }
219                     out.push([start[i][0], this.computeDelta(start[i][1], end, damper, initial)]);
220                 }
221                 return out;
222             },
223
224             set: function(values, easing) {
225                 var ln = values.length,
226                     out = [],
227                     outObject = {},
228                     i, from, delta, val, p;
229                 for (i = 0; i < ln; i++) {
230                     val  = values[i][1];
231                     from = val.from;
232                     delta = val.delta;
233                     for (p in from) {
234                         outObject[p] = Math.round(from[p] + delta[p] * easing);
235                     }
236                     out.push([
237                         values[i][0],
238                         outObject
239                     ]);
240                 }
241                 return out;
242             }
243         },
244
245         path: {
246             computeDelta: function(from, end, damper, initial) {
247                 damper = (typeof damper == 'number') ? damper : 1;
248                 var start;
249                 from = +from || 0;
250                 end = +end || 0;
251                 start = (initial != null) ? initial : from;
252                 return {
253                     from: from,
254                     delta: (end - start) * damper
255                 };
256             },
257
258             forcePath: function(path) {
259                 if (!Ext.isArray(path) && !Ext.isArray(path[0])) {
260                     path = Ext.draw.Draw.parsePathString(path);
261                 }
262                 return path;
263             },
264
265             get: function(start, end, damper, initialFrom) {
266                 var endPath = this.forcePath(end),
267                     out = [],
268                     startLn = start.length,
269                     startPathLn, pointsLn, i, deltaPath, initial, j, k, path, startPath;
270                 for (i = 0; i < startLn; i++) {
271                     startPath = this.forcePath(start[i][1]);
272
273                     deltaPath = Ext.draw.Draw.interpolatePaths(startPath, endPath);
274                     startPath = deltaPath[0];
275                     endPath = deltaPath[1];
276
277                     startPathLn = startPath.length;
278                     path = [];
279                     for (j = 0; j < startPathLn; j++) {
280                         deltaPath = [startPath[j][0]];
281                         pointsLn = startPath[j].length;
282                         for (k = 1; k < pointsLn; k++) {
283                             initial = initialFrom && initialFrom[0][1][j][k].from;
284                             deltaPath.push(this.computeDelta(startPath[j][k], endPath[j][k], damper, initial));
285                         }
286                         path.push(deltaPath);
287                     }
288                     out.push([start[i][0], path]);
289                 }
290                 return out;
291             },
292
293             set: function(values, easing) {
294                 var ln = values.length,
295                     out = [],
296                     i, j, k, newPath, calcPath, deltaPath, deltaPathLn, pointsLn;
297                 for (i = 0; i < ln; i++) {
298                     deltaPath = values[i][1];
299                     newPath = [];
300                     deltaPathLn = deltaPath.length;
301                     for (j = 0; j < deltaPathLn; j++) {
302                         calcPath = [deltaPath[j][0]];
303                         pointsLn = deltaPath[j].length;
304                         for (k = 1; k < pointsLn; k++) {
305                             calcPath.push(deltaPath[j][k].from + deltaPath[j][k].delta * easing);
306                         }
307                         newPath.push(calcPath.join(','));
308                     }
309                     out.push([values[i][0], newPath.join(',')]);
310                 }
311                 return out;
312             }
313         }
314         /* End Definitions */
315     }
316 }, function() {
317     Ext.each([
318         'outlineColor',
319         'backgroundColor',
320         'borderColor',
321         'borderTopColor',
322         'borderRightColor', 
323         'borderBottomColor', 
324         'borderLeftColor',
325         'fill',
326         'stroke'
327     ], function(prop) {
328         this[prop] = this.color;
329     }, this);
330 });