Image Transitions Manual
2. Further Development
This is the advanced user guide, which focuses on how to synchronise transitions, such as triggering one from another to create interesting two-stage effects. It will also show you how to synchronise longer, more complex sequences, for things like slideshows, presentations and image-rotation scripts.
Defining the transition callback
At the heart of the script's synchronisation capabilities is the ability to define an asynchronous callback, that the transition method will call immediately after the transition has finished. You can use the callback function simply to start another transition straight away, or put it to use as part of a more sophisticated sequence of events.
The callback function is the
final argument to any transition method —
you can define an anonymous function directly,
or pass a reference to a named function.
So for example, when added to fade
,
it would be argument [4]
:
Transitions.fade("#flag", "red.png", "Red Flag", "2", myCallback);
Or added to any of the other
transition methods,
it would be [7]
:
Transitions.wipe("#flag", "red.png", "Red Flag", "2", "RND", "0", "No", myCallback);
However, since the fade depth and reverse transition arguments are optional, the script allows you to omit those arguments entirely, and define the callback function directly after the animation type. You can omit both those optional arguments, or just the last one, and this saves you having to add their values simply to re-create their defaults. So all three of the examples below are effectively identical:
Transitions.wipe("#flag", "red.png", "Red Flag", "2", "RND", "0", "No", myCallback);
Transitions.wipe("#flag", "red.png", "Red Flag", "2", "RND", "0", myCallback);
Transitions.wipe("#flag", "red.png", "Red Flag", "2", "RND", myCallback);
Synchronising multiple transitions
We've seen how the key to synchronisation is the use of a transition callback. So now let's take a look at some of the things we can do!
Creating a two-stage transition effect
The simplest kind of synchronisation is using the callback to start a second transition, combining both transitions to create some kind of two-stage effect.
The previous version of this script included an effect called
Swap-Fade
, whereby the original image would fade-out and then
the new image would fade-in — two discreet transitions,
as opposed to the cross-fade the current script implements.
But we can still create that swap-change effect with the help of a callback function, by implementing a two-stage transition via an intermediate shim (a completely transparent image, either GIF or PNG):
Transitions.fade("#flag", "shim.png", "", "1", function()
{
Transitions.fade("#flag", "red.png", "Red Flag", "1");
});
We're not just limited to fade
, of course, we can do this
with any transition. How about using grow
, for an effect
where the original image shrinks-away then the new one grows in its place:
Transitions.grow("#flag", "shim.png", "", "1", "TB", "0", "Yes", function()
{
Transitions.grow("#flag", "red.png", "Red Flag", "1", "TB");
});
Notice how the first transition is a reverse top-to-bottom —
which is different than a forward bottom-to-top. A
reverse transition
shrinks the original image
to reveal the new one underneath; but conversely, a forward transition
grows the new image
to cover-over the original — and that's not the effect we want.
More to the point, since the new image in the first transition is completely blank,
if we ran that half as a forward transition we wouldn't see anything at all.
Don't forget to cache the images first!
Creating a longer sequence
Now that we have the basic idea, we can extend the principle as far as we like, to create a longer, more complex sequence with any number of images. Such a sequence could form the basis of a slideshow, or a presentation, or it could be the eye-candy on top of an image-viewing gallery — whatever.
If we create a wrapper function around a single transition, and pass the transition a callback function which calls the wrapper again, then we have a process that will run forever! But further logic inside the function could determine when to stop, what the next image is, or whatever else it takes to create the finished product.
So for example — let's define some images in an array, then run a bunch of transitions from one to the next, until we've seen them all; we can use a numeric pointer to track our progress through the array:
var n = 0, flags = ["red", "gold", "green", "blue"];
function sequence()
{
Transitions.fade("#flag", flags[n] + ".png", flags[n] + " flag", "0.8",
function()
{
if(++n < flags.length) { sequence(); }
});
}
sequence();
In that example, the
ALT
text
for each image is extrapolated from the
image SRC
,
but if the images you're using require more
intelligent descriptions, you can always define
a second array to store different text for each one.
And not just for ALT
, of course — the same principle is true
for any of the transition methods' arguments.
Supposing we wanted each transition to have a different animation type, we could define an array of types and use the same pointer to refer to it. This next example uses double-slide transitions, to move between four images that are slices from a larger one — giving the impression of panning around a single, large image:
var n = 0,
types = ["DLR", "DTB", "DRL", "DBT"],
slices = ["bottom-left", "top-left", "top-right", "bottom-right"];
function sequence()
{
Transitions.slide("#map", slices[n] + ".jpg", "Map of Australia", "1.6", types[n],
function()
{
if(++n < slices.length) { sequence(); }
});
}
sequence();
So, using the same approach of creating additional argument arrays,
we can organise any parameter into a sequence of events.
Perhaps you'd like
to vary the timing, so that some changes are quicker than others; maybe introduce
a pause between each image and the next one, as slideshows and image-rotation
scripts generally do.
With a very long list of images, you might even wish
to pre-load on-the-fly — for example, only
cache the first five
images, and then use each sequence iteration to load the next one in line
(having buffered five frames' worth of data,
you should have enough time to load each new image before you need to display it;
or if the images are particularly large, the buffer should probably be larger as well).
Sequencer fallback timing for partially-supported browsers
As we've noted before,
there are a few browsers that only support some
of the transitions — Firefox 3.0, for example,
doesn't support grow
, twist
or skew
.
There's also the possibility, in any
supported
browser, that the user is viewing the page
with images disabled. In both these cases, the
fallback behavior
is to do a simple image-swap.
And therefore ... any sequence you put together will always produce some kind of result — a basic image-rotation at least — whichever transitions you use and whatever the state of the browser that views it. The issue, however, is one of timing.
The callback fires as soon as the method completes, but if all it's doing is the basic swap — which happens almost instantly, rather than being a timed effect — then each iteration will happen so fast that it rips-through the whole set of images in virtually no time at all!
To get round this problem, there's a configuration option called
"long-fallback"
,
which when enabled, adds a delay to the fallback behavior, so it
still has the same duration as the original transition effect.
Used with a sequence of transitions, it means that you'll still see each image
(or its ALT
text)
for the right length of time, as they're stepped-through progressively
rather than spewed out in an instantaneous blur!
Detecting the fallback behavior
You can also detect when a browser does the fallback behavior for a transition, because when this happens, the transition method will return null to indicate the exclusion (rather than returning true for success, as it otherwise normally would).
The timing of transition methods and their callbacks is such that the method will always return before its callback fires. So if you save what the method returns, then you can refer to it from within the callback to infer what the browser did:
var result = Transitions.skew("#flag", "red.png", "Red Flag", "2", "TRDF",
function()
{
if(result === true)
{
//the browser ran this transition
}
else if(result === null)
{
//the browser did the fallback behavior instead
}
});