Click to return to the Streaming     
Web Workshop  |  Streaming & Interactive Media

The Microsoft DirectAnimation Multimedia Controls


April 3, 1998

Sue Ledoux
Developer Technology Engineer
Microsoft Corporation

Download Download the four sample pages in .HTM format (zipped, 98.3K).

 
Contents
Introduction
Path Control
Structured Graphics Control
Sequencer Control
Sprite Control
Authoring and Run-Time Issues
Conclusion

Introduction

Remember how excited we all got when we first figured out how to animate GIFs on our Web pages? Well, progress marches on, and animated GIFs are now destined to fall by the wayside as much more powerful and flexible mechanisms evolve. The DirectAnimation™ Multimedia Controls are part of this move toward more dynamic and efficient Web pages.

The Multimedia Controls are a set of transparent, windowless ActiveX™ controls that can be used to add multimedia effects and functionality to your Web site. They are included in the minimum installation of Internet Explorer 4.0, so your users won't have to perform an additional download. Performance is improved in many situations where you wish to use a multimedia effect, because your user no longer has to download a series of bitmap images so you can create the effect using an animated GIF.

There are four Multimedia Controls. Each works independently of the others, but they can be combined on a page to provide even more interesting effects and animations. The following table summarizes the functionality of each of the controls:

Table 1. Multimedia Controls Available in Internet Explorer 4.0

Control Description
Path Moves HTML objects over time.
Structured Graphics Draws vector graphics.
Sequencer Provides timing and sequence control over scripts, intrinsic functions, and ActiveX controls.
Sprite Creates sprite-based animation.

A Bit Of History

You may have heard of or even used the Dynamic HTML Multimedia Controls in preview versions of Internet Explorer 4.0. There were seven controls: the four listed above, plus the Transitions, Filters, and Mixer Controls. They didn't actually go away -- we just got smarter about architecture and figured out a better way to organize and provide the same functionality. The Filters and Transitions Controls were reworked to build the functionality into Cascading Style Sheets (CSS), allowing much better integration with the Dynamic HTML Object Model and CSS.

Additionally, the DirectX® SDK was merged with the Internet Client SDK to enable smoother integration between Multimedia and Internet technologies. The sound functionality of the Mixer control was dropped in favor of DirectAnimation's sound capabilities, and the Path, Sequencer, Sprite, and Structured Graphics controls were integrated with DirectAnimation. To reflect this, they were renamed the DirectAnimation Multimedia Controls.

The Samples

Each Multimedia Control is described in the sections that follow. Each section includes a sample HTML file demonstrating the basic functionality of the control. Open up the sample file in your browser and see what it does, and then view the source code so that you can follow along as I explain each sample's HTML code and script.

I took the liberty of stealing many of the samples from the Internet Client SDK documentation and from the Multimedia Controls team, modifying them to suit the purpose of the article. I kept the samples simple (and yes, you might even call them boring) to make them easy to follow and understand. Their purpose is to show how to use the controls and get you going as quickly as possible. You can use your imagination to conjure up much more interesting uses for the functionality.

This article and the samples are based on the final release of Internet Explorer 4.0. If you haven't had a chance to upgrade and are still using Platform Preview 2, you will find that most of the samples will work, but there may be a few anomalies here and there.

TopBack to top

Path Control

Open Path Control sample (.HTM) in a new browser window. (Requires Internet Explorer 4.0 or later.)

The Path Control lets you move HTML objects (such as images or text) and ActiveX controls around on a page over time. Any object that has Top and Left properties that can be set from script can be controlled by the Path Control.

One instance of the Path Control is used for each moving object. The movement of the object along the path is controlled by a clock internal to the Path Control. The control has a TimerInterval property that specifies how often I would like the locations of the objects to be updated. The default is 100 milliseconds; this means that every 100 milliseconds, the control will calculate where the object should be, and will move it there. By making the timer interval smaller, you can achieve finer granularity of path movement (which may look visually smoother), but this requires more processing power. You can experiment with what tick interval works best on your page. In general, though, the default value is ideal for most applications, and you will probably want to change this value only if you are encountering performance problems and wish to slow down the refresh rate.

Let's walk through a simple example that uses two path controls on a Web page. If you run the sample HTML file (PATH.HTM) you'll see two objects, an image and a button, moving on the page. A picture of my dog, Olivia, moves continuously from left to right, and a button follows a circular path, starting and stopping whenever the image of Olivia crosses the halfway point while traveling toward the right. Straightforward HTML sets up the image and button:

<IMG ID="imgOlivia1" STYLE="POSITION:absolute; WIDTH:136; HEIGHT:228;TOP:120;LEFT:0" SRC=olivia1.gif>

<INPUT NAME=btnOlivia TYPE=button VALUE="Olivia" STYLE="POSITION:absolute;LEFT:550;TOP:120">

