The jQuery's fx
object forms the core of all jQuery effects. In its essence, this object handles CSS styles and timers used during jQuery's effects. In fact, all jQuery's effects are basically a combination of CSS properties and timers. When you have to create an effect, you have to keep track both of the current style property and the interval when your style change occurs. jQuery handles this task with steps. A step is a fragment of an effect. Each effect can be actually broken down into several steps. For example, when you call the hide()
method, the CSS display
property is set to none
. If you don't use steps, this effect will be immediate. Instead, with steps you can add a certain delay to this transition, for example by specifying slow
as the first parameter of this method.
The fx
object is declared as follows:
fx: function( elem, options, prop ) { this.options = options; this.elem = elem; this.prop = prop; if ( !options.orig ) { options.orig = {}; } }
This object has three properties:
elem
: the element where the effect takes placeoptions
: an object containing all the settings forfx
prop
: the CSS property currently in use.
Then the prototype
object of fx
is augmented with several private methods. The first is update()
:
// Simple function for setting a style value update: function() { if ( this.options.step ) { this.options.step.call( this.elem, this.now, this ); } (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); }
In this case, the step()
method is called to change a style property on a specific moment during the progress of the effect. The comes the cur()
method:
cur: function() { if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) { return this.elem[ this.prop ]; } var r = parseFloat( jQuery.css( this.elem, this.prop ) ); return r || 0; }
This method returns the current numeric value of a CSS property that specifies a length. For example, CSS properties such as top
, margin
andwidth
all have a numeric value. The next method, custom()
, actually handles animations:
custom: function( from, to, unit ) { var self = this, fx = jQuery.fx; this.startTime = jQuery.now(); this.start = from; this.end = to; this.unit = unit || this.unit || "px"; this.now = this.start; this.pos = this.state = 0; function t( gotoEnd ) { return self.step(gotoEnd); } t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { timerId = setInterval(fx.tick, fx.interval); } }
This method starts an animation from one number to another. If no unit is provided, all values are treated as pixels. An animation is divided into three phases:
- start: the origin of the animation
- destination: the target state of an element after an animation is complete (e.g, its position on the viewport)
- end: the end of the animation.
The most important method is surely step()
. It is as follows:
step: function( gotoEnd ) { var t = jQuery.now(), done = true; if ( gotoEnd || t >= this.options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); this.options.curAnim[ this.prop ] = true; for ( var i in this.options.curAnim ) { if ( this.options.curAnim[i] !== true ) { done = false; } } if ( done ) { // Reset the overflow if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { var elem = this.elem, options = this.options; jQuery.each( [ "", "X", "Y" ], function (index, value) { elem.style[ "overflow" + value ] = options.overflow[index]; } ); } // Hide the element if the "hide" operation was done if ( this.options.hide ) { jQuery(this.elem).hide(); } // Reset the properties, if the item has been hidden or shown if ( this.options.hide || this.options.show ) { for ( var p in this.options.curAnim ) { jQuery.style( this.elem, p, this.options.orig[p] ); } } // Execute the complete function this.options.complete.call( this.elem ); } return false; } else { var n = t - this.startTime; this.state = n / this.options.duration; // Perform the easing function, defaults to swing var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop]; var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear"); this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration); this.now = this.start + ((this.end - this.start) * this.pos); // Perform the next step of the animation this.update(); } return true; }
First, this method uses the done
private property to check whether an animation has reached its final state. If so, all CSS properties are changed and then the callback function of each animation is executed (of course if such a callback function has been provided). Otherwise, the animation is started and its steps are all performed by the update()
method. Note that in this case both the duration
and easing
options are used.