A Realist's SMIL Manifesto, Part II
by Fabio Arciniegas A.
|
Pages: 1, 2, 3, 4, 5, 6, 7
The Problem
The page we want to create is a brief explanation of the lives of the people in a group photo. The idea is to be able to focus the reader's attention on synchronized details in the text and in the picture, without loosing the overall context that the complete page provides. Figure 7 shows a snapshot of the final result. Whenever a person clicks on a link, a sound (or a combination of sounds) is played. Whenever a person clicks on a person on the picture, all the relevant links are highlighted in the page. You can play around with the final page before jumping to the following sections which deal with the creation of the piece.

Figure 7. Snapshot of the Final Page at Two Stages
The Base SVG Image
Figure 8. Basic Image |
The first step is to create the base SVG
image, as shown in Figure 8. The file velvet.svg was
created in Adobe Illustrator, using one layer for each colored
silhouette, the result is not only a reasonably organized SVG file (a
named group with a path inside for each layer and CSS for each color
effect) but also much smaller than the alternative of creating
multiple (seven) flat image files with each character highlighted.
We modify the CSS in the source as shown in Listing 8 so all the color layers have an opacity of 0 (invisible) so we start with just the black and white picture. |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN"
"http://www.w3.org/TR/2000/03/WD-SVG-20000303/
DTD/svg-20000303-stylable.dtd" [
<!ENTITY st0 "fill:#C0C311;stroke:none;">
<!ENTITY st1 "fill:#00D759;stroke:none;">
<!ENTITY st2 "opacity:0;">
<!ENTITY st3 "opacity:0">
<!ENTITY st4 "opacity:0;">
<!ENTITY st5 "opacity:0;">
<!ENTITY st6 "opacity:0;">
<!ENTITY st7 "opacity:0;fill:#000EC0;stroke:none;">
<!ENTITY st8 "opacity:0;fill:#E990C9;stroke:none;"> ...
]>
<svg width="599.368pt" height="425.031pt" viewBox="0 0
599.368 425.031" xml:space="preserve"> ...
Listing 8. Modified CSS properties for the base SVG Image
Showing/Hiding Pieces - The Declarative way vs The Procedural Way
Before we show how to create the colored effect with SMIL 2, lets see the alternative with procedural JavaScript.
The idea is to show the colored paths as the user places the mouse over
each area, so we associate a custom function showWithOpacity to the
onmouseover event of each group (that is each g element
in the SVG) as shown below:
<g id="Andy" style="&st13;" onmouseover="showWithOpacity(evt,'
Andy',0.3)">
<path style="&st14;"
d="M206.328,397c22-7-1-33,12-48c13-13,21-3,22-29c0-
25-5-47-1-72c2-17,5-28,12-43c14-31,21-54,55-67c9-4,
..."/>
</g>
The body of the function is shown in Listing 9.
<script language="Javascript">
var lastobj = document.getElementById ("nico");
function showWithOpacity(evt,targetId,opacity)
{
var target = evt.getTarget();
var svgdoc = target.getOwnerDocument();
var svgobj = svgdoc.getElementById (targetId);
if(lastobj)
{
var oldstyle = lastobj.getStyle();
if (oldstyle)
oldstyle.setProperty ('opacity', 0);
}
if (svgobj)
{
var parnode = svgobj.getParentNode();
parnode.removeChild(svgobj);
parnode.appendChild(svgobj);
var svgstyle = svgobj.getStyle();
if (svgstyle)
svgstyle.setProperty ('opacity', opacity);
lastobj = svgobj;
}
}
</script>
Listing 9. Procedural way to vary opacity
The function above not only requires a bit of proficiency with JavaScript but is limited to vary the opacity of the group (in one step, not gradually). If you wanted to add another effect, such as changing the size of the path or rotate it as it gets positioned, you would have to re-write the wheel and write the appropriate loops. This can get tedious and expensive to implement, so for the onclick effect we will change the strategy and rely instead on the animate support of SMIL 2.
With animate, the way we tie events to actions is reversed from the traditional javascript call: instead of saying in the element "execute this every time there is a click", we create the effect and specify we want to "get this executed every time the objectID.click event is fired". The following example (Listing 10) clarifies the point.
<g id="Andy" style="&st13;" onmouseover="showWithOpacity(evt,
'Andy',0.3)">
<animate attributeName="opacity" values=".3;1;.4"
begin="Andy.click" keyTimes="0;0.7;1" dur="1" />
<path style="&st14;"
d="M206.328,397c22-7-1-33,12-48c13-13,21-
3,22-29c0-25-5-47-1-72c2-17,5-28,12-43c14-31,
21-54,55-67c9-4, ..."/>
</g>
Listing 10. Declarative way to vary opacity
There are at least three main advantages on this approach:
- You can leverage all the power of SMIL 2 transformations, including gradual and non-linear variations of a parameter (as shown)
- You don't need to code or debug JavaScript
- There can be as many animate elements which begin when Andy.click is fired as you want, they are all coded independently, and the g element needs to know nothing about them.
For CSS connoisseurs who might be wondering why we did not use the visible property instead of opacity in Listing 9, the reason is an element with visibility equal to false does not emit mouse over or mouse click events in the SVG Viewer.