Specifying your Path

There are a few ways you can specify a path. The first uses the KeyFrame method, in which you specify the exact locations for your object to be at specific times. Note that the location/time pairs that you specify are not required to be matched to the value of the TimerInterval property; if they don't match, the Path Control will calculate and interpolate where your object should be at each update.

The second way to specify a path is to use one of the predefined path shape methods: Oval, Polygon, Polyline, Rect, or Spline. Each method accepts assorted parameters to define the exact shape of the path. When you use one of these, you also use the Duration property, which tells the control how long you want one round of the path to take.

Whether you use the KeyFrame method or one of the predefined paths, you can specify the path shape by using the <PARAM> tag or through script. Because I have two instances of the Path Control in my sample, I'll demonstrate both techniques.

You'll need an instance of the Path Control for each object that you want to animate. Let's look at the first of the two path objects that I set up in the sample:

<OBJECT ID=pthLeft STYLE="position:relative"
 CLASSID="CLSID:D7A7D7C3-D47F-11d0-89D3-00A0C90833E6">
 <PARAM NAME="AutoStart" VALUE="-1">
 <PARAM NAME="Repeat" VALUE="-1">
 <PARAM NAME="Bounce" VALUE="-1">
 <PARAM NAME="Target" VALUE="imgOlivia1">
</OBJECT>

I give the object a name, pthLeft (representing the path of the left-hand object on my page) so that I can refer to it later. I also position the control using the STYLE attribute. The Path control doesn't need an initial position to be set, but the position property must be set to either absolute or relative to indicate that the control will be moving. Following the CLSID of the Path Control, you'll see four <PARAM> tags that set properties of the control. First, the AutoStart property determines whether the path begins playing immediately (-1 = TRUE), or not (0 = FALSE). The Repeat property determines how many times the path will play. You can give the property a positive value to specify exactly how many times the path will play, or use -1 to repeat it infinitely. The Bounce property specifies what will happen when the object reaches the end of the path. You can reverse the path, as I do here, or simply stop the playback. And finally, the Target property indicates what object will be following the path. So, this path object will cause an image to move infinitely along a path and back again. Note that I haven't set up an actual path of travel; I'll do that later in script.

You'll see next in the code that I create another instance of the Path Control, which I've named pthRight.

<OBJECT ID=pthRight 
 CLASSID="CLSID:D7A7D7C3-D47F-11d0-89D3-00A0C90833E6">
 <PARAM NAME="AutoStart" VALUE="0">
 <PARAM NAME="Repeat" VALUE="-1">
 <PARAM NAME="Bounce" VALUE="0">
 <PARAM NAME="Duration" VALUE="5.0">
 <PARAM NAME="Shape" VALUE="Oval(450, 120, 200, 100)">
 <PARAM NAME="Target" VALUE="btnOlivia">
</OBJECT>

For the button, I've done things a little differently. I don't automatically start playback, and I don't have it bounce. The Shape property is used to specify the shape of the path using the <PARAM> tag rather than in script. The value of this property gets set to the method you'd like to use -- KeyFrame or one of the five predefined shapes. Note that the Shape property only exists for <PARAM> tag syntax; if you decide to set the shape of the path through script, simply call the method directly.

I now have two Path objects, one with an image attached and one with a button attached.

Setting the Paths Through Script

As I discussed, you can define the path through the <PARAM> tag or through script. In my sample, I define the button's path as an oval, and specify that it should take five seconds for my button to travel that oval (by using the Duration property). For the image, I'll specify the path through script, in the window_onload subroutine:

dim KeyFrameArray
dim TimeFrameArray

 KeyFrameArray = Array (0,120,50,120,100,120,150,120,200,120)
 TimeFrameArray = Array (1,1,1,1)
 pthLeft.KeyFrame 5, KeyFrameArray, TimeFrameArray

I've created two arrays here -- one contains a series of points in an x,y format, and the second contains times. Each time in the TimeFrameArray array corresponds with one of the x,y points in the KeyFrameArray array; this correspondence defines the course of the path. Note, though, that there is one less time value than point pair; the first x,y location is the initial location of the object to be animated, and the first time value indicates when the object should be at the second x,y location.

Once I've set up the KeyFrame and TimeFrame arrays, I pass them to the Path Control using the KeyFrame method. It accepts three parameters -- the number of points there are, the KeyFrame array, and the TimeFrame array.

Markers

A marker is sort of like a bookmark; it's a way for you to be notified when a particular time in the playback has been reached. An event is fired, and you can trap this event to synchronize the playback of your path with any other actions you specify. I've set one marker for demonstration purposes. I originally set up my image to travel infinitely back and forth along a straight line. I've decided that whenever the image reaches the halfway point going toward the right, I will start the playback of the other path (the moving button), or stop it if it's already moving.

