XML Matters: SVG and the scriptless script

Declarative animation for junior rocket scientists

Scalable Vector Graphics (SVG) browsers are becoming mainstream now, and they can be used in many powerful ways. Continuing on from David's earlier SVG column, Dethe looks at some of the ways that declarative markup can replace script for animation and other common scripting tasks. In the process, he briefly looks at replacing script with declarative markup in other XML dialects. Moving common scripting tasks into declarative markup can eliminate the need for tedious boilerplate code, reduce errors, and make your script's intent easier to follow, freeing you to focus on your code's unique aspects.

Share:

Dethe Elza (delza@livingcode.org), Senior Technical Architect, Blast Radius

Photo of Dethe ElzaDethe Elza's favorite job title has been Chief Mad Scientist. Dethe can be reached at delza@livingcode.org. He keeps a blog mainly about Python and Mac OS X at http://livingcode.blogspot.com/ and writes programs for his kids. Suggestions and recommendations on this column are welcome.



David Mertz, Ph.D (mertz@gnosis.cx), Author, Gnosis Software, Inc.

Photo of David MertzDavid Mertz is a great believer in open standards, and is only modestly intimidated by verbosity. David may be reached at mertz@gnosis.cx; his life pored over at http://gnosis.cx/dW/. Suggestions and recommendations on this, past, or future columns are welcomed. Check out David's book Text Processing in Python.



09 March 2011 (First published 25 October 2005)

Also available in Japanese

09 Mar 2011 Editor's note: Some browsers support SVG animations. These animations were tested in Microsoft Internet Explorer with the Adobe plug-in, Google Chrome, and Mozilla Firefox. The sample animations worked best in Internet Explorer with the Adobe plug-in. Part of the animations worked in Google Chrome. In Download, find the sample SVG files in x-matters42-examples.zip and HTML files that embed the sample SVG files in x-matters42-html-examplefiles.zip.

SVG has been a W3C recommendation for some time now but has been slow to catch on in the wider Web. That might be changing now that Mozilla (Firefox), Apple (Safari), and Opera all support (or are about to support) SVG in their browsers, without plug-ins. The Linux desktops Gnome and KDE also support SVG for use in themes, icons, backgrounds, and games. Until now, the main way to view SVG was to use the Adobe plug-in (see Resources), which I used to test the example code.

What exactly is SVG, and when is it appropriate to use? SVG has been compared to PDF, PostScript, Flash, and HTML, but it has elements of all without duplicating any of them. SVG is complex, which allows it to be many things to many people while remaining a text format (Google can index it) and XML (you can manipulate it with the DOM). At the most basic level, it is an XML language for describing vector graphics -- pictures made by drawing lines (as opposed to bitmap graphics -- pictures made by drawing pixels). But SVG can also contain and manipulate bitmaps, text, even sound files. In addition, it can:

  • Describe ways to apply noise and other effects to vector or bitmap images
  • Specify elaborate color gradients and patterns
  • Provide links to other parts of the Web
  • Be scripted and transformed, animated, and styled
  • Be interactive in many ways.

I want to follow up on David's earlier XML Matters column on SVG by talking about SVG animation and interactivity, specifically its declarative animation and interactivity.

Note: To view the SVG documents in this article, you need an SVG viewer which you can find in Resources. You can also download a .zip file that includes all associated SVG files.

Declarative programming 101

Declarative programming is more like a description of what you want to happen, without worrying about the details of how to make it happen. Common examples of declarative programming include spreadsheets, SQL, XSLT, and programming languages such as Haskell. Other programming languages that provide a mix of declarative and procedural constructs include Lisp and Python. Several XML dialects are moving to include more declarative features in place of more complex and/or repetitive JavaScript for handling tasks such as forms validation (XForms), data mining (XQuery), transformations (XSLT), event handling (XML Events), and animation (Synchronized Multimedia Integration Language, or SMIL).

