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 forfxprop: 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.