You'll see two other lines in the window_onload routine:

pthLeft.AddTimeMarker 2, "OnWayThere", False
pthLeft.AddTimeMarker 6, "OnWayBack", False

This sets two markers on the pthLeft object -- a marker named "OnWayThere" that is set to fire when we are two seconds into the path playback, and another named "OnWayBack" that will fire at six seconds. Because I've defined the path to be four seconds of duration with bounce, making it effectively eight seconds long, these markers will fire halfway through the rightward path and halfway through the return path.

Sub pthLeft_onmarker(MarkerName)

 If pthRight.Playstate = 1 Then
  pthRight.Pause
 Else
  pthRight.Play
 End If

End Sub

There are two events you can choose to capture when you set a time or frame marker -- the onmarker event or the onplaymarker event. The latter is sent only if the path is playing at that particular time; other than that they are identical. I've decided to capture the onmarker event. Each time I get it, I check to see whether the button is currently moving by checking the Playstate property of the object (which returns Play, Pause, or Stop), and I toggle it between playing and paused.

If I had decided that I wanted to set more than one marker, I would have put a Select statement in the event handler, choosing each case based on the name that I specified in the AddTimeMarker method call, and performed a different action depending on which marker I received. I can also receive events from the Play, Pause, Stop, and Seek actions.

That's pretty much all you need to know to use the Path Control. The control is simple to use, and with minimal effort you can script the movement of the objects on your page in whatever manner suits your application.

TopBack to top

Structured Graphics Control

Open Structured Graphics Control sample (.HTM) in a new browser window. (Requires Internet Explorer 4.0 or later.)