SMIL (see Resources) -- a language for mixing video, pictures, music, and text in real time -- has been adopted and extended by SVG. Much of the declarative animation in SVG is borrowed directly from SMIL (without using the SMIL namespace), although some aspects of SMIL were left out because they made no sense in the context of SVG, and others were extended. SMIL is used in RealNetworks' RealPlayer, in Apple's QuickTime, and (as XHTML+SMIL) in Microsoft's Internet Explorer. SMIL is a tool for choreography of these different media formats in response to time and events.

The declarative capability that SVG inherits from SMIL lets you animate graphics (for example) either at predetermined times, or in response to certain events. You can declare five types of animation and use many events to trigger your animations.

It's time to show you some examples.


Drawing a blank

The first example creates a canvas for the rest of the examples in this article. I'm going to drift back to grade school and use sketches of rockets and UFOs, so the background will be a simple sheet of lined notebook paper with three punch holes. This example doesn't use animation. I merely set up a canvas reminiscent of a grade-school notebook, ready for doodles. The paper is quite simple, consisting of a single svg element containing a short section of definitions: a line pattern and a small circle. Then, in the body (outside the defs) I draw a rectangle over the whole page, filling it with the line pattern. Then I grab the circle I just defined and draw it in three places. Listing 1 shows the SVG code for the notebook-paper example.

Listing 1. A sheet of notebook paper
				<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink" 
        width="100%" height="100%" fill="white">
    <defs>
        <pattern id="single_line" x="0" y="0" width="1" height="32"
                patternUnits="userSpaceOnUse" viewBox="0 0 1 32">
            <line x1="0" y1="32" x2="1" y2="32"
                stroke="lightblue" stroke-width="0.5"/>
        </pattern>
        <circle id="single_hole" width="28" height="28"
            cx="14" cy="14" r="14" 
            fill="white" stroke="black" stroke-width="0.5"/>
    </defs>
    <rect x="0" y="0" width="100%" height="100%" 
        fill="url(#single_line)" stroke="none"/>
    <use xlink:href="#single_hole" x="32" y="10%"/>
    <use xlink:href="#single_hole" x="32" y="50%"/>
    <use xlink:href="#single_hole" x="32" y="90%"/>
</svg>

To run this example in your browser, download the example code (01_paper.svg in Download). If you have installed an SVG viewer, click to see this example.


Rocket science

The second example adds one path element to the definitions and uses it once in the body of the svg (see Listing 2). The path is made up of a move statement (Mx y) and line-to statements (Lx y) in absolute coordinates. (Statements using relative coordinates would be lowercase.) The d attribute contains 1,072 statements (gathered through Wacom tablet), so I've trimmed it for brevity in Listing 2. You can view the full file all its glory in the example code (see 02_rocket_static.svg in Download).

Listing 2. A rocket ship (changes only)
				<defs>
    [...]
        <path id="rocket" stroke-width="3" stroke-linejoin="round" 
            stroke-linecap="round" stroke="#4C4C4C" fill="white" 
            d="M23 8 L21 11 L21 11 L20 16 [etc...]"/>
</defs>
[...]
<use x="50%" y="50%" xlink:href="#rocket"/>

So far, my doodle is as static as the virtual paper it's sitting on (see Figure 1), but that will change in the next example.

Figure 1. The rocket
The rocket

To run this example in your browser, download the example code. If you have installed an SVG viewer, click to see graphic.


Blast-off

At last it's time for some motion. The rocket will follow a circle to demonstrate some of the features you can expect from SVG: path following and auto-rotation. This third example demonstrates the first type of declarative animation I'll cover -- the animateMotion element (see Listing 3).

Listing 3. A rocket ship on the move (changes only)
				<defs>
    [...]
    <path id="rocket2" transform="rotate(90)" [...]/>
    <path id="circle" stroke-width="4" fill="none" stroke="#000000" 
        d="M100 350 A300,300 0 1,1 700,350 A300,300 0 1,1 100,350"/>
</defs>
[...]
<use xlink:href="#rocket">
  <animateMotion rotate="auto" dur="30s" repeatCount="indefinite">
      <mpath xlink:href="#circle"/>
  </animateMotion>
</use>

