Create an image slideshow with MooTools
Ryan Florence explains how to create a great-looking slideshow that's easy for the client to update using the incredibly extensible MooTools framework
MooTools is a half-acronym for My Object Oriented (JavaScript) Tools. Unlike a lot of JavaScript libraries, where you drop in a file and suddenly JavaScript is more awesome, MooTools is modular – you just use the pieces of it you need to incrementally make JavaScript more awesome. It could be said that MooTools is not a library, but a language extension, or a framework.
Modules
The two most common modules are Element and Class. Think of Element as jQuery. The goal of both is to make writing code for the DOM both palpable and rapid. Take that same thought and apply it to code design. That’s where Class comes in. JavaScript features prototypes (proto-what?); most of us aren’t used to them. Much the same way that Element and jQuery sort out the DOM, Class sorts out prototypal inheritance.
The screengrab (below right) shows what some MooTools classes look like.
Additionally, some older browsers don’t support some of the ECMAScript 5 spec such as Array.map or Array.forEach.
MooTools upgrades the environment with ‘Type’ extensions, enabling you to use the current and future standards, plus dozens of other utility methods and functions – and you can add more of your own if you like. They’re implemented with the same API as existing JavaScript.
// nice and clean[1.4, 2, 22/7].map(fn).forEach(fn).getRandom().round(2);// vs. whatever you want to call thisnamespace.roundNumber(namespace.arrayRandom(namespace.map(namespace.each([1,2,3], fn), fn)));
I mean no disrespect to namespaced toolkits and libraries like Dojo and jQuery: they’re all making the web better and have their own unique features that set them apart. It seems clear to me, however, that MooTools syntax – which is just JavaScript syntax – wins the readability contest.
This clean syntax is not free, however. Some criticise MooTools for extending the native objects. It’s no secret that the framework assumes you control the environment, which is true most of the time a person writes JavaScript. It couldn’t very well be named “My Object Oriented Tools” if it was merely a collection of functions hanging off a namespace. If you don’t control the environment, like creating a “share button” or CMS plug-in, you shouldn’t use MooTools for the task.
Get top Black Friday deals sent straight to your inbox: Sign up now!
We curate the best offers on creative kit and give our expert recommendations to save you time this Black Friday. Upgrade your setup for less with Creative Bloq.
Finally, MooTools is not about shortcuts (though it has many). Its real power is that it first provides an API to extend JavaScript, then uses that API itself to provide features – offering you the tools to add even more.
The slideshow
SlideShow is a low-level interface widget I designed to handle the very basics of a slideshow: positioning slides in the same space, transitioning from slide to slide, play, pause and so on. You can learn more at ryanflorence.com/slideshow. We’ll be extending it with a sub-class, and implementing a mixin. Here are the requirements (these are real, from a recent project of mine).
- Image tags are dynamically generated from an external text file
- Text labels are dynamically generated from the same external text file
- Text labels work as navigation, onclick, with a fade effect
- An indicator animates from previous slide’s label to current slide’s label
- Animations are 10fps for mobile devices and 50fps for desktop
- Keyboard arrows navigate the slideshow with push effects (push-down for down and right keys, push-up for up and left keys)
- Swiping left or right on mobile devices also navigates but with slide effects (slide-left for left, slide-right for right)
Two approaches
There are two ways to approach this.
- Write out a monstrosity of application-specific code, wrapped in a domready function, providing all of these requirements together, or
- Organise several single-purpose, externally testable, easily packagable, abstract classes that harmonise into a coordinated code concerto.
MooTools, by its design, encourages you to separate logic from implementation. A typical MooTools application will have a folder somewhere full of packages containing several classes and other scripts containing the logic.
Developers then use a packager to create custom builds. Alternatively, you can download custom builds from mootools.net/download.
Requirements 2 & 3: Creating the text labels
Before we see how Requirement 1 is implemented, let’s tackle requirements 2 and 3. Navigation labels are an extremely common use case for a slideshow.
Solid MooTools code is organised. Experienced developers write classes and methods that do one specific thing.
Writing code this way takes a little more time up front – you have to plan it out and think about it outside of the current task – but it pays off in huge dividends down the road.
Each piece is small and processable. This kind of code is not only easy to maintain, but highly portable.
On line 3 (see below), the magic begins. Extends tells the Class constructor to make SlideShow the prototype of this class.
Just like an array inherits the join and sort prototype methods, SlideShow.Labels inherits all the methods of SlideShow.
Continuing to line 5, we can add new options or redefine the default values of the parent’s options.
The initialize method already exists on the parent class, so it gets over-written when we define it in this sub-class.
However, there’s a class method called parent that calls the parent’s method with the same name as the method from which parent is called.
This enables you to do some extra stuff in a sub-class before or after the parent class method runs. In this example, we want to build the labels after the parent initialises everything.
The buildLabels method creates the labels’ container and the labels. When it creates each label it also adds a click event, injects the label into the label container, and if the developer added a ‘label’ option, sets the HTML of the label.
Line 22 makes use of the super-handy Function.pass. It lets you pass in some arguments and the context to the event handler when it runs.
Here it calls the show method, inherited from the parent class, and passes in an index to tell the slideshow to show whichever slide this label represents.
Near the end of the buildLabels method is an element method called store. You can store anything on an element: another element, an object, string, function, array – anything.
This is especially handy when you need to pass information around as you manipulate elements. There’s a good chance whoever uses SlideShow.Labels will want quick access to the label from a slide.
Finally, the code injects the labels into the document. It’s always a good idea to let the developer control where things get injected so they don’t have to move it around later, hence the inject option of this class.
Requirement 1:
Creating the HTML dynamically from a text file
The approach here is to use a request to the server for the text file, parse it, and then generate some HTML. Here’s the format we think the client can successfully reproduce:
- images/01.jpg “Waterfall”
- images/02.jpg “Triple arches”
- images/03.jpg “Wasatch Mountains”
- images/04.jpg “Delicate Arch”
- images/05.jpg “Moab”
- images/06.jpg “More Moab”
- images/07.jpg “Subway”
- images/08.jpg “Salt Lake City”
This certainly sounds like something to reuse in other slideshow implementations. So we’ll create a mixin for SlideShow that we can implement into another class (see above). In buildFromConfig, this class creates an Ajax request. When complete, it parses the response and builds the slides. You may have also noticed a few methods up there like each and trim. These are utilities added by MooTools. There’s probably a better way to parse the text, but I wanted to show off some of these features.
Requirement 4: The animating indicator
MooTools More is a set of classes and plug-ins that are just slightly out of scope of the core framework. To get the indicator to move from label to label becomes quite trivial when we use Fx.Move from MooTools More.
Fx.Move enables you to animate an element to any position relative to another element (or the window).
SlideShow has a custom class event named show that we can attach to. When a new slide is shown, we can move the indicator element around.
Class events in MooTools have the same API as DOM events.
myElement.addEvent('click', fn); slideshow.addEvent('show', fn);
The class SlideShow.FancyPants (see below left) pulls together everything we’ve done so far.
The use of Extends and Implements gives us a lot here. This class now has SlideShow.Labels as its prototype from Extends, and it’s copied over the methods from SlideShow.Config with Implements. Looking at the initialize method we first cache the main slideshow element because buildFromConfig needs it. Normally this is cached in SlideShow::initialize, but we don’t want to call that yet because we haven’t even created the slide elements. After we build the slides we’re ready to run the parent initialize function with parent.
The build method then creates the indicator and positions it next to the first slide. In line 3 of build we set the move property of our element and define the duration of the animation to match the duration of the slide animations. There are all sorts of things you can ‘set’ and ‘get’ on an element with MooTools, such as element attributes. To get any of this information, simply ask for it with el.get('whatever') or set it with el.set('whatever').
Not only can you get and set these native properties, you can define your own element get and set methods – which is exactly what Fx.Move does here. It creates the element property move, enabling us to set the default animation behaviour. Being simple functions, they’re easy and powerful tools for organising DOM behaviour.
Back in initialize, the last thing to do is get the indicator to animate to the current slide’s label. As mentioned before, we can listen to the custom show event on the SlideShow class. The show event passes an object containing data about the previous and next slides. Because SlideShow.Labels stores the label on the slide we can access it easily with a quick call to retrieve. Now, thanks to Fx.Move, all we have to do is tell our indicator to ‘move’ to the label and we’re done.
For the final three requirements we’ll be writing some application code. I don’t normally write very much application code: I like to abstract nearly everything into a class or type method. However, I thought it valuable to show what this kind of MooTools code looks like.
Typically, application code is wrapped in a DOMReady function. This ensures the HTML is loaded and you can safely find and manipulate the DOM. Let’s add our SlideShow.FancyPants instance:
window.addEvent('domready', function(){ var slideshow = new SlideShow.FancyPants('slideshow', { duration: 300, label: 'alt' }); });
Requirement 5: Changing the FPS for mobile devices
Because all Fx classes inherit from Fx, this task is really simple. All we do is change the default fps for the Fx and all of the sub-classes will follow suit. With a little help from MooTools Mobile, by Christoph Pojer, we can detect that it’s a mobile device easily and change the fps.
if (Browser.isMobile) Fx.prototype.options.fps = 10;
Requirement 6:
Keyboard navigation with different transitions
Our client wants the slideshow to fade between slides, normally. But when the user navigates with the keyboard he wants a push effect, up or down, depending on the key.
SlideShow supports overriding the default transition in the show method, so it’s no big deal. For this we add a keyup event to the window and then manage the state of slideshow.
window.addEvent('keyup', function(event){ var next = ['down', 'right'] , previous = ['up' , 'left' ]; if (next.contains(event.key)) slideshow.showNext({ transition: 'pushUp' }); if (previous.contains(event.key)) slideshow.showPrevious({ transition: 'pushDown' }); });
We store which keys should navigate to the next and previous slides, then
we check if either array contains the event.key. If so, call the showNext or showPrevious method. MooTools maps the key codes so that event.keyCode // 37 becomes event.key // left.
Requirement 7: Touch-enabled swipe navigation
We’ll want to add the swipe event to the main slideshow element. Rather than select it again with $('slideshow') we’ll use a slick MooTools trick.
You can ‘select’ a class instance and it will return an element if it has a toElement method that returns an element.
$(slideshow).addEvents({ swipe: function(event){ slideshow['show' + ((event.direction == 'left') ? 'Next' : 'Previous')]({ transition: 'blind' + event.direction.capitalize() }); }, mousedown: function(event){ event.stop(); } });
MooTools Mobile contains an easy-to-use ‘swipe’ event. The rest of this code block is admittedly funky, but still fun. The ‘swipe’ event.direction is either left or right. Here we use a little meta programming to dynamically call the showNext or showPrevious method with either the blindLeft or blindRight transition, using the value from event.direction.
Note the handy String method capitalize. That mousedown event keeps the image from being draggable with a mouse gesture.
Homework
Once you’ve downloaded the source code, try this homework. All SlideShow instances have ‘play’ and ‘pause’ methods. Create a play/pause button to control the slideshow. If you get stuck, look up javascripts/slideshow/Docs and you should find the help you need. l
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1
The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of eight full-time members of staff: Editor Georgia Coggan, Deputy Editor Rosie Hilder, Ecommerce Editor Beren Neale, Senior News Editor Daniel Piper, Editor, Digital Art and 3D Ian Dean, Tech Reviews Editor Erlingur Einarsson and Ecommerce Writer Beth Nicholls and Staff Writer Natalie Fear, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.