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