In the defs element I've added a path element that defines a circle for the rocket to move around. I've also added a rotate transform to the rocket definition so that the rocket will face the right way as it goes around the circle. SVG can turn an image so it always faces the tangent of the line it is following. I chose a circle because my hand-drawn paths made the tangent jump around. Someone with a steadier hand on the tablet might achieve better results. The important thing is that the line the animation follows can be any arbitrary path. Also note that instead of the simpler circle element, I have created the circle using a path with elliptical arcs, so the rocket has a path to follow with a beginning and an end.

To run this example in your browser, download the example code (03_rocket_moving.svg in Download). If you have installed an SVG viewer, click to see this animation.


UFO sighting

Okay, so the rocket spinning around gets old after a while. In the fourth example I spice up the scene with a visitor from another world, in a handy-dandy UFO (see Figure 2). This gives me the chance to demonstrate the vanilla animate element as well as its sibling, animateColor.

Figure 2. Unidentified flying vectors
Unidentified flying vectors

Listing 4 shows all the changes that create the UFO.

Listing 4. UFO (changes only)
				<defs>
   [...]
    <g id="ufo">
        <path id="ufo-body" d="M0 50 A100 100
            0 0 0 100 50 L100 40 A100 100 0 0 0 0 40 z"/>
        <circle id="port-1" class="port" cx="25" cy="45" r="6"/>
        <circle id="port-2" class="port"  cx="50" cy="45" r="6"/>
        <circle id="port-3" class="port" cx="75" cy="45" r="6"/>
    </g>
    <path id="back-and-forth" d="M100 50 L700 50 z"/>
</defs>
<use xlink:href="#ufo">
    <animateMotion dur="50s" repeatCount="indefinite">
        <mpath xlink:href="#back-and-forth"/>
    </animateMotion>
    <animateColor xlink:href="#port-1" dur="10s"
        repeatCount="indefinite" attributeName="fill"
        values="red;green;blue;red" begin="ufo.load"/>
    <animateColor xlink:href="#port-2" dur="10s"
        repeatCount="indefinite" attributeName="fill"
        values="green;blue;red;green" begin="ufo.load"/>
    <animateColor xlink:href="#port-3" dur="10s"
        repeatCount="indefinite" attributeName="fill"
        values="blue;red;green;blue" begin="ufo.load"/>
</use>

[...]

In the defs, I've added a ufo formed from simple SVG arcs and circles, in order to avoid another huge block of path statements from the tablet. I've also added a path to follow for moving back and forth -- a simple line. The closing z closes the path so the UFO has something to follow back to its starting point. In the body, I have a more complex use element than before which contains four different animation elements: an animateMotion similar to what you've seen with the rocket, then three animateColor blocks. Interestingly, the animateColor elements do not apply to the ufo directly (which would be the default), but instead target the UFO's individual portholes by using xlink:href attributes. I've also tied the start of each animateColor to the loading of the UFO's main element.

To run this example in your browser, download the example code (04_ufo.svg in Download). If you have installed an SVG viewer, click to see this animation.


Rockets versus UFOs

The fifth example adds user interaction, still through declarations. SVG supports all of the mouse events you expect but also has support for keyboard events -- even for specific key events, which is what I've chosen to demonstrate here. Each letter of the alphabet triggers a rocket headed for space (see Figure 3). Time to defend your home planet from the UFO invader!

Figure 3. Missile defense
Missile defense

For this example I remove the transform attribute from the rocket definition, because the rocket will no longer be going in circles, and I remove the definition for the circle. No other changes to the defs are needed. All the action this time is in the body, with 26 variations on a theme (see Listing 5).

Listing 5. Rockets versus UFOs (changes only)
				<use xlink:href="#rocket" x="4%" y="85%" display="none">
    <set id="showa" attributeName="display" to="inherit"
        dur="5s" begin="accessKey(a)"/>
    <animate dur="5s" begin="showa.begin" attributeName="y" 
        from="600" to="-100"/>
</use>

