Dev.Opera - Follow the standards, break the rulesDev.Opera - Follow the standards, break the rules

Login

Lost password?

SVG Evolution 2: Our First Steps Into SVG

Breathing Life Into the UI

As far as web applications go, our photo gallery user interface is very simple and not very interactive. There is nothing in the UI that responds organically or reacts to mouse movements to indicate the application is alive and well. Modern applications sport these interfaces not just because they look good but offer the user a sense of satisfaction that they are operating a well-oiled machine and not a dated, rusty antique. It tells the user something is happening and makes the application seem responsive.

We are going to make our preview SVG document respond to mouse-over/mouse-out events by highlighting the moused-over image. Such techniques have been used for a long time in web applications by some combination of HTML, CSS and/or JavaScript. For a touch of class, we're going to animate the highlighting such that it smoothly transitions from dim to bright. And we're going to do it without any JavaScript or CSS using SVG Declarative Animation instead.

Dropping A Veil

Our first step is to add a "veil" on top of the thumbnail raster image to darken it. The veil will be a semi-transparent black and will completely cover the image:

<g id="thumbnail" onclick="showPreviewFromSVG(this, event); return false;" cursor="pointer">
  <rect id="blueborder" x="0" y="0" width="104" height="79" fill="blue"/>
  <image id="theImage" class="thumb" x="2" y="2" width="100" height="75"/>
  <rect id="veil" fill="black" x="2" y="2" width="100" height="75" fill-opacity="0.3">
  </rect>
</g>

Note that the above "veil" element has an opacity of 0.3, which has the effect of darkening all the thumbnail images slightly.

Animation

Next, we add some animation to the veil. We are only going to touch briefly on the topic of animation, since there have already been two excellent articles on SVG animation (here and here). For this animation, our needs are simple:

  • when the mouse enters the thumbnail, animate the fill-opacity of the veil from 0.3 to 0.0 over 250ms
  • when the mouse leaves the thumbnail, animate the fill-opacity of the veil from 0.0 to 0.3 over 250ms

Since the subject of the animation is the veil, we add two <animate> elements as children to the "veil" <rect> element. The attribute of the "veil" element that we want to animate is the fill-opacity attribute. Here is the same code as above with the animation bits added:

<g id="thumbnail" onclick="showPreviewFromSVG(this, event); return false;" cursor="pointer">
  <rect id="blueborder" x="0" y="0" width="104" height="79" fill="blue"/>
  <image id="theImage" class="thumb" x="2" y="2" width="100" height="75"/>
  <rect id="veil" fill="black" x="2" y="2" width="100" height="75" fill-opacity="0.3">
    <animate attributeName="fill-opacity" attributeType="XML" 
      begin="mouseover" dur="0.25s" fill="freeze" to="0.0" />
    <animate attributeName="fill-opacity" attributeType="XML" 
      begin="mouseout" dur="0.25s" fill="freeze" to="0.3" />
  </rect>
</g>

The to attribute is the final value that the attribute should have. The dur attribute is how long the animation should take. The begin attribute defines when that animation will start (in this case, the animations begin upon a mouseover/mouseout event). The fill attribute defines what will happen when the animation is over: in this case we want to freeze the values once the animation is finished (the other option is "remove" which would remove the animated effect once the animation is complete, obviously we do not want this for our example) .

Click Here to play with the animation by waving your mouse over the thumbnail images.

Conditional Processing: The Cold Hard Reality

While declarative animation is really cool, the unfortunate reality is that, as of 2006, very few desktop web browsers support it. Opera 9 is an exception in this case, so the effect (although subtle) in the example above is not lost on users of that browser. However, what happens to the rest of the browsers? In those browsers, the <animate> elements are ignored, thus all thumbnails will be slightly darkened and remain that way with no other visible effect.

Now, darkening all the thumbnail images isn't the end of the world, but for users of browsers that don't support animation, we are darkening the images for no apparent reason. We'll briefly address how to handle this situation next.

The SVG spec is huge, packed with many features. The spec authors realized this, and consequently realized that expecting user agent developers to support all features of the SVG language during the early phases of adoption would be unrealistic. As a result, SVG supports conditional processing, which allows content developers and web authors to produce fall-back content when a particular SVG feature is not supported. A list of SVG feature strings is available in the spec here.

The key to conditional processing is the <switch> element and the requiredFeatures attribute. As per the spec: The 'switch' element evaluates the requiredFeatures, requiredExtensions and systemLanguage attributes on its direct child elements in order, and then processes and renders the first child for which these attributes evaluate to true. In other words, we can wrap the "veil" <rect> element of our thumbnail image in a <switch> element and then add a requiredFeatures attribute to the <rect> elements. In this way, if the user agent supports declarative animation, the "veil" <rect> will be rendered (and its <animate> children will be processed) and if declarative animation is not supported, then the "veil" <rect> element is not processed or rendered.

Here is the final code for the thumbnail SVG image:

<g id="thumbnail" onclick="showPreviewFromSVG(this, event); return false;" cursor="pointer">
  <rect id="blueborder" x="0" y="0" width="104" height="79" fill="blue"/>
  <image id="theImage" class="thumb" x="2" y="2" width="100" height="75"/>
  <switch>
  <rect id="veil" fill="black" x="2" y="2" width="100" height="75" fill-opacity="0.3"
  requiredFeatures="http://www.w3.org/TR/SVG11/feature#Animation">
    <animate attributeName="fill-opacity" attributeType="XML" 
      begin="mouseover" dur="0.25s" fill="freeze" to="0.0" />
    <animate attributeName="fill-opacity" attributeType="XML" 
      begin="mouseout" dur="0.25s" fill="freeze" to="0.3" />
  </rect>
  </switch>
</g>

Click Here to see this in action. For Opera 8/9 users, this example (Example 5) works identically to the previous example (Example 4) and for Firefox 1.5/2.0 users, this example works identically to Example 3 (with no animation).

Alternative Solutions

I should point out a couple other possible solutions that may have occurred to the astute reader:

  • We could have scripted the animation here for Firefox users by creating event listeners and then using setTimeout to adjust the value of fill-opacity in the SVG DOM, or we could have used the excellent smilscript until such time as Firefox supports declarative animation.
  • Even easier, instead of using the veil to darken all thumbnails and removing it when hovered over, we could have used the veil to lighten the hovered thumbnail (by filling the veil with white) and then having the fill-opacity attribute animate from 0.0 to 0.3 when the thumbnail was moused over. In the real world, this would be a preferred approach, but to be honest, we were using this somewhat contrived example to illustrate the conditional processing functionality within SVG. We leave this as an exercise for the reader.

Are you still with me? Ok, enough playing around with this glitzy animation, let's get into some actually useful SVG functionality on the next page.

Article categories