jQuery Mosaic Plugin
TL;DR: jquery.mosaic is a jQuery plugin written in TypeScript that you can use to display a mosaic of images, which are periodically swapped using configurable effects. View the demo
I like jQuery. A lot. I tend to include it in every web site I make and as a result I am now much more comfortable writing DOM manipulation code in jQuery than in "vanilla" JavaScript.
So when I needed a script to swap images around in a grid (aka a "mosaic"), I turned to jQuery to try to write my own plugin to do just that.
What I wanted was a simple way to display a collection of images (in a grid maybe, but really in any arrangement with a common parent), and turn it into a "live mosaic" by swapping the sources of some of the images every now and then.
The plumbing for such a plugin is really simple, but then I ran into another problem: I really don't know enough Javascript to write the actual plugin! I needed a way to store data about the mosaic somewhere, maybe some static data, etc. I'd have written the plugin in C# in less than an hour, but in Javascript I would have needed Googles help for just about every line of code.
TypeScript
So why not use TypeScript? I'd been experimenting with that for a while and felt really confident about it. Not only is it type-safe (which I love) but it also helps me with Intellisense about all those things in plain JavaScript I'm insecure about.
Long story short: I wrote the basic working version in TypeScript in about an hour and a half. It then took me two hours [sigh] to make it into a proper plugin, mainly caused by confusion over the meaning of this, which is different in a TypeScript-style anonymous function as opposed to a normal JavaScript function. Oh well. (And finally, it took me the better part of an hour to write this post!)
Update Of course, I couldn't leave it at that. Two more days (!) of work - in which I learned a lot more about TypeScript - produced version 0.2.0, with:
- Support for jQuery-UI effects
- Support for responsive layouts
- A much cleaner object oriented design
The plugin
But because the basics of a jQuery plugin are so simple, I now have a plugin called jquery.mosaic that allows you to call:
$("some-selector").mosaic();
to activate it on one or more elements matching the selector. You can pass options, which even have defaults (see below):
$("some-selector").mosaic({ effect: "slideLeft", duration: "fast", interval: 5000});
But best of all, you can use the plugin using data-mosaic- attributes, without any JavaScript at all - except including the script on your page,of course. If your HTML looks like this:
<div data-mosaic>
<img src="..." />
<img src="..." />
<img src="..." />
</div>
then the images inside the div will automatically be swapped using the default options: two swaps every 3000 ms using the "fade" transition.
The magic here is the data-mosaic attribute. If that is present (even if it's empty as in the example above!), the images in the element 0 which does'n need to be a div - with the attribute will be swapped. I did my best to not mess with the layout of the images at all - you can float them, put them inside other elements, make them percentage-wide: whatever. The mosaic plugin will leave the original images in place. A requirement, really, if you want your mosaics to be responsive!
It is, however, required (but not enforced!) that the images are all the same size. Most of the effects the plugin supports will make a mess of any layout with different-sized images, even if they have the same aspect ratio.
Configuring the plugin
The full list of options:
- effect. The transition effect to use. Default: "fade". Can also be "slideUp", "shrinkLeft", etc. for a full list see the demo page. In addiition, any jQuery UI effect (such as "explode" or "blinds") can be used - when prefixed with "ui-", e.g. "ui-explode". Attribute: data-mosaic-effect
- interval. The amount of milliseconds between each set of swaps. Default: 3000. Attribute: data-mosaic-interval
- duration. The amount of milliseconds a transition should take. Default: "fast". Can also be "slow" or a number, in which case it's a duration in milliseconds. Attribute: data-mosaic-duration
- swaps. The number of swaps to perform in each set. Default: 2. Attribute: data-mosaic-swaps
- easing. Defines the way the effect takes place. Default: "swing". Can also be "linear". Attribute: data-mosaic-easing
- options. Options to be passed to jQuery UI effects. Attribute: data-mosaic-options. Take care to format the options with double quotes, as in '"pieces": 4'. New in v0.2.1.
Get jQuery.mosaic
You can download version 0.2.2 of the plugin here, also minified. Still quite messy, isn't it? Compare that to the TypeScript version which is much cleaner and easier to read. And frankly, I wouldn't have been able to write all the native Javascript '__extends' and 'prototype' junk stuff myself even if I would have wanted to!
Note: the TypeScript version has an extension of .ts.js to allow it to be served. Change the extension back to .ts if you want to compile it using Typescript.
Try it out now!
See jQuery Mosaic in action on the jQuery Mosaic Demo Page.
Needless to say I'm somewhat proud since this is my first functioning jQuery plugin. And for someone who's really at best a moderate JavaScript user, the amount of time and code required to write it were really low. (Update Initially, that is - it doesn't help when you get carried away, but that's not TypeScripts problem!)
I now officially love jQuery and TypeScript.
How it works
After a lot of experimenting, implementing the animations is now relatively straightforward. At initialization (i.e. when mosaic() is called on a set of elements) the images in the mosaic element are stored in an array, and so are the src-attributes of all relevant images. Then a function is set up that gets called periodically to swap the sources of the images and perform the animation.
When animating two images, the following happens:
- An absolutely positioned, transparent div is created with the size of the original image, with a 100% wide and high, relatively positioned image inside of it. This div is positioned right over the original image, effectively covering it.
- The src of the original image is set to the new image source. Because the image is hidden behind the temporary div, this happens invisibly - and without flicker!
- The image inside the temporary div is now animated using the configured effect. Since the image is positioned relatively, it always starts at position (0, 0) which makes animations like Slide Left really simple - in fact, a single call to animate(). During animation, the new image will be visible behind and through the temporary div, which is transparent. The animation will always hide the temporary image in some way, revealing the new image.
- As soon as the animation is done, the temporary div is removed.
The advantage of this method is that the original layout of the page stays intact. A temporary element is used to basically disguise the fact that we changed the sources of one or more images - because that's the net effect of the whole animation. This enables the page to stay responsive.