Each variation uses the same rocket I defined earlier, but ties it to a different x coordinate and an alphabetic keyboard event. When the viewer presses a key, it triggers the set element, which makes the rocket visible at the bottom of the screen. Notice how an ordinary animate element is tied to the start of the set event. This demonstrates how events can trigger other events. If you want chained events, the second event can be triggered by the end of the set event, rather than the beginning.

To run this example in your browser, download the example code (05_rocket_defense.svg in Download). If you have installed an SVG viewer, click to see this animation. Remember that you need to press a letter key or keys to trigger the rocket motion; depending on your computer's speed, you might experience a slight delay before the rockets appear.


Asteroid invasion

The final example completes your tour of declarative animation scripting in SVG with the animateTransform element. This example shows five rocks, or groups of rocks, appearing in the center of the page, hurling out toward the viewer and disappearing off the edges (see Figure 4).

Figure 4. Rocks coming right at you
Rocks coming right at you

This effect requires the animations both to nest and to influence one another. The additive="sum" attribute allows the effect of the various transforms to be cumulative. The first inner transform rotates each rock on its own axis, so that the rocks appear to be spinning as they approach the viewer. The second inner transform scales each rock so it grows (simulating the approach). Both of these transforms are applied to the rock's path, which I pull in with the use element. The outer transform, applied to the entire grouping, moves the rock out toward an edge of the view and off-screen.

Listing 6 shows only one group of animations, but the others are similar, with different points to move offscreen to, and tweaks to their starting time and duration, to mix things up. Most of the line data in Listing 6 is snipped for brevity.

Listing 6. Asteroids! (changes only)
				<defs>
    [...]
    <path id="rock1" d="M-8 -21 L-9 -21 L-15 -21 [...] />
    <path id="rock2" d="M19 -15 L18 -17 L14 -20 L12 [...] />
    <path id="rock3" d="M-17 -20 L-18 -20 L-19 -20 [...] />
    <path id="rock4" d="M11 -14 L11 -15 L10 -15 [...] />
    <path id="rock5" d="M14 -30 L13 -30 L12 -29 [...] />
</defs>
[...]
<g>
    <use xlink:href="#rock1">
        <animateTransform additive="sum" attributeName="transform"
            type="rotate" from="0" to="360" dur="6s"
            repeatCount="indefinite"/>
        <animateTransform additive="sum" attributeName="transform"
            type="scale" from="0.1" to="6.0" dur="6s"
            repeatCount="indefinite"/>
    </use>
    <animateTransform additive="sum" attributeName="transform"
        type="translate" from="600,400" to="1400,-200" dur="6s"
        repeatCount="indefinite"/>
</g>
[...]

To run this example in your browser, download the example code (06_asteroids.svg in Download). If you have installed an SVG viewer, click to see this animation.


Limitations

"Simple things should be declarative. Complex things should be procedural." --Adam Bosworth

Declarative scripting in SVG has its limits. For collision detection and real keyboard navigation, you need to add procedural JavaScript. There was talk of adding a constraint feature to SVG 1.2 but it wasn't adopted, so you need to code constraints procedurally. Adding new objects also requires scripting. Like HTML, SVG adds methods to the DOM interface for more advanced uses. Of course, you can use normal XML DOM methods as well. I think SVG is close to its tipping point, where use of SVG will grow rapidly. At the time of this writing, the latest beta of Firefox doesn't support declarative animation, but the Mozilla team is working on it. The effect once SVG is built into browsers will be huge. New tools to generate or view SVG appear all the time. The future is brighter than a rocket's red glare.


Downloads

DescriptionNameSize
Example SVG codex-matters42-examples.zip14 KB
Example HTML filesx-matters42-html-examplefiles.zip2 KB

Resources

Learn

Get products and technologies

  • Adobe SVG Viewer: Download the viewer that was used to test the examples in this article.
  • Batik: Try this Java™ technology-based SVG toolkit from the Apache-XML project.
  • Compound XML Document Editor: This standards-based, model-driven editor for mixed-namespace XML documents includes support for SVG and SMIL.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Web development
ArticleID=96522
ArticleTitle=XML Matters: SVG and the scriptless script
publish-date=03092011