Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / core / src / dom / Element.anim.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.core.Element
17  */
18 Ext.applyIf(Ext.core.Element.prototype, {
19     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
20     animate: function(config) {
21         var me = this;
22         if (!me.id) {
23             me = Ext.get(me.dom);
24         }
25         if (Ext.fx.Manager.hasFxBlock(me.id)) {
26             return me;
27         }
28         Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
29         return this;
30     },
31
32     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
33     anim: function(config) {
34         if (!Ext.isObject(config)) {
35             return (config) ? {} : false;
36         }
37
38         var me = this,
39             duration = config.duration || Ext.fx.Anim.prototype.duration,
40             easing = config.easing || 'ease',
41             animConfig;
42
43         if (config.stopAnimation) {
44             me.stopAnimation();
45         }
46
47         Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
48
49         // Clear any 'paused' defaults.
50         Ext.fx.Manager.setFxDefaults(me.id, {
51             delay: 0
52         });
53
54         animConfig = {
55             target: me,
56             remove: config.remove,
57             alternate: config.alternate || false,
58             duration: duration,
59             easing: easing,
60             callback: config.callback,
61             listeners: config.listeners,
62             iterations: config.iterations || 1,
63             scope: config.scope,
64             block: config.block,
65             concurrent: config.concurrent,
66             delay: config.delay || 0,
67             paused: true,
68             keyframes: config.keyframes,
69             from: config.from || {},
70             to: Ext.apply({}, config)
71         };
72         Ext.apply(animConfig.to, config.to);
73
74         // Anim API properties - backward compat
75         delete animConfig.to.to;
76         delete animConfig.to.from;
77         delete animConfig.to.remove;
78         delete animConfig.to.alternate;
79         delete animConfig.to.keyframes;
80         delete animConfig.to.iterations;
81         delete animConfig.to.listeners;
82         delete animConfig.to.target;
83         delete animConfig.to.paused;
84         delete animConfig.to.callback;
85         delete animConfig.to.scope;
86         delete animConfig.to.duration;
87         delete animConfig.to.easing;
88         delete animConfig.to.concurrent;
89         delete animConfig.to.block;
90         delete animConfig.to.stopAnimation;
91         delete animConfig.to.delay;
92         return animConfig;
93     },
94
95     /**
96      * Slides the element into view.  An anchor point can be optionally passed to set the point of
97      * origin for the slide effect.  This function automatically handles wrapping the element with
98      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
99      * Usage:
100      *<pre><code>
101 // default: slide the element in from the top
102 el.slideIn();
103
104 // custom: slide the element in from the right with a 2-second duration
105 el.slideIn('r', { duration: 2 });
106
107 // common config options shown with default values
108 el.slideIn('t', {
109     easing: 'easeOut',
110     duration: 500
111 });
112 </code></pre>
113      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
114      * @param {Object} options (optional) Object literal with any of the Fx config options
115      * @return {Ext.core.Element} The Element
116      */
117     slideIn: function(anchor, obj, slideOut) { 
118         var me = this,
119             elStyle = me.dom.style,
120             beforeAnim, wrapAnim;
121
122         anchor = anchor || "t";
123         obj = obj || {};
124
125         beforeAnim = function() {
126             var animScope = this,
127                 listeners = obj.listeners,
128                 box, position, restoreSize, wrap, anim;
129
130             if (!slideOut) {
131                 me.fixDisplay();
132             }
133
134             box = me.getBox();
135             if ((anchor == 't' || anchor == 'b') && box.height == 0) {
136                 box.height = me.dom.scrollHeight;
137             }
138             else if ((anchor == 'l' || anchor == 'r') && box.width == 0) {
139                 box.width = me.dom.scrollWidth;
140             }
141             
142             position = me.getPositioning();
143             me.setSize(box.width, box.height);
144
145             wrap = me.wrap({
146                 style: {
147                     visibility: slideOut ? 'visible' : 'hidden'
148                 }
149             });
150             wrap.setPositioning(position);
151             if (wrap.isStyle('position', 'static')) {
152                 wrap.position('relative');
153             }
154             me.clearPositioning('auto');
155             wrap.clip();
156
157             // This element is temporarily positioned absolute within its wrapper.
158             // Restore to its default, CSS-inherited visibility setting.
159             // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
160             me.setStyle({
161                 visibility: '',
162                 position: 'absolute'
163             });
164             if (slideOut) {
165                 wrap.setSize(box.width, box.height);
166             }
167
168             switch (anchor) {
169                 case 't':
170                     anim = {
171                         from: {
172                             width: box.width + 'px',
173                             height: '0px'
174                         },
175                         to: {
176                             width: box.width + 'px',
177                             height: box.height + 'px'
178                         }
179                     };
180                     elStyle.bottom = '0px';
181                     break;
182                 case 'l':
183                     anim = {
184                         from: {
185                             width: '0px',
186                             height: box.height + 'px'
187                         },
188                         to: {
189                             width: box.width + 'px',
190                             height: box.height + 'px'
191                         }
192                     };
193                     elStyle.right = '0px';
194                     break;
195                 case 'r':
196                     anim = {
197                         from: {
198                             x: box.x + box.width,
199                             width: '0px',
200                             height: box.height + 'px'
201                         },
202                         to: {
203                             x: box.x,
204                             width: box.width + 'px',
205                             height: box.height + 'px'
206                         }
207                     };
208                     break;
209                 case 'b':
210                     anim = {
211                         from: {
212                             y: box.y + box.height,
213                             width: box.width + 'px',
214                             height: '0px'
215                         },
216                         to: {
217                             y: box.y,
218                             width: box.width + 'px',
219                             height: box.height + 'px'
220                         }
221                     };
222                     break;
223                 case 'tl':
224                     anim = {
225                         from: {
226                             x: box.x,
227                             y: box.y,
228                             width: '0px',
229                             height: '0px'
230                         },
231                         to: {
232                             width: box.width + 'px',
233                             height: box.height + 'px'
234                         }
235                     };
236                     elStyle.bottom = '0px';
237                     elStyle.right = '0px';
238                     break;
239                 case 'bl':
240                     anim = {
241                         from: {
242                             x: box.x + box.width,
243                             width: '0px',
244                             height: '0px'
245                         },
246                         to: {
247                             x: box.x,
248                             width: box.width + 'px',
249                             height: box.height + 'px'
250                         }
251                     };
252                     elStyle.right = '0px';
253                     break;
254                 case 'br':
255                     anim = {
256                         from: {
257                             x: box.x + box.width,
258                             y: box.y + box.height,
259                             width: '0px',
260                             height: '0px'
261                         },
262                         to: {
263                             x: box.x,
264                             y: box.y,
265                             width: box.width + 'px',
266                             height: box.height + 'px'
267                         }
268                     };
269                     break;
270                 case 'tr':
271                     anim = {
272                         from: {
273                             y: box.y + box.height,
274                             width: '0px',
275                             height: '0px'
276                         },
277                         to: {
278                             y: box.y,
279                             width: box.width + 'px',
280                             height: box.height + 'px'
281                         }
282                     };
283                     elStyle.bottom = '0px';
284                     break;
285             }
286
287             wrap.show();
288             wrapAnim = Ext.apply({}, obj);
289             delete wrapAnim.listeners;
290             wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
291                 target: wrap,
292                 duration: 500,
293                 easing: 'ease-out',
294                 from: slideOut ? anim.to : anim.from,
295                 to: slideOut ? anim.from : anim.to
296             }));
297
298             // In the absence of a callback, this listener MUST be added first
299             wrapAnim.on('afteranimate', function() {
300                 if (slideOut) {
301                     me.setPositioning(position);
302                     if (obj.useDisplay) {
303                         me.setDisplayed(false);
304                     } else {
305                         me.hide();   
306                     }
307                 }
308                 else {
309                     me.clearPositioning();
310                     me.setPositioning(position);
311                 }
312                 if (wrap.dom) {
313                     wrap.dom.parentNode.insertBefore(me.dom, wrap.dom); 
314                     wrap.remove();
315                 }
316                 me.setSize(box.width, box.height);
317                 animScope.end();
318             });
319             // Add configured listeners after
320             if (listeners) {
321                 wrapAnim.on(listeners);
322             }
323         };
324
325         me.animate({
326             duration: obj.duration ? obj.duration * 2 : 1000,
327             listeners: {
328                 beforeanimate: {
329                     fn: beforeAnim
330                 },
331                 afteranimate: {
332                     fn: function() {
333                         if (wrapAnim && wrapAnim.running) {
334                             wrapAnim.end();
335                         }
336                     }
337                 }
338             }
339         });
340         return me;
341     },
342
343     
344     /**
345      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
346      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
347      * 'hidden') but block elements will still take up space in the document.  The element must be removed
348      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
349      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
350      * Usage:
351      *<pre><code>
352 // default: slide the element out to the top
353 el.slideOut();
354
355 // custom: slide the element out to the right with a 2-second duration
356 el.slideOut('r', { duration: 2 });
357
358 // common config options shown with default values
359 el.slideOut('t', {
360     easing: 'easeOut',
361     duration: 500,
362     remove: false,
363     useDisplay: false
364 });
365 </code></pre>
366      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
367      * @param {Object} options (optional) Object literal with any of the Fx config options
368      * @return {Ext.core.Element} The Element
369      */
370     slideOut: function(anchor, o) {
371         return this.slideIn(anchor, o, true);
372     },
373
374     /**
375      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
376      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
377      * Usage:
378      *<pre><code>
379 // default
380 el.puff();
381
382 // common config options shown with default values
383 el.puff({
384     easing: 'easeOut',
385     duration: 500,
386     useDisplay: false
387 });
388 </code></pre>
389      * @param {Object} options (optional) Object literal with any of the Fx config options
390      * @return {Ext.core.Element} The Element
391      */
392
393     puff: function(obj) {
394         var me = this,
395             beforeAnim;
396         obj = Ext.applyIf(obj || {}, {
397             easing: 'ease-out',
398             duration: 500,
399             useDisplay: false
400         });
401
402         beforeAnim = function() {
403             me.clearOpacity();
404             me.show();
405
406             var box = me.getBox(),
407                 fontSize = me.getStyle('fontSize'),
408                 position = me.getPositioning();
409             this.to = {
410                 width: box.width * 2,
411                 height: box.height * 2,
412                 x: box.x - (box.width / 2),
413                 y: box.y - (box.height /2),
414                 opacity: 0,
415                 fontSize: '200%'
416             };
417             this.on('afteranimate',function() {
418                 if (me.dom) {
419                     if (obj.useDisplay) {
420                         me.setDisplayed(false);
421                     } else {
422                         me.hide();
423                     }
424                     me.clearOpacity();  
425                     me.setPositioning(position);
426                     me.setStyle({fontSize: fontSize});
427                 }
428             });
429         };
430
431         me.animate({
432             duration: obj.duration,
433             easing: obj.easing,
434             listeners: {
435                 beforeanimate: {
436                     fn: beforeAnim
437                 }
438             }
439         });
440         return me;
441     },
442
443     /**
444      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
445      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
446      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
447      * Usage:
448      *<pre><code>
449 // default
450 el.switchOff();
451
452 // all config options shown with default values
453 el.switchOff({
454     easing: 'easeIn',
455     duration: .3,
456     remove: false,
457     useDisplay: false
458 });
459 </code></pre>
460      * @param {Object} options (optional) Object literal with any of the Fx config options
461      * @return {Ext.core.Element} The Element
462      */
463     switchOff: function(obj) {
464         var me = this,
465             beforeAnim;
466         
467         obj = Ext.applyIf(obj || {}, {
468             easing: 'ease-in',
469             duration: 500,
470             remove: false,
471             useDisplay: false
472         });
473
474         beforeAnim = function() {
475             var animScope = this,
476                 size = me.getSize(),
477                 xy = me.getXY(),
478                 keyframe, position;
479             me.clearOpacity();
480             me.clip();
481             position = me.getPositioning();
482
483             keyframe = Ext.create('Ext.fx.Animator', {
484                 target: me,
485                 duration: obj.duration,
486                 easing: obj.easing,
487                 keyframes: {
488                     33: {
489                         opacity: 0.3
490                     },
491                     66: {
492                         height: 1,
493                         y: xy[1] + size.height / 2
494                     },
495                     100: {
496                         width: 1,
497                         x: xy[0] + size.width / 2
498                     }
499                 }
500             });
501             keyframe.on('afteranimate', function() {
502                 if (obj.useDisplay) {
503                     me.setDisplayed(false);
504                 } else {
505                     me.hide();
506                 }  
507                 me.clearOpacity();
508                 me.setPositioning(position);
509                 me.setSize(size);
510                 animScope.end();
511             });
512         };
513         me.animate({
514             duration: (obj.duration * 2),
515             listeners: {
516                 beforeanimate: {
517                     fn: beforeAnim
518                 }
519             }
520         });
521         return me;
522     },
523
524    /**
525     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
526     * Usage:
527 <pre><code>
528 // default: a single light blue ripple
529 el.frame();
530
531 // custom: 3 red ripples lasting 3 seconds total
532 el.frame("#ff0000", 3, { duration: 3 });
533
534 // common config options shown with default values
535 el.frame("#C3DAF9", 1, {
536     duration: 1 //duration of each individual ripple.
537     // Note: Easing is not configurable and will be ignored if included
538 });
539 </code></pre>
540     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
541     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
542     * @param {Object} options (optional) Object literal with any of the Fx config options
543     * @return {Ext.core.Element} The Element
544     */
545     frame : function(color, count, obj){
546         var me = this,
547             beforeAnim;
548
549         color = color || '#C3DAF9';
550         count = count || 1;
551         obj = obj || {};
552
553         beforeAnim = function() {
554             me.show();
555             var animScope = this,
556                 box = me.getBox(),
557                 proxy = Ext.getBody().createChild({
558                     style: {
559                         position : 'absolute',
560                         'pointer-events': 'none',
561                         'z-index': 35000,
562                         border : '0px solid ' + color
563                     }
564                 }),
565                 proxyAnim;
566             proxyAnim = Ext.create('Ext.fx.Anim', {
567                 target: proxy,
568                 duration: obj.duration || 1000,
569                 iterations: count,
570                 from: {
571                     top: box.y,
572                     left: box.x,
573                     borderWidth: 0,
574                     opacity: 1,
575                     height: box.height,
576                     width: box.width
577                 },
578                 to: {
579                     top: box.y - 20,
580                     left: box.x - 20,
581                     borderWidth: 10,
582                     opacity: 0,
583                     height: box.height + 40,
584                     width: box.width + 40
585                 }
586             });
587             proxyAnim.on('afteranimate', function() {
588                 proxy.remove();
589                 animScope.end();
590             });
591         };
592
593         me.animate({
594             duration: (obj.duration * 2) || 2000,
595             listeners: {
596                 beforeanimate: {
597                     fn: beforeAnim
598                 }
599             }
600         });
601         return me;
602     },
603
604     /**
605      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
606      * ending point of the effect.
607      * Usage:
608      *<pre><code>
609 // default: slide the element downward while fading out
610 el.ghost();
611
612 // custom: slide the element out to the right with a 2-second duration
613 el.ghost('r', { duration: 2 });
614
615 // common config options shown with default values
616 el.ghost('b', {
617     easing: 'easeOut',
618     duration: 500
619 });
620 </code></pre>
621      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
622      * @param {Object} options (optional) Object literal with any of the Fx config options
623      * @return {Ext.core.Element} The Element
624      */
625     ghost: function(anchor, obj) {
626         var me = this,
627             beforeAnim;
628
629         anchor = anchor || "b";
630         beforeAnim = function() {
631             var width = me.getWidth(),
632                 height = me.getHeight(),
633                 xy = me.getXY(),
634                 position = me.getPositioning(),
635                 to = {
636                     opacity: 0
637                 };
638             switch (anchor) {
639                 case 't':
640                     to.y = xy[1] - height;
641                     break;
642                 case 'l':
643                     to.x = xy[0] - width;
644                     break;
645                 case 'r':
646                     to.x = xy[0] + width;
647                     break;
648                 case 'b':
649                     to.y = xy[1] + height;
650                     break;
651                 case 'tl':
652                     to.x = xy[0] - width;
653                     to.y = xy[1] - height;
654                     break;
655                 case 'bl':
656                     to.x = xy[0] - width;
657                     to.y = xy[1] + height;
658                     break;
659                 case 'br':
660                     to.x = xy[0] + width;
661                     to.y = xy[1] + height;
662                     break;
663                 case 'tr':
664                     to.x = xy[0] + width;
665                     to.y = xy[1] - height;
666                     break;
667             }
668             this.to = to;
669             this.on('afteranimate', function () {
670                 if (me.dom) {
671                     me.hide();
672                     me.clearOpacity();
673                     me.setPositioning(position);
674                 }
675             });
676         };
677
678         me.animate(Ext.applyIf(obj || {}, {
679             duration: 500,
680             easing: 'ease-out',
681             listeners: {
682                 beforeanimate: {
683                     fn: beforeAnim
684                 }
685             }
686         }));
687         return me;
688     },
689
690     /**
691      * Highlights the Element by setting a color (applies to the background-color by default, but can be
692      * changed using the "attr" config option) and then fading back to the original color. If no original
693      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
694      * Usage:
695 <pre><code>
696 // default: highlight background to yellow
697 el.highlight();
698
699 // custom: highlight foreground text to blue for 2 seconds
700 el.highlight("0000ff", { attr: 'color', duration: 2 });
701
702 // common config options shown with default values
703 el.highlight("ffff9c", {
704     attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
705     endColor: (current color) or "ffffff",
706     easing: 'easeIn',
707     duration: 1000
708 });
709 </code></pre>
710      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
711      * @param {Object} options (optional) Object literal with any of the Fx config options
712      * @return {Ext.core.Element} The Element
713      */ 
714     highlight: function(color, o) {
715         var me = this,
716             dom = me.dom,
717             from = {},
718             restore, to, attr, lns, event, fn;
719
720         o = o || {};
721         lns = o.listeners || {};
722         attr = o.attr || 'backgroundColor';
723         from[attr] = color || 'ffff9c';
724         
725         if (!o.to) {
726             to = {};
727             to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
728         }
729         else {
730             to = o.to;
731         }
732         
733         // Don't apply directly on lns, since we reference it in our own callbacks below
734         o.listeners = Ext.apply(Ext.apply({}, lns), {
735             beforeanimate: function() {
736                 restore = dom.style[attr];
737                 me.clearOpacity();
738                 me.show();
739                 
740                 event = lns.beforeanimate;
741                 if (event) {
742                     fn = event.fn || event;
743                     return fn.apply(event.scope || lns.scope || window, arguments);
744                 }
745             },
746             afteranimate: function() {
747                 if (dom) {
748                     dom.style[attr] = restore;
749                 }
750                 
751                 event = lns.afteranimate;
752                 if (event) {
753                     fn = event.fn || event;
754                     fn.apply(event.scope || lns.scope || window, arguments);
755                 }
756             }
757         });
758
759         me.animate(Ext.apply({}, o, {
760             duration: 1000,
761             easing: 'ease-in',
762             from: from,
763             to: to
764         }));
765         return me;
766     },
767
768    /**
769     * @deprecated 4.0
770     * Creates a pause before any subsequent queued effects begin.  If there are
771     * no effects queued after the pause it will have no effect.
772     * Usage:
773 <pre><code>
774 el.pause(1);
775 </code></pre>
776     * @param {Number} seconds The length of time to pause (in seconds)
777     * @return {Ext.Element} The Element
778     */
779     pause: function(ms) {
780         var me = this;
781         Ext.fx.Manager.setFxDefaults(me.id, {
782             delay: ms
783         });
784         return me;
785     },
786
787    /**
788     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
789     * using the <tt>{@link #endOpacity}</tt> config option.
790     * Usage:
791 <pre><code>
792 // default: fade in from opacity 0 to 100%
793 el.fadeIn();
794
795 // custom: fade in from opacity 0 to 75% over 2 seconds
796 el.fadeIn({ endOpacity: .75, duration: 2});
797
798 // common config options shown with default values
799 el.fadeIn({
800     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
801     easing: 'easeOut',
802     duration: 500
803 });
804 </code></pre>
805     * @param {Object} options (optional) Object literal with any of the Fx config options
806     * @return {Ext.Element} The Element
807     */
808     fadeIn: function(o) {
809         this.animate(Ext.apply({}, o, {
810             opacity: 1
811         }));
812         return this;
813     },
814
815    /**
816     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
817     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
818     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
819     * Usage:
820 <pre><code>
821 // default: fade out from the element's current opacity to 0
822 el.fadeOut();
823
824 // custom: fade out from the element's current opacity to 25% over 2 seconds
825 el.fadeOut({ endOpacity: .25, duration: 2});
826
827 // common config options shown with default values
828 el.fadeOut({
829     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
830     easing: 'easeOut',
831     duration: 500,
832     remove: false,
833     useDisplay: false
834 });
835 </code></pre>
836     * @param {Object} options (optional) Object literal with any of the Fx config options
837     * @return {Ext.Element} The Element
838     */
839     fadeOut: function(o) {
840         this.animate(Ext.apply({}, o, {
841             opacity: 0
842         }));
843         return this;
844     },
845
846    /**
847     * @deprecated 4.0
848     * Animates the transition of an element's dimensions from a starting height/width
849     * to an ending height/width.  This method is a convenience implementation of {@link #shift}.
850     * Usage:
851 <pre><code>
852 // change height and width to 100x100 pixels
853 el.scale(100, 100);
854
855 // common config options shown with default values.  The height and width will default to
856 // the element&#39;s existing values if passed as null.
857 el.scale(
858     [element&#39;s width],
859     [element&#39;s height], {
860         easing: 'easeOut',
861         duration: .35
862     }
863 );
864 </code></pre>
865     * @param {Number} width  The new width (pass undefined to keep the original width)
866     * @param {Number} height  The new height (pass undefined to keep the original height)
867     * @param {Object} options (optional) Object literal with any of the Fx config options
868     * @return {Ext.Element} The Element
869     */
870     scale: function(w, h, o) {
871         this.animate(Ext.apply({}, o, {
872             width: w,
873             height: h
874         }));
875         return this;
876     },
877
878    /**
879     * @deprecated 4.0
880     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
881     * Any of these properties not specified in the config object will not be changed.  This effect 
882     * requires that at least one new dimension, position or opacity setting must be passed in on
883     * the config object in order for the function to have any effect.
884     * Usage:
885 <pre><code>
886 // slide the element horizontally to x position 200 while changing the height and opacity
887 el.shift({ x: 200, height: 50, opacity: .8 });
888
889 // common config options shown with default values.
890 el.shift({
891     width: [element&#39;s width],
892     height: [element&#39;s height],
893     x: [element&#39;s x position],
894     y: [element&#39;s y position],
895     opacity: [element&#39;s opacity],
896     easing: 'easeOut',
897     duration: .35
898 });
899 </code></pre>
900     * @param {Object} options  Object literal with any of the Fx config options
901     * @return {Ext.Element} The Element
902     */
903     shift: function(config) {
904         this.animate(config);
905         return this;
906     }
907 });
908