The Structured Graphics Control lets you draw structured graphics (also often called vector graphics) on your Web page. The difference between structured graphics and bitmaps is that a bitmap explicitly stores every pixel of an image in a file, whereas structured graphics consist of "instructions" on how to draw things. (If you're a computer music buff, bitmaps are like WAV files, and structured graphics are like MIDI files).

The biggest advantage of using structured graphics is that the files are much smaller. Also, the elements can be easily scaled and rotated, giving you greater flexibility within your Web page. The disadvantage is that they cannot represent complex images; they're limited to primitives such as lines, ovals, wedges, and so on. You will usually use both structured graphics and bitmap images in your applications.

There are several advantages to using structured graphics. The elements can be easily scaled and rotated, giving you greater flexibility within your Web page. Also, the files are much smaller than if a bitmap were used. (Note that hand-created structured graphics files tend to be smaller than those created using a conversion tool). The disadvantage is that they cannot represent complex photographic-style images; they're limited to clipart-style images that use primitives (like lines, ovals, wedges, and so on), and that use solid colors rather than gradients and complex shading. You will usually use both structured graphics and bitmap images in your applications.

The Structured Graphics Control implements 25 methods. These methods can be grouped into two categories. First, we have the methods that actually draw something:

Table 2. Structured Graphic Drawing Primitives

Method Description
Arc Creates a single circular or elliptical arc.
FillSpline Creates a closed, filled spline curve.
Oval Creates an ellipse.
Pie Creates a single circular or elliptical arc closed to form a wedge (pie) shape.
Polygon Creates a closed polygon.
Polyline Creates a segmented line.
Polyspline Creates a closed spline curve.
Rect Creates a rectangle.
RoundRect Creates a rounded rectangle.
Text Creates a string with the current font and color.

In addition to these drawing primitives, there are a number of additional methods that help you set the characteristics of the shapes that you draw. They are listed here:

Table 3. Structured Graphic Operations

Method Description
SetFillColor Sets the foreground and background colors for graphic fills.
SetFillStyle Sets the type of fill.
SetFont Sets the font for the control.
SetGradientFill Specifies the start and end points for a gradient fill.
SetGradientShape Sets the shape of a gradient to be an outline of a polygon shape.
SetHatchFill Whether the hatch fill is transparent.
SetLineColor Sets the line color for drawing graphics.
SetLineStyle Changes the line style for the current shape.
SetTextureFill Sets the texture source to be used to fill a structured graphics shape.
Clear Clears the control of its contents, resetting it to null.
Rotate Sets the rotation of the world.
Scale Sets the current scaling in the X, Y, Z axis for the world.
SetIdentity Set the object to its original state.
Transform4x4 Sets scaling, rotating, and translation information all at once, using a transform matrix.
Translate Sets the X, Y, Z location of the world.

Multiple Syntaxes

There are two distinct ways in which methods are called in the Structured Graphics Control. The first uses the <PARAM> tag syntax, as follows:

<PARAM NAME="LineNNNN" VALUE="MethodName(parameter, parameter, ...)">

These lines appear within the <OBJECT> tag definition for the Structured Graphics object, one for each method that you would like to call. Each <PARAM> tag accepts a NAME and a VALUE. The NAME must be in the form LineNNNN where the NNNN values must be consecutive numbers starting at 0001. The VALUE specifies the desired method, along with its parameters.

The second way is to call methods in your script. For JScript™, the call would look like this:

object.
MethodName(parameter, parameter, ...)

VBScript is of course almost identical, but without the parentheses. Object is the name that you give your object using the ID attribute of the <OBJECT> tag.

All of the drawing primitive methods use the <PARAM> tag syntax, as do the SetXXX methods. The remaining methods use the script syntax. (The other DirectAnimation Multimedia Controls also use these syntaxes, usually supporting both techniques. In these cases, typically the <PARAM> tags set up the initial values for a control, and script changes the values once the animation begins playback.)

There is also one other option available to call methods in the Structured Graphics control. All the methods that use the <PARAM> tag syntax may be called from a file. To do this, set the SourceURL property of an object to a text file that contains a list of the methods you wish to call for that object. This functionality is valuable for several reasons. It enables you to change the shape associated with a control through script, which is significant because the individual methods cannot be called through script. It also provides a convenient way to package common shapes for reuse. And finally, because you don't have to use line numbers, the code is smaller, and easier to reorder. The sample for the Sequencer Control, discussed later in this article, demonstrates the use of the SourceURL property. This option also provides the best performance over the <PARAM> tag or script techniques.

Making Your Own Shapes from Scratch

If you've already looked at the SG.HTM sample provided at the top of this section, you'll notice it's a rather boring sample. I simply created an example of each of the available shapes. Because I have absolutely no artistic ability, you'll have to rely on your imagination to come up with more interesting uses of the shapes.

To use the Structured Graphics Control, create an instance of it and use that instance to draw your shape in one step. For example, here's the code for my sample rectangle:

<OBJECT ID=sgRect
 STYLE="HEIGHT:70;WIDTH:80;ZINDEX:0" 
 CLASSID="CLSID:369303C2-D7AC-11d0-89D5-00A0C90833E6">
 <PARAM NAME="ExtentTop" VALUE="0">
 <PARAM NAME="ExtentLeft" VALUE="0">
 <PARAM NAME="Line0001" VALUE="SetLineColor(255, 255, 255)">
 <PARAM NAME="Line0002" VALUE="SetLineStyle(1)">
 <PARAM NAME="Line0003" VALUE="SetFillColor(255, 0, 0, 0, 0, 255)">
 <PARAM NAME="Line0004" VALUE="SetFillStyle(1)">
 <PARAM NAME="Line0005" VALUE="Rect(0, 0, 60, 40, 0)">
</OBJECT>

This piece of code sets the line color and style, and the fill color and style. These styles set the parameters of the "brush" (this will sound familiar to Windows® programmers) that will be used to draw the shape, so they'll need to be done before the shape is drawn. Once they are done, the Rect method is used to draw a rectangle.

A Note About Coordinates

You'll notice that within the STYLE attribute of the <OBJECT> tag, I specify a WIDTH and a HEIGHT. These values define the actual screen size, in pixels, of the object's coordinate space; that is, the bounding rectangle or viewing window onto the shape. Note that you will need to specify at least one more pixel than the actual size of the object if you want to view the entire object.

You can use the ExtentLeft and ExtentTop properties to change where the shape is drawn from within the coordinate space. By default shapes are drawn from the center. However, I find this cumbersome, because the coordinate space must be properly calculated to allow the entire shape to be viewed. Consequently, I have set the ExtentLeft and ExtentTop properties to zero for all my shapes, to force them to be drawn from the upper left corner. Note, however, that the Text method is unique in that it draws from the lower left.

The ExtentWidth and ExtentHeight properties warrant a little clarification. They define the logical width and logical height of the drawing area; in other words, these numbers provide context for the width and height parameters that are given in the various drawing methods (like Rect(), Oval(), and so on). So suppose we set the WIDTH of the STYLE attribute to 200 pixels, ExtentWidth to 100 (which is logical units, now) and use the Rect() method to draw a rectangle that is 70 units wide. The width of this rectangle will then span 70% of the drawing area, (whose actual screen size was defined to be 200 pixels), or 140 pixels wide.

The defaults for ExtentWidth and ExtentHeight are the same as the actual width and height in pixels, giving you a one-to-one mapping. So if you don't need additional logical-unit functionality, you can skip setting these two properties, and the values given in the drawing methods will behave like normal pixel values.

Using the CoordinateSystem property, you can also choose whether to use a Windows-style system, where y values start at the top of the page and progress downward, or a Cartesian system, where y values start at the bottom of the page and progress upward.

Importing Graphics

Rather than having to painfully create all your structured graphics from scratch as I did in the example above, you also have the option to import any Windows Metafile (.WMF) file. This enables you to use any authoring tool on the market that creates structured graphics, as long as you export them in the .WMF format.

To import a .WMF file, run the Windows Metafile to Structured Graphics Converter (WMFCNV.EXE) that is included in the \bin directory of the Internet Client SDK. Simply use the tool to open the .WMF file, choose "HTML <PARAM> tags" under File Options, then use File Save. You can cut and paste the resulting code into your HTML file.

That's It

There's not much more than that to using the Structured Graphics Control. The Internet Client SDK documentation explains the individual parameters for each method, and my sample shows what each of the drawing primitives can do. The control also fires mouse events that you can capture, should you wish to act on mouse clicks and movements over your structured graphics.

TopBack to top

Sequencer Control

Open Sequencer Control sample (.HTM) in a new browser window. (Requires Internet Explorer 4.0 or later.)

As you saw, the Path Control enables simple manipulation of the position of an object over time. If you want to manage more complex actions over time, such as other properties of objects besides position, or the execution of script, or the manipulation of ActiveX controls, you'll want to use the Sequencer Control.

The sample (SEQ.HTM) demonstrates a simple use of the sequencer. I use a Sequencer Control to create a stopwatch that counts up in seconds and minutes. You can pause and resume the counting, and you can reset the stopwatch to begin at zero again. Obviously this is not the most efficient way to create a stopwatch, but it's a nice simple way to demonstrate the use of the Sequencer Control.

If you skip past the introductory text you'll see where I set up five Structured Graphics Controls. They display the minutes and seconds of the stopwatch as well as the separating colon. By the way, I didn't have to use the structured graphics for these numbers; I did so to make the numbers prettier (giving them a nice white border), and to demonstrate the use of the SourceURL property for structured graphics.

Here's what the code looks like that creates the tens digit of the minute display:

<OBJECT ID=sgMinTen
 CLASSID="CLSID:369303C2-D7AC-11d0-89D5-00A0C90833E6"
 STYLE="POSITION:absolute;VISIBILITY:visible;HEIGHT:300;WIDTH:300;LEFT:0;TOP:100"> 
 <PARAM NAME="Line0001" VALUE="SetFont('Verdana', 100, 650, 0, 0, 0)">
 <PARAM NAME="Line0002" VALUE="SetLineColor(255,255,255)">
 <PARAM NAME="Line0003" VALUE="SetFillColor(0,0,0)">
 <PARAM NAME="Line0004" VALUE="SetFillStyle(1)">
 <PARAM NAME="Line0005" VALUE="Text('0', 0, 0, 0)">
</OBJECT>

After creating the five Structured Graphics Controls and initializing the four digits to zeroes, I create two buttons on the page so I can stop and reset the stopwatch:

<INPUT ID=ToggleButton TYPE=button VALUE="Pause" STYLE="POSITION:absolute; LEFT:200; TOP:300" onclick="TogglePlay()">
<INPUT ID=ResetButton TYPE=button VALUE="Reset" STYLE="POSITION:absolute; LEFT:300; TOP:300" onclick="Reset()">

Finally, I create an instance of the Sequencer Control, which will be running our stopwatch:

<OBJECT ID=seq
 CLASSID="CLSID:B0A6BAE2-AAF0-11d0-A152-00A0C908DB96">
</OBJECT>

Note that the Sequencer Control doesn't have any initialization performed here; it is simply instantiated and named. The Sequencer Control has dispensed with the <PARAM> tag syntax used by some of the other controls, and all manipulation is now done through script.

Creating an Action Set

An action set is a logical grouping or sequence of actions that can be stopped, started, paused, and so on. To control my stopwatch, I use only one Sequencer object that employs one action set. This is not a requirement; there are no limits on the number of Sequencer objects per page or the number of action sets per sequencer, but optimum performance is achieved by grouping all of your actions into one action set controlled by a single sequencer.

I set up an action set to control only the least-significant digit of my stopwatch; in other words, the job of the sequencer in this example is to time and cycle the display of the single-second digit. So let's look at the script portion of the sample. The first thing I do is declare three variables: SecTen, MinOne and MinTen, to keep track of each digit in the stopwatch besides the digit that is controlled by the sequencer.

The oninit event of the sequencer gets fired as soon as the sequencer is fully loaded, so the oninit event handler routine is an ideal place to set up my sequencer object and start things moving:

Sub seq_oninit

 SecTen = 0
 MinOne = 0
 MinTen = 0

 call seq("ActionSet1").At(0.0, "DrawNum(sgSecOne, 0)")
 call seq("ActionSet1").At(1.0, "DrawNum(sgSecOne, 1)")
 .
 .
 .
 call seq("ActionSet1").At(8.0, "DrawNum(sgSecOne, 8)")
 call seq("ActionSet1").At(9.0, "DrawNum(sgSecOne, 9)")
 call seq("ActionSet1").At(10.0, "")

 call seq("ActionSet1").Play
End Sub

After initializing the variables storing the values of the higher digits of the stopwatch, I make successive calls to the At method. It is this method that actually sets up the sequence of events that are associated with an action set and played back on command. The parameters of the At method are as follows:

I use only the first two parameters to the At method, because I don't require looping, and I don't have multiple actions taking place simultaneously. I set up an action set called "ActionSet1" that consists of eleven actions. The first 10 call the DrawNum subroutine at one second intervals to actually display the single-second digit of the stopwatch.

The DrawNum routine itself is very straightforward. It accepts two parameters: sgClockNum indicates which of the Structured Graphics objects I refer to, and Num specifies what number I would like drawn. DrawNum employs the SourceURL property of the Structured Graphics Control to enable us to change the contents of the object dynamically, through script (by reading in the methods used to draw each number from a text file).

Sub DrawNum(sgClockNum, Num)
 Select Case Num
  Case 0
   sgClockNum.SourceURL = "0.txt"
  Case 1
   sgClockNum.SourceURL = "1.txt"
  .
  .
  .
  Case 9
   sgClockNum.SourceURL = "9.txt"
 End Select
End Sub

Back to the seq_oninit subroutine: the final call to the At method has no procedure associated with it, and simply allows the correct one-second interval to elapse before ending the playback of the sequence. And finally, once the action set has been set up, I call the Play method of the Sequencer Control and the whole thing starts playing.

Counting Up

Okay, so now I've got the sequence playing. If I just left it at that, I would count up from zero to nine in the single-second digit of the stopwatch, and then stop. To have the stopwatch operate properly, I'll take advantage of a few more features of the Sequencer Control.

Whenever an action set has completed its playback, it fires an onstop event. I use this event to update the rest of the digits of the stopwatch. The onstop event handler routine looks like this:

Sub seq_onstop(ActionSetName)

 SecTen = SecTen + 1
 If SecTen = 6 Then
  SecTen = 0
  MinOne = MinOne + 1
  If MinOne = 10 Then
   MinOne = 0
   MinTen = MinTen + 1
   If MinTen = 6 Then
    MinTen = 0
   End If
   DrawNum sgMinTen, MinTen
  End If
  DrawNum sgMinOne, MinOne
 End If
 DrawNum sgSecTen, SecTen

 call seq("ActionSet1").Play
End Sub

I can ignore the ActionSetName parameter. If I had set up multiple action sets for the sequencer, this parameter would determine which action set had fired the event.

When I receive this event, I know that our single-second digit has reached nine. So most of this event handler calculates which of the other digits need to be advanced, stores the new value for each digit, and draws the new digit if necessary. Then the last line of the subroutine calls the Play method of the sequencer, which restarts the playback of the single-second digit counting.

Stop and Go

Now, let's look at the two buttons I put on the page. The HTML definition of the first button, which I named "ToggleButton", specifies that a subroutine called TogglePlay is to be called when the button is pressed. Let's look at that subroutine now:

Sub TogglePlay
 If seq("ActionSet1").PlayState = 1 Then
  ToggleButton.value = "Resume"
  call seq("ActionSet1").Pause
 Else
  ToggleButton.value = "Pause"
  call seq("ActionSet1").Play
 End If
End Sub

This routine allows you to pause and restart the stopwatch. It makes use of the PlayState property, one of the two properties available on an action set. (The other property is the Time property, which gives elapsed time since the beginning of playback). The PlayState property is a read-only property that can have one of three values: 0 = stopped, 1 = playing, and 2 = paused. I am only interested in whether the stopwatch is playing. If it is, I pause the playback and change the text of the button to read "Resume". If it is not playing, I start it playing again and make the button read "Pause".

The second button, labeled "Reset", allows you to reset the stopwatch back to zero. When pressed, it calls the Reset subroutine.

Sub Reset
 SecTen = 0
 MinOne = 0
 MinTen = 0
 DrawNum sgMinTen, 0
 DrawNum sgMinOne, 0
 DrawNum sgSecTen, 0
 DrawNum sgSecOne, 0
 call seq("ActionSet1").Seek(0.0)
End Sub

This reinitializes all the variables and draws a zero in all four digit positions. It then calls the Seek method of the sequencer, which resets the time position of the sequencer. Note that the Seek method does not affect the play state of the action set, so this will work correctly whether the stopwatch is currently playing or not playing.

That's all there is to it. You don't even need to call the Stop method in the window_onunload subroutine, because the control automatically stops playback and cleans things up for you when the unload event is fired.. Although it is very easy to use, the Sequencer Control is a very powerful control that enables you to animate or manipulate over time just about anything on your Web page.

TopBack to top

Sprite Control

Open Sprite Control sample (.HTM) in a new browser window. (Requires Internet Explorer 4.0 or later.)

Some of you may have used animated GIFs on your Web pages to create simple animations by cycling through images. You can create animations in a similar manner with the Sprite Control. But where animated GIFs give you a rudimentary ability to animate images, they are very limited in functionality. The Sprite Control provides greater control over playback, and you can capture and react to events based on mouse activity and playback position.

Let's start by taking a look at the sample I've created in SPRITE.HTM. Once again, I treat you to the delights of Olivia, this time engaged in her two favorite activities: smiling and eating. And once again, let me apologize for the artwork -- the pathetic presentation of these animations has nothing to do with the Sprite Control and everything to do with my utter lack of artistic talent. But after all, this is only a sample; if this had been a real application, I would have used an actual artist.

So, having said that, let's have a look at what I did. When you run the sample, you'll see Olivia just sitting there and smiling (yes, that is how a dog smiles). Then, if you press the first button, her dreams come true: a bone materializes out of thin air, she eats it, and then goes back to smiling. The second button causes her to eat it even faster.

I've set up two sprites on this page -- one for Olivia, and one for the bone. Looking at the code for the page, you'll see the usual introductory blurb, and then an instantiation of the Sprite Control to create the first sprite:

<OBJECT  ID="Olivia" WIDTH=136 HEIGHT=228 STYLE="POSITION:absolute; LEFT:100; TOP:150; VISIBILITY:visible" 
 CLASSID = "CLSID:FD179533-D86E-11D0-89D6-00A0C90833E6">
 <PARAM NAME="SourceURL" VALUE="olivia3.gif">
 <PARAM NAME="NumFrames" VALUE=3>
 <PARAM NAME="NumFramesAcross" VALUE=1>
 <PARAM NAME="NumFramesDown" VALUE=3>
 <PARAM NAME="FrameMap" VALUE="1,0.100;2,0.100;3,0.100;2,0.100">
 <PARAM NAME="UseColorKey" VALUE="True">
 <PARAM NAME="ColorKey" VALUE="255,255,255">
 <PARAM NAME="AutoStart" VALUE=1>
 <PARAM NAME="Repeat" VALUE=-1> 
</OBJECT>

This piece of code creates a sprite object named "Olivia" and initializes various properties. The SourceURL property specifies the sprite source, an image file that contains the actual frames of the sprite. This file can be in .GIF, .PNG, .JPG, or .WMF format. The sprite source file consists of multiple frames, each the same size. There can be multiple rows and/or columns of frames within the file, and the NumFrames, NumFramesAcross and NumFramesDown properties tell the Sprite Control the configuration of the frames within the file.

The default playback order of the frames from the sprite source file starts at the top left of the file, moves left to right across each row, then down to the next row. If you would like the frames played back in a different order, you can use the FrameMap property to specify the playback order. This is handy if you have frames that you want repeated; by specifying the order, you can avoid duplicating identical frames within the file, thereby keeping the sprite source smaller. A frame map is also useful if you don't want all the frames displayed for the same amount of time, because the frame map also contains display times for each frame.

If you look at the sprite source for Olivia (in the OLIVIA3.GIF file), you'll see three images of Olivia, each with her tongue sticking out a different amount. The FrameMap property has assigned to it four pairs of numbers, separated by semi-colons. Each pair consists of the frame number followed by the length of time to display that frame. I specify the order of the frames to be 1 - 2 - 3 - 2 to give the impression that Olivia's tongue is going in and out. Since she's a very rhythmic breather, I have each frame displayed for the same amount of time.

You may have observed that the duplication of the image of Olivia three times is not the most efficient way to do this. If this were a real animation on a real Web page, where download time is always a concern, I would have made only the tongue a sprite, and I'd have layered the tongue sprite over a single image of Olivia. But because this is only a sample, I'm allowed to be lazy.

After setting the FrameMap property, you'll see that I set the UseColorKey property to True, and specify that the RGB value of 255,255,255 (white) is my color key value. This tells the Sprite Control that all the white pixels in my sprite source should be transparent when rendered. Next, the AutoStart property is set to 1 (non-zero = TRUE, zero = FALSE) so that the Olivia sprite will begin playback as soon as the Sprite Control and image are loaded. And finally, the Repeat property indicates how often the sprite playback should loop. I've set it to -1, which represents infinity, because Olivia is a very happy puppy.

After setting up a sprite object for Olivia, I instantiate and initialize another one for the bone. Most of the parameters are similar, with just a few exceptions. For the bone sprite, I don't specify a frame map, because I simply want the frames of the bone to be played back in the order that they appear in the sprite source file. I specify a TimerInterval property of 200 milliseconds; this sets the length of time between the display of each frame of the bone animation (I could have left this out and the default of 100 milliseconds would have applied). The TimerInterval property isn't needed if you have a frame map because you are explicitly specifying the length between each frame. As with the Path control, the TimerInterval property can usually be left at its default value; changes are needed only if you have a performance problem. I've specified it here only to demonstrate usage. There are only a few other minor differences in the setup of the bone sprite object: I have eight frames instead of three, I don't want playback to start right away, and I want playback to loop only once.

Adding a Marker

Now that I have both sprites set up, let's look at the script portion of the sample. The window_onload subroutine has only one line in it:

Bone.AddFrameMarker 8, EndBone

You've already been introduced to markers in the Path Control, where you can choose to have an event fired when a particular time in the playback is reached. The Sprite Control uses markers in the much the same way, but expands the functionality a bit. You can have a frame marker, in which the event is fired when playback reaches a certain frame, or a time marker, in which you specify what time during playback you want the event to fire. In my sample, I've requested that an event be fired when playback of the bone reaches the eighth frame. I've named this marker "Endbone", though it's not really needed here because I have only one marker. If you create multiple markers, the names can distinguish which event you're handling.

Changing Playback Rate

Playback of the bone animation is initiated by pressing one of the two buttons, labeled "Hungry" and "Really Hungry" (representing the two possible states of a small Rottweiler puppy). The buttons were previously defined as follows:

<INPUT TYPE=button VALUE="Hungry" STYLE="POSITION:absolute; LEFT:135; TOP:400" onclick="FeedOlivia(1.0)">
<INPUT TYPE=button VALUE="Really Hungry" STYLE="POSITION:absolute; LEFT:100; TOP:440" onclick="FeedOlivia(4.0)"> 

When either button is pressed, the FeedOlivia subroutine is called. A single parameter is passed to this routine, specifying the playback rate of the sprite. The routine looks like this:

Sub FeedOlivia(PlayRate)
 olivia.Stop
 bone.Style.Visibility = "visible"
 bone.PlayRate = PlayRate
 bone.Play
End Sub

The FeedOlivia subroutine stops the playback of the Olivia sprite (after all, one can't pant and eat at the same time), changes the visibility attribute of the bone sprite to visible, uses the PlayRate parameter to set the PlayRate property of the bone sprite object, and then begins playback of the bone animation. The PlayRate property gives you the ability to alter the speed or direction of playback independently of the initial frame intervals you have set up. A value of 1.0 causes no change to the playback rate. Values between 0.0 and 1.0 slow down playback, values over 1.0 speed it up, and negative values reverse the order of playback. For my "Hungry" button, I specified a playrate of 1.0, while the "Really Hungry" merits a speedy 4.0 value.

Once the bone has reached the eighth frame, the event fired as a result of the marker I set up is handled in the bone_onmarker subroutine, which contains only three lines:

 bone.Stop
 bone.Style.Visibility = "hidden"
 olivia.Play

The bone.Stop method call is superfluous in this instance, because I specified no looping and this was the last frame anyway. Next, I change the visibility attribute of the bone back to hidden, and then I restart the playback of the Olivia sprite.

Note that I could've just as easily captured the onstop event of the bone sprite object to perform these last steps. I set a marker on the last frame of the bone playback only to demonstrate the use of markers, but in normal playback without looping, using the onstop event is functionally equivalent to setting a marker event for the last frame of the sprite.

This gives you a tour of the main functionality available in the Sprite Control. You can specify the order, speed, and direction of playback; you can start, pause, stop, and seek during playback; and you can set and capture events based on mouse movement, frame location, elapsed time, and media download completion. This functionality gives you all you need to easily create and control sprite-based animations on your Web page.

TopBack to top

Authoring and Runtime Issues

Authoring

To use the DirectAnimation Multimedia Controls on your Web pages, you'll need version 4.0 of Internet Explorer Non-MSDN Online link (which includes the controls as part of its minimum install), and the Internet Client SDK, which contains the reference documentation that gives complete coverage of all of the methods, properties, and events supported by the Multimedia Controls. If you don't wish to download the Internet Client SDK, the documentation is also accessible online at http://www.microsoft.com/directx/dxm/help/da/default.htm Non-MSDN Online link.

Distribution and Run-Time

Because the Multimedia Controls are included in the minimum installation of Internet Explorer 4.0, users of this version of Internet Explorer will not have to download anything extra. You will probably want to check which browser the user has installed, and provide an alternate page or code path for users not using Internet Explorer 4.0.

Conclusion

This article gave you a great introduction to the DirectAnimation Multimedia Controls (not to mention my dog Olivia). The Multimedia Controls offer a wide range of functionality but are very easy to use; with a little imagination, your Web sites will soon be alive with multimedia effects and animations.



Back to topBack to top

Did you find this material useful? Gripes? Compliments? Suggestions for other articles? Write us!

© 1999 Microsoft Corporation. All rights reserved. Terms of use.