Digging Animation
by Antoine Quint
|
Getting Our Mouse To Work
So far the work we've done, while valuable, is still a little
lame. Niklas had his cubes reacting to mouse events generated when the
user rolled over them. Let's get that to work, too. SVG animation
provides a mechanism for reacting to mouse events. You might have
noticed that in our previous animation we did not specify when our
animation started. There is an attribute "begin" that would do exactly
that, but it has a default value of "0s", which means our animation
starts when the document is loaded. Here we want our animation to
start when we mouse over the cube. Let's try introducing the "begin"
attribute to our animation and set it to "mouseover", and see what it
does:
<use xlink:href="#cube" transform="translate(307.5, 105.75)">
<animate attributeName="y" begin="mouseover" dur="2s"
values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0" />
</use>
[View this code as SVG]
If you tried rolling your mouse over the cube you will have noticed
it did start the animation. You might also have noticed that there is
a bit of a strange behavior going on. If you don't move your pointer
away from where you entered the cube and started the animation, then
the animation will restart from the beginning when the cube falls down
and goes under your pointer again. This is not what we want; we would
rather have the cube not take any mouse event until the animation is
finished. Once again, SVG animation provides the exact mechanism we
are looking for: the "restart" attribute. By default its value is set
to "always", which means that the animation is restarted at every time
the situation indicated by the animation "begin" attribute is
true. Another possible value is "whenNotActive", which according to
the spec means that "the animation can only be restarted when it is
not active [and that any] attempts to restart the animation during its
active duration are ignored". This sounds like what we have been
looking for, let's see how it goes:
<use xlink:href="#cube" transform="translate(307.5, 105.75)">
<animate attributeName="y" begin="mouseover" restart="whenNotActive"
dur="2s"
values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0" />
</use>
[View this code as SVG]
This is exactly the behavior we wanted. Excellent. However, we
still have some way to go to a refined animation like the
original. Let's move on to better things.
Upping the Pace
The key ingredient to make our animation as spiffy as Niklas's is
to give the animation a acceleration/deceleration, gravity-like
feel. When I opened the original source file in Flash, I noticed
Niklas did two things. The first thing was adjusting the keyframes so
that the animation would have different intervals between two sets of
values. The other was to have easing-in and easing-out on certain
intervals of the animation. Let's see how to implement that in SVG:
keep your eyes peeled as this is really is the hottest part of what
SVG animation offers.
Our first task is to get the values to be taken into account at
non-identical intervals in time. It is time to introduce a new
attribute to our growing set of friends: the "keyTimes"
attribute. This attribute will help us recreate the timing that was
going on in the original SWF animation; it will help us create a
mapping between the "values" attribute and the time at which each
value will be reached in our animation. The SVG specification says
that "each time value in the keyTimes list is specified as a floating
point value between 0 and 1 (inclusive), representing a proportional
offset into the simple duration of the animation element". Albeit in
formal terms, this is what we are after. Let's give it a shot:
<use xlink:href="#cube" transform="translate(307.5, 105.75)">
<animate attributeName="y" begin="mouseover"
restart="whenNotActive" dur="2s"
values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0"
keyTimes="0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
0.7949; 0.8462; 0.8974; 0.9231; 0.9487;
0.9744; 1" />
</use>
[View this code as SVG]
Pay no attention to the weird values we set in the "keyTimes"
attribute. These were computed by hand from the original Flash
animation. It looks kind of odd because Niklas's keyframes were placed
themselves at odd times. This is of course a job best suited for an
SVG-enabled animation authoring tool, but here we're trying to figure
out how SVG animation works exactly so it is worth doing by hand. The
result we have now is somewhat paced animation. It is not as refined
as Niklas's yet, but the end bit looks exactly like it ought to. As
for the start of the animation, this is where Niklas had the easing-in
and easing-out take place. Now watch out, because this is getting
really smooth.
In Macromedia Flash 5, one can specify easing-in and easing-out
between two keyframes with a percentage ranging from "-100%" to
"100%". Although this is quite a jolly nice control over acceleration,
SVG provides a much sweeter mechanism. Instead of having a simple
percentage, SVG allows us to describe the speed behavior of an
animation interval with a two-point Bezier curve (you've probably
heard a lot about those if you've got any experience with SVG). What
does this mean?
Draw a Bezier spline that fits in a square, starting bottom-left
going top-right. The rule to draw that kind of curve is that it has to
be bijective (a unique mapping of x and y). You can find quite a few
of these curves just above
section 19.2.8 of the spec, which are really helpful in
visualizing how keySplines work. Now the x-axis represents time and
the y-axis represents the percentage of the variation between the two
values. That allows us to have very fine control of animation
speed. While Flash only allowed us to specify constant speed
variations, SVG enables multiple speed variations in one given
interval. Now that we have a better idea of how keySplines work, let's
put our knowledge to work:
<use xlink:href="#cube" transform="translate(307.5, 105.75)">
<animate attributeName="y" begin="mouseover"
restart="whenNotActive" dur="2s" calcMode="spline"
keySplines="0 .75 .5 1; .5 0 1 .25; 0 .25 .25 1;
.5 0 1 .5; 0 0 1 1; 0 0 1 1; 0 0 1 1;
0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1"
values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0"
keyTimes="0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
0.7949; 0.8462; 0.8974; 0.9231; 0.9487;
0.9744; 1" />
</use>
[View this code as SVG]
Now this looks nice, much like the real thing, in fact a lot
smoother since we did not have to worry about the cumbersome
frame-rate. Besides the "keySplines" attribute we just introduced, you
will have noticed a new friend: "calcMode".
This attribute enables tweaking of the way the interpolation between
the animation values we set is done. So far, we have use its default
value ("linear") and now we needed to set it to "spline" so that it
would take into account our "keySplines" attribute.
Go Forth And Multiply!
One of the last things missing is actually having the sixteen
instances of our cube. Since we defined our cube as an SVG "symbol",
we only have to place sixteen "use" elements, much like we have used
so far with our single cube. I'm not going to teach you how to line
cubes up, I actually got Illustrator to give me the bounding box of
the cube and did a rough alignment by hand (you can see it's not
perfectly aligned when you zoom in).
In much the same way as we created a symbol for the graphics in
order to create a single definition for multiple re-use, we may well
want to have references to our animation since all the cubes are
animated in the same way. We could have had our "animation" element as
part of the symbol, but the SVG 1.0 specification states that this
would result in all instances of the symbol being animated at the same
time. However, animation referencing is an issue being addressed by
the W3C SVG Working Group for future enhancements, and SVG 1.1
(currently in Working Draft status) introduces a mechanism allowing
for animation of animated symbol instances only. Still, there is a way
to actually re-create this kind of behavior, using entities. The idea
is to have all the sensible values of our animation, which may be
changed in our authoring, be centralized so that a single change would
be applied to all the animations. Here goes:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [
<!ENTITY dur "2s">
<!ENTITY values "0; -45; 0; 16; 0; -7;
0; 3; 0; -2; 0; 1; 0">
<!ENTITY keyTimes "0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
0.7949; 0.8462; 0.8974; 0.9231; 0.9487; 0.9744; 1">
<!ENTITY keySplines "0 .75 .5 1; .5 0 1 .25; 0 .25 .25 1; .5 0 1 .5;
0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1;
0 0 1 1; 0 0 1 1; 0 0 1 1">
<!ENTITY calcMode "spline">
<!ENTITY begin "mouseover">
]>
<svg width="665px" height="250px" viewBox="0 0 665 250"
xml:space="preserve">
<!-- <title>, <defs> and background <rect> as we have seen -->
<g id="cubes" transform="translate(300.25, 143.45)" >
<use xlink:href="#cube" transform="translate(0,-72)">
<animate dur="&dur;" values="&values;" keyTimes="&keyTimes;"
keySplines="&keySplines;"
attributeName="y" begin="&begin;"
restart="whenNotActive" calcMode="&calcMode;" />
</use>
<!-- fifteen other <use> -->
</g>
</svg>
[View this code as SVG]
Et voil!. This might well look like a dirty trick, but it
does the job quite nicely. Now if we decide to change the keySpline
for the third interval of our animation, we only have to edit it once.
As for the animation itself, it looks like we're done. It should look
very much like the original SWF version. In fact, Adobe's SVG Viewer
on my laptop gives me a much smoother animation than the SWF played in
the Flash player. By the way, the gzipped
version (commonly known as SVGZ) of the final animation is only
926 bytes, while the SWF version is 1.29 KB. Prettier and
smaller!
Wrapping It All Up
I hope you enjoyed this ride through some of the nicest features of
SVG animation. There is a lot more to SVG animation, especially the
idea of synchronization, which we'll consider in future articles. I
think this simple animation highlights some of the key concepts of SVG
animation, primarily that it is time-based and property-based, as well
as some of its differences from the SWF animation capabilities.
It's probably now time for you to read the whole animation chapter
of the SVG 1.0 specification and start digging into it yourself. One
thing you'll find missing at the moment is an authoring tool for SVG
animations. Jasc's WebDraw 1.0 has just been announced and includes
support for some of SVG's animation features. And Adobe just recently
asked on the SVG-Developers
list for feedback on the need for SVG support in their animation tool,
LiveMotion. Adobe is soliciting your input on its email wish list. If you
want to see SVG grow in terms of user penetration and ease-of-use,
make sure Adobe and other vendors hear from you.
Prev [1] [2]