Mootools Chaining for Image Effects

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

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.

Son of Multibox Rewrite (mea culpa)

March 9th, 2009  |  Published in Compatibility, Javascript, Mootools, multibox, phatfusion

I missed something when I modified Samuel Birch’s Multibox application to be compatible with Mootools 1.2. You see, when I did the rewrite I was using Mootools latest and greatest, version 1.2.1.

Imagine my chagrin (oh, the shame) when I discovered that it bombed against version 1.2! A little digging revealed that during the creation of 2 Fx.Morph objects, I had missed the old style of the transition: Fx.Transitions.sineInOut. Weirdly enough, 1.2.1 forgave my omission and ran without error. Version 1.2 wasn’t as nice about things. Anyway, long story short, I changed the transitions to Fx.Transitions.Sine.easeInOut and all seems right with the world now. Sorry. The download has been updated.

Multibox rewrite for Mootools 1.2

March 7th, 2009  |  Published in Compatibility, Javascript, Mootools, multibox, phatfusion  |  3 Comments

For a recent project I needed a lightbox-style application that could handle multiple content types. You know, something flexible enough to show images, html, video, etc.

Multibox, a well-known JavaScript program by Samuel Birch, seemed a likely candidate. The problem: Multibox was written for Mootools version 1.1 and I needed to use version 1.2. So I rewrote multibox.js and overlay.js to make them compatible with the latest version of Mootools.

It’s a pretty straightforward rewrite; any code that’s been commented out is left over from the original and wasn’t done by me. I did, however, fix one bug while I was at it:

				if(this.elementContent.getStyle('width') != 'auto'){
					//	Bug fix: this.elementContent.getStyle('width')
					//	returns 480px.  This causes NaN (and IE error)
					//	in subsequent calculations.  Fixed by invoking toInt().
					this.contentObj.width = this.elementContent.getStyle('width').toInt();
				}

The bug only affects situations where you want to take an inline html element (i.e., it’s already embedded on the page) and display it in the multibox. this.elementContent.getStyle(’width’) returns a string. In the demo it was returning 480px and this caused errors later on in the code. Adding toInt() to the end seems to have fixed it.

I would have posted this on phatfusion’s user forum but it has evidently been taken down for a spell.

Multibox is very handy for displaying all sorts of different content…and now it’s updated. I’ve gotten a lot of use out of it; I hope you do as well. Rather than distribute the updated js files separately, I simply bundled it back into Birch’s original download package. The script tags in the demo page have been updated to call for the rewritten files so it should (fingers crossed) run okay right out of the box.

Download it here.

It occurred to me after the fact that since Birch’s original download is kind of large, I ought to provide just the 2 rewritten files (multibox and overlay).

Chaining Functions in Mootools for Dynamic Text Effects

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

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.

Expanding Menu Bug Fixed

December 12th, 2008  |  Published in CSS, Javascript, Mootools

As I mentioned yesterday, helpful fellow Mootoolers pointed out a nasty bug in the expanding menu application. This particular bug, which caused the entire menu structure to essentially freeze itself in a fully expanded state, seemed to affect earlier versions of Firefox. One nice coder mentioned Firefox 2.0.0.13, so I downloaded and installed this earlier version and went to work.

Once I had figured out what was going on, the fix was simple: all I had to do was change a class declaration in the main stylesheet. Specifically, I changed “display:inline-block” to “display:block.” Voila, problem solved. So what happened and why did my simple fix straighten it out? Well, menu text in my application demo is enclosed within a span tag, which in the stylesheet had been given the “display:inline-block” declaration. The reason for this is that the javascript has to take the height of this element and use it in the calculations.

The problem was, the earlier Firefox version didn’t understand inline-block and just dropped the declaration altogether. So by the time my span height was used in the code it arrived as NaN (”Not a Number”). Not surprisingly, the code bombed from that point on.

The funny thing is, I can’t remember why I used “display:inline-block” in the first place, instead of plain old “display:block.”

Expanding Menu Update

December 11th, 2008  |  Published in Javascript, Mootools

A couple of helpful fellow Mootoolers over at the MooForum let me know about a bug in my Mootools-based expanding menu program. The bug appears to be limited to earlier (pre-3.0) versions of FireFox.

What happens in these earlier versions is that all the menu items simultaneously open in fully expanded mode … obviously what should not happen. I think the bug may center on declarations in the stylesheet. Anyway, we’ll see.

Ah, the joys of cross-browser compatibility (sigh). I’ll get to work on it. Once it’s fixed, I’ll make a new entry and explain what I did to fix it.

The Expanding Menu

October 20th, 2008  |  Published in Javascript, Mootools


You’re welcome to view the Demo, download the Code, or read the mini-tutorial. The image on the left shows the “closed” and “open” states, respectively, of the last item on the menu.

MenuOpener is a Javascript class I wrote with the help of Mootools. The key ingredient for making use of this class is a vertical menu structure with overflow. MenuOpener adds event handlers for the custom Mootools events “mouseenter” and “mouseleave,” exposing the overflow of a particular menu item when you roll your mouse over it. I use this primarily to show thumbnails of the web pages associated with the menu item links.

In addition to creating the artwork for the menu items, the main task for the user is to figure out what the margins or spacings should be between the individual menu items. That’s it, in the proverbial nutshell.

Before I began writing the code for menuOpener, I found myself fiddling around with Samuel Birch’s excellent imageMenu program, which can be found at his website, phatfusion. ImageMenu works flawlessly, but I needed something that could expand a vertical menu, and Birch’s code is set up for horizontal menu structures. Also, I needed to be able to squeeze an adjustable margin in between the menu elements, and control the positioning of text within the individual menu items. Should I attempt to rewrite Birch’s code? The problem was, Birch’s imageMenu is configured in an entirely different direction than the one I needed to go.

Well, you know the answer to this story: I decided to write my own expanding menu class, which I cleverly named menuOpener, in tribute to banal and trite naming schemes everywhere.

MenuOpener is a lightweight (~3kb) piece of Javascript that leverages the power of the Mootools framework. Element heights, margins and paddings are dynamically adjusted based on parameters supplied by the user. Creating an instance of the menuOpener class is simple:

	var myMenuOptions = {
		wrapper: 'side_nav',
		menuItems: '.side_nav',
		navMask: '.nav_mask',
		navText: '.nav_text',
		mgnLarge: $empty,
		mgnSmall: 15,
		mgnNorm: 22
	};

	var myMenuOpener =
	new MenuOpener(myMenuOptions);

Of the default options, mgnLarge, mgnSmall, and mgnNorm are the ones you’d typically use. The other 4 are class and id names, which would only be changed if you modified the underlying CSS.

The following parameters would likely be in a typical setup:

	var myMenuOptions = {
		mgnLarge: 0,
		mgnSmall: 15,
		mgnNorm: 22
	};

Where mgnNorm refers to the margin or spacing between menu items when a mouseenter event has not occurred, mgnLarge is the spacing between an opened menu item and its nearest neighbor, and mgnSmall refers to the decreased margins between the remaining menu items during a mouseenter.

Then again, it might be easier to simply view a DEMO of the menu opener in operation. Or if you’d prefer, go ahead and download the demo using the link in the upper right of the page.

Oh, one more thing before I forget … the code fires off 2 events: a “complete” event that occurs after all the mouseenter transitions have taken effect (and a menu item has been opened), and a “closed” event, fired after the mouseleave transitions have happened and all the menu items have been returned to their closed states.