Demo

Mootools Chaining for Image Effects

May 18th, 2009  |  Published in Chaining, Demo, Image Effects, Javascript, Mootools

The internet abounds with JavaScript code samples that produce various fade effects on images. The multitude (some might say excess) of gallery slideshows attest to the popularity of this type of application.  A huge help has been the development of JavaScript frameworks like Mootools and jQuery, which make it incredibly easy to produce simple image effects and even chain them together to achieve more complex results.

One thing you don’t see a lot of, though, are image gallery applications where the effects are triggered to begin at arbitrary time intervals.  For example, say you have a large group of images to which you’re going to apply individual fade-in effects.  Not hard to do, but what if you want to have the fade-in for the next image begin before the effect on the preceeding image (or several preceeding images) has completed?  That’s the question I asked myself: for me the answer was MooGal, a small class I wrote with the help of Mootools.

Instead of sitting there scratching your head and wondering exactly what I’m talking about, please click Here to see a demo of the effect in action.

Let’s take a look at some of the code, shall we?

var MooGal = new Class({
	Implements: [Chain, Options],

	options: {
		duration: 3000,
		delay: 400,
		transition: Fx.Transitions.Sine.easeInOut
	},

	initialize: function(gallery, options){
		this.gallery = $$(gallery).length == 0 ? $$('.' + gallery) : $$(gallery);
		if (!this.gallery.length) return;
		this.setOptions(options);
		this.timerArray = [];
		this.gallerySort();
		this.galleryFx();
		this.load();
	},

By implementing the Chain class we put its methods and properties at the disposal of MooGal. In the demo, the initialize method takes a CSS class selector (”.moogal”) and uses the default options to set the duration, delay and transition effect. The moogal class consists of a number of unordered list elements, each wrapping an image element. Because each of these elements will have its own Fx.Tween instance and basically be independent of one another, this.timerArray is set up to hold the timer ids associated with the function delays that control the overall timing.

The next two key methods are galleryFx() and load():

/**
Creates a tween instance for each element and stores it in the
element.
*/
	galleryFx: function(){
		this.gallery.each(function(picture){
			picture.store('fx', new Fx.Tween(picture,
            {property:'opacity', duration:this.options.duration,
            link:'cancel', transition:this.options.transition}));
		}, this);
		return this.gallery;
	},

/**
Retrieves tween instances and places them on the call stack.
*/
	load: function(){
		this.clearChain(); // clear the call stack of any remaining tween instances.
		this.gallery.each(function(picture){
			this.chain(
				function() {picture.retrieve('fx').set(0).start(1);}
			);
		}, this);
	},

The load() method is where we want to focus our attention. It takes the Fx.Tween instances that were created in galleryFx() and uses the chain() method to place them on our class’ call stack. What this really does is load these function definitions into an internal Mootools array called $chain. One of the interesting things about JavaScript is that you can treat functions like data and load them into arrays, assign references to them in variables, etc. But the important thing to note is that this.chain simply gets our functions ready: it does not invoke them. That comes later with the run() method:

	run: function() {
		var i = 0;
		// $chain is an internal Mootools array that holds the chained functions.
		var chainLength = this.$chain.length;
		while (i < chainLength) {
			// set up delays and start running the transitions one after another.
			// binding is tricky here.
			// with a default delay of 400ms, the first effect starts at t=0, the second at t=0.4sec,
			// the third at t=0.8sec, the fourth at t=1.2sec, etc.
			this.timer = (function() {this.callChain();}.bind(this)).delay(i * this.options.delay);
			this.timerArray[i] = this.timer; // store timer ids in a timer array.
			i++;
		}
		return this;
	}

The run() method takes whatever Fx.Tween instances are remaining on the call stack and employs the callChain method to execute them. The most critical part of the entire class, however, is the use of the delay method, which essentially staggers their execution out in time. The reason for using the $chain array and storing the timer ids in this.timerArray is due to the cancel() method:

	cancel: function(cancelled){
		if (cancelled){
			this.clearChain();
			this.gallery.each(function(picture){
				picture.retrieve('fx').cancel().set(0);
			});
		}
		// clear the timers to prevent any more transitions from starting.
		for (i = 0; i < this.timerArray.length; i++){
			$clear(this.timerArray[i]);
		}
		this.timerArray.empty(); // empty the timer id array.
	},

In other words, we need to be able to clear all the timers so that any remaining delayed functions are prevented from happening if the effects are cancelled or paused. The $chain array holds the “unused” Fx.Tween instances we’ll need if the action is resumed, as is possible in the demo.

To make the timing more apparent, you can lengthen the duration option in relation to the delay. If you’d like to download the MooGal code and play around with it, please get it here.

Chaining Functions in Mootools for Dynamic Text Effects

February 28th, 2009  |  Published in Chaining, Demo, Javascript, Mootools, Text Effects

First, click HERE so you can see what I’ll be referring to below.

Dynamic text effects (fade ins, moving text, etc.) can enhance the viewer experience by directing attention to specific (and presumably important) areas of the page.  All well and good.  But how do you do this?

Some of the things I like about Mootools are its class-oriented approach, its outstanding plugins and the ease with which you can put together complex effects.  But we won’t be creating a class here.  We’re going to keep this real simple…

I recently needed to animate some text on a page: specifically, I had to fade in several (distinct) elements in the page header, and produce a fade-in/fly-in effect for some text in the main content area.  By itself, this wasn’t hard to do but the kicker was that the effect for each element had to fire off in sequence, one after the other.  It had to go Snap, Crackle, Pop!  What I didn’t want was for the effects to fire together because then I’d end up with a snapplepopackle mess.

So I turned to the Mootools Chain class for assistance.  Let’s look at the code behind the demo page; it’s short and to the point.  Relatively speaking, that is.

	window.addEvent('domready', function(){

		var fnChain = new Chain();
		var hdrItems = $$('.sub-header-item');
		var sayings = $$('.saying');

		hdrItems.each(function(item) {
			item.setStyle('opacity', 0);
			item.set('morph', {
				duration: 1200,
				onComplete: function(){fnChain.callChain()}
			});
			fnChain.chain(
				function(){item.morph({
					opacity: 1,
					backgroundColor: '#fff',
					borderColor: '#fff',
					color: '#002a46'});
				}
			);
		});

		sayings.each(function(saying) {
			saying.setStyle('opacity', 0);
			saying.set('morph', {
				duration: 800,
				transition: Fx.Transitions.Bounce.easeOut,
				onComplete: function(){fnChain.callChain()}
			});
		});

		fnChain.chain(
			function(){$('where').morph({opacity: 1, left: 180});},
			function(){$('when').morph({opacity: 1, right: 185});},
			function(){$('final').morph({opacity: 1});}
		);

		(function(){fnChain.callChain();}).delay(1000);

	});

Let’s start at the top and work our way  down.  Within the ‘domready’ event handler code, we first create an instance of the Mootools Chain class and stick a reference to it in fnChain.  Then we create a couple of local variables to hold references to the elements we want to apply the effects to.

Next we iterate over the elements containing the header text in the hdrItems array and do several things: first we set the opacity to 0 so that they’re invisible when the page loads; second, we create default instances of Fx.Morph for each element in the array (we’ll come back to this in a second); third, we take our default Fx.Morph instances, apply the morph method to generate a transition and load this onto the fnChain call stack.

Here’s the important thing about getting the Mootools Chain class to do what you want: using the chain and callChain methods is analogous to loading and firing a gun.  The analogy works like this: calling the chain method simply loads the gun with bullets, whereas invoking callChain fires a single bullet.  Okay, that isn’t too hard to grasp … wait, there’s something missing.  Ah, the finger that pulls the trigger!  We kind of need that, don’t we?

That’s where the onComplete event of our Fx.Morph instances comes in: it’s the finger that pulls the trigger.  And it only pulls the trigger when the last effect has finished.  Setting it up this way ensures that all functions loaded onto the fnChain call stack get used.  Using the chain and callChain methods by themselves will not get us where we want to be.

The last sections of code (with the exception of the last line) basically repeat the process for the text in the content area.  The final line:

		(function(){fnChain.callChain();}).delay(1000);

is needed to get that first function from the call stack and kick the process off.
If you’re into Mootools I hope you’ll add the Chain class to your toolkit. With it, you can kick up the complexity of your effects by a notch or two. Thanks for reading.