WebDevelopersJournal.comTips on Web Page Design, HTML and Graphics
SITE SEARCH
Newsletters
HTML (M-F) Text (M,TH)



Jobs at webdeveloper.com

Resources By Subject
Technical
Graphical
Authoring
Business
WDJ resources
Archive

internet.com

internet.commerce
  • Partner With Us
















Developer Channel


Find a web host with:
CGI Access DB Support Telnet Access
NT Servers UNIX Servers



Semi-automatic?

JavaScript
JavaScript Helper:
Meet Paige Turner, the least geeky geek we've ever come across.

Variables and Operators Explained:
First of a three part guide to JavaScript basics.

Controlling Forms:
Enhance your HTML forms with a touch of JS.

DHTML:
Forget how it works, let's see some in action!


Direct Animation And The Structured Graphic Control - Part 2

by Jon Perry

DirectX taken a step further

In the first article, we saw how to create basic shapes using the Direct Animation element of DirectX, specifically the Structured Graphic Control (SGC) ActiveX object. The SGC is a lot more powerful than this. We can enhance these shapes and apply transformations to them, and that's exactly what we'll do in this article.
February 29, 2000

Go to Part 1

We will finish by opening the Drawing Surface up, allowing the SGC to be used entirely from script - no more re-numbering! - and revealing a host of powerful graphics routines.

As I said in Part 1, we can change the pen (the outline), and the brush (the fill color and style) of the SGC. We can also manipulate the actual graphic - rotating it, scaling it or translating it.

To begin with, we will look at improving the plain outline shape, starting with the SGC pen.

Pens

When we draw a picture, there are two components we draw. One is the outline of the shape, and the other is the contents of the shape. In computer graphics terminology, the pen draws the outline, and a brush creates the contents.

The SGC provides us with a variety of pens. We can change the pen's color and the pen's style - solid, dashed and invisible.

The color command is:

<PARAM NAME="Linexxxx" VALUE="SetLineColor(r, g, b)">

Each parameter has the following function.

Parameter Description
r The red color component
g The green color component
b The blue color component

The style of the pen is governed by:

<PARAM NAME="Linexxxx" VALUE="SetLineStyle(style)">

Each parameter has the following function.

Parameter Description
style 0 - no outline
  1 - solid
  2 - dashed

To see this, we can take an ordinary shape, and alter the outline to produce the three different effects, though 'no outline' is invisible to the eye.

<HTML>
<HEAD>
<TITLE>Red Dashed Square</TITLE>
</HEAD>
<BODY>
<OBJECT ID="RDS" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetLineStyle(2)">
<PARAM NAME="Line0002" VALUE="SetLineColor(255,0,0)">
<PARAM NAME="Line0003" VALUE="Rect (-100, -100, 100, 100, 30)">
</OBJECT>
</BODY>
</HTML>

Change the value in the parenthesis of the SetLineStyle parameter to see the different effects possible.

If we change the <BODY> definition to:

<BODY style="background-color:black">

then strange things start to happen. The basic shape is filled in white, because the brush is white by default, but if the SetLineStyle property is 0, then the outline is rendered in black - or more precisely - is not rendered at all.

Brushes

Brushes provide the content for an outline. When we created the red oval example in Part 1, we set the brush to red, using the SetFillColor method.

SetFillColor is defined similarly to SetLineColor.

<PARAM NAME="Linexxxx" VALUE="SetFillColor(r, g, b, backr, backg, backb)">

Each parameter has the following function.

Parameter Description
r The red color component
g The green color component
b The blue color component
Backr The red background color component
Backg The green background color component
Backb The blue background color component

We have a greater range of brush styles, although again the function is similar to the pen style function.

<PARAM NAME="Linexxxx" VALUE="SetFillStyle(style)">

Each style represents the following fill type (or brush).

Style Description
1 Solid
2 Transparent
3 Hatch horizontal
4 Hatch vertical
5 Hatch forward diagonal
6 Hatch backward diagonal
7 Hatch cross
8 Hatch diagonal cross
9 Horizontal gradient

So, to fill a shape in a certain style and color, we could use:

<HTML>
<HEAD>
<TITLE>Filled Pie</TITLE>
</HEAD>
<BODY>
<OBJECT ID="PieChart" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetLineColor(127, 255, 30)">
<PARAM NAME="Line0002" VALUE="SetFillStyle(1)">
<PARAM NAME="Line0003" VALUE="SetFillColor(0, 255, 0)">
<PARAM NAME="Line0004" VALUE="Pie(-100, -100, 100, 100, 0, 60, 0)">
<PARAM NAME="Line0005" VALUE="SetFillStyle(2)">
<PARAM NAME="Line0006" VALUE="SetFillColor(0, 0, 255)">
<PARAM NAME="Line0007" VALUE="Pie(-100, -100, 100, 100, 60, 180, 0)">
<PARAM NAME="Line0008" VALUE="SetFillStyle(7)">
<PARAM NAME="Line0009" VALUE="SetFillColor(0, 255, 255)">
<PARAM NAME="Line0010" VALUE="Pie(-100, -100, 100, 100, 240, 120, 0)">
</OBJECT>
</BODY>
</HTML>

This program presents a professional pie chart as a feature of the SGC.

With care, we can highlight a piece of the pie chart by displacing it. Try replacing the original 'Line0010' with this new one.

<PARAM NAME="Line0010" VALUE="Pie(-95, -95, 105, 105, 240, 120, 0)">

You may be wondering what the background colors from the SetFillColor definition are used for. They can be used with the SetHatchFill method.

When we use a hatch brush, we create a fill with a hatch pattern. Between the hatch lines we have a choice. We can either leave these areas transparent, or we can fill them in with the background color.

<PARAM NAME="Linexxxx" VALUE="SetHatchFill(transparent)">

The choices are 0 for transparent or 1 for 'use the background color'.

An example demonstrates this:

<HTML>
<HEAD>
<TITLE>Oval Hatch Fill</TITLE>
</HEAD>
<BODY>
<IMG SRC="ABC.JPG" STYLE="position:absolute;top:90;left:90;height:120;width:120">
<OBJECT ID="Oval" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetFillStyle(5)">
<PARAM NAME="Line0002" VALUE="SetHatchFill(1)">
<PARAM NAME="Line0003" VALUE="SetFillColor(0, 255, 0, 0, 0, 255)">
<PARAM NAME="Line0004" VALUE="Oval(-100, -100, 100, 100, 0)">
</OBJECT>
</BODY>
</HTML>

When the SetHatchFill property is 0, we can see nearly all of the background image. When it is 1, we see only the outside of the image, and we see blue between the hatch lines.

Once we have our image, we can manipulate it on a web page, as well as dynamically interact with it. Dynamical manipulation is the same as for any HTML object and DHTML, change the style.left, style.top properties.

To directly affect the graphic as it stands we can use Control Methods.

Control Methods

Control methods can rotate, scale and translate the image. All of these methods work in a 3D co-ordinate space, with x running from left to right, y form top to bottom, and the z-axis coming straight out of the screen.

Rotate

The rotate method rotates the entire structured graphic by any angle, given in degrees. We can rotate around all three axis, which produces spectacular effects when used correctly.

The syntax for rotate is:

SGCobject.rotate(x-rotation, y-rotation, z-rotation)

SGCobject is the name of a structured graphical object.

*-rotation represents the angle of rotation about the * axis.

The code, like the other control methods, is incorporated into a <SCRIPT> element.

The z-axis is the axis that rotates the image on a page, for example like the rotating oval example in Part 1, the x and y axis produce a rolling motion as the graphic repeatedly becomes full-on and fades to a line.

As an example of axis rotation, this program allows you to selectively switch rotation about a particular axis on and off, and have simultaneous axial rotations.

<HTML>
<HEAD>
<TITLE>Axis rotate</TITLE>
<SCRIPT>
x=false;
y=false;
z=false;

function axis() {
if (x) Rect.rotate(5,0,0);
if (y) Rect.rotate(0,5,0);
if (z) Rect.rotate(0,0,5);
status='x:'+x+' y:'+y+' z:'+z;
setTimeout('axis()',100);
}
</SCRIPT>
</HEAD>
<BODY onload="axis();">
<OBJECT ID="Rect" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetFillStyle(1)">
<PARAM NAME="Line0002" VALUE="SetFillColor(0, 0, 255)">
<PARAM NAME="Line0003" VALUE="Rect(-100, -100, 100, 100, 0)">
</OBJECT>
<BUTTON onclick="x=!x;">X axis</BUTTON>
<BUTTON onclick="y=!y;">Y axis</BUTTON>
<BUTTON onclick="z=!z;">Z axis</BUTTON>
<BUTTON onclick="Rect.setIdentity();">Set Identity</BUTTON>
</BODY>
</HTML>

The status bar displays whether a particular axis is being rotated about (true) or not (false). As an exercise, you could store the angles each axis has been rotated through and display these values in the status bar.

The axis() routine is called periodically by the setTimeout function, which rotates any 'live' axis. These can be altered using the buttons provided, which negate the current value of the axis variable in order to switch the 'is rotating' Boolean property for each axis.

An interesting feature of rotate, and the rotation property, and the defining coordinates for the shape, is that they can all be used independently on the same graphic.

If we offset the shape from the origin, the rotate method produces a 'Catherine Wheel' type of rotation.

Replace 'Line0003' with:

<PARAM NAME="Line0003" VALUE="Rect(-80, -80, 120, 120, 30)">

to see this in practice.

setIdentity

This program introduces another control method, setIdentity(), which restores the graphic to its original form. setIdentity() resets all rotations, scales and translations to the original values.

scale

The scale method enlarges or reduces a graphic along any of the axis.

The syntax for scale is:

SGCobject.scale(x-scale, y- scale, z- scale)

SGCobject is the name of a structured graphical object.

*-scale represents the multiplying factor for each axis.

The code for this example is very similar to the code for the rotate method, you may wish just to edit one into the other.

<HTML>
<HEAD>
<TITLE>Axis Scale</TITLE>
<SCRIPT>

function axis(n) {
switch (n) {
case 0:Rect.scale(1.1,1,1);break;
case 1:Rect.scale(0.9,1,1);break;
case 2:Rect.scale(1,1.1,1);break;
case 3:Rect.scale(1,0.9,1);break;
}
}
</SCRIPT>
</HEAD>
<BODY>
<OBJECT ID="Rect" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetFillStyle(1)">
<PARAM NAME="Line0002" VALUE="SetFillColor(0, 0, 255)">
<PARAM NAME="Line0003" VALUE="Rect(-100, -100, 100, 100, 0)">
</OBJECT>
<BUTTON onclick="axis(0);">X enlarge</BUTTON>
<BUTTON onclick="axis(1);">X shrink</BUTTON>
<BUTTON onclick="axis(2);">Y enlarge</BUTTON>
<BUTTON onclick="axis(3);">Y shrink</BUTTON>
<BUTTON onclick="Rect.setIdentity();">Set Identity</BUTTON>
</BODY>
</HTML>

When we scale, it is important to remember to set any axis we are not scaling to 1, and not 0 as with rotate. Setting these values to zero results in a scale to nothing, and the graphic disappears.

The buttons in this example only enlarge or shrink the x and y axis. The z-axis in this graphic has zero size, and so can't be enlarged or shrunk.

Translate

The translate method moves the origin of the graphic along any axis.

The syntax for translate is:

SGCobject.scale(x-coordinate, y- coordinate, z- coordinate)

SGCobject is the name of a structured graphical object.

*-coordinate represents the translation of the origin for each axis.

The program allows you to move the graphic left, right, up or down.

<HTML>
<HEAD>
<TITLE>Axis Translation</TITLE>
</HEAD>
<BODY>
<OBJECT ID="Rect" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" STYLE="position:absolute;top:0;left:0;width:400;height:400">
<PARAM NAME="Line0001" VALUE="SetFillStyle(1)">
<PARAM NAME="Line0002" VALUE="SetFillColor(0, 0, 255)">
<PARAM NAME="Line0003" VALUE="Rect(-100, -100, 100, 100, 0)">
</OBJECT>
<BUTTON onclick="Rect.translate(-10,0,0);">left</BUTTON>
<BUTTON onclick="Rect.translate(10,0,0);">right</BUTTON>
<BUTTON onclick="Rect.translate(0,-10,0);">up</BUTTON>
<BUTTON onclick="Rect.translate(0,10,0);">down</BUTTON>
<BUTTON onclick="Rect.setIdentity();">Set Identity</BUTTON>
<BUTTON onclick="Rect.clear();">Clear</BUTTON>
</BODY>
</HTML>

This program is fairly simple to follow.

It does however introduce the final control method, clear().

clear

The clear method removes all the contents of the SGC from the screen. Once removed, you cannot get them back. This method is of more use when we use the Drawing Surface, which allows more flexibility and freedom when we create our shapes.

And this is how we will finish this article. So far, we have seen how to produce a wide variety of colourful shapes, and manipulate them in interesting ways. But we have been constrained by HTML and the awkward line numbering system.

We can jump two hurdles with one leap here. The SGC uses a Drawing Surface, which is the canvas we have been drawing on. We can remove the line numbering system, and release a great deal more graphical power onto the canvas using the next level of the SGC.

Drawing Surface

The DrawingSurface is a Direct Animation object. We can access it through the DrawSurface property. We may also need to use the Direct Animation Library, which contains very useful functions.

This entire topic is too large to cover here, but to get you started on the right track, here is a working example of an SGC that uses the DA Library and DrawSurface.

<HTML>
<HEAD>
<TITLE>DrawSurface</TITLE>
</HEAD>
<BODY>
<OBJECT ID="SG1"
STYLE="position:absolute; top:0 left;0;width:400;height:400"
CLASSID="CLSID:369303C2-D7AC-11d0-89D5-00A0C90833E6">
</OBJECT>
<SCRIPT>
lib = SG1.Library;
ds = SG1.DrawSurface;
ds.fillcolor(lib.blue);
ds.fillstyle(1);
ds.rect(-50,-100,150,150);
ds.fillcolor(lib.red);
ds.oval(-30,-50, 100, 120);
SG1.DrawSurface = ds;
SGrotate();

function SGrotate() {
SG1.rotate(0,0,5);
setTimeout('SGrotate()',10);
}
</SCRIPT>
</BODY>
</HTML>

This is adapted from one of Microsoft's examples. I have converted it into JavaScript and changed some of the details.

We still follow a formal procedure to create the graphic at first. We still need a SGC, and this SGC must have an ID.

<OBJECT ID="SG1"
STYLE="position:absolute; top:0 left;0;width:400;height:400"
CLASSID="CLSID:369303C2-D7AC-11d0-89D5-00A0C90833E6">
</OBJECT>

We use this reference to the SGC to extract the separate Library and DrawSurface properties.

lib = SG1.Library;
ds = SG1.DrawSurface;

We can then draw on the DrawSurface using similar commands to the HTML version.

ds.fillcolor(lib.blue);
ds.fillstyle(1);
ds.rect(-50,-100,150,150);
ds.fillcolor(lib.red);
ds.oval(-30,-50, 100, 120);

Once we have finalised our picture, we must send it back to the DrawSurface.

SG1.DrawSurface = ds;

To rotate the graphic, we call the SGrotate() function for the first time, and then use the standard setTimeout method to provide animation.

SGrotate();

function SGrotate() {
SG1.rotate(0,0,5);
setTimeout('SGrotate()',10);
}

And that is that. The whole Direct Animation scene is very large, and Direct Animation is capable of some very impressive effects. Check out Microsoft's web pages on it, and related topics, and start bringing those web pages into the 21st Century.

As a bonus for managing to read this article, you may have my FourCorners program, which uses the SGC as an 'advanced' mouse pointer.

<HTML>
<HEAD>
<TITLE>Four Corners</TITLE>
<STYLE>
.pointer {position:absolute;width:122;height:122}
</STYLE>
<SCRIPT>
oa=new Array(0,0,0,0);
px=new Array();
py=new Array();
pxs=new Array();
pys=new Array();
rtd=180/(Math.PI);
noinit=false;
bch=0;
bcw=0;


function init() {
pointer=new Array(Pointer1,Pointer2,Pointer3,Pointer4);
bcw=document.body.clientWidth;
bch=document.body.clientHeight;
px[0]=0;
py[0]=0;
px[1]=bcw;
py[1]=0;
px[2]=0;
py[2]=bch;
px[3]=bcw;
py[3]=bch;
pxs[0]=-1;
pys[0]=-1;
pxs[1]=1;
pys[1]=-1;
pxs[2]=-1;
pys[2]=1;
pxs[3]=1;
pys[3]=1;
noinit=true;
}

function rotatepointer() {
if (noinit) {
ex=event.clientX;
ey=event.clientY;
for (i=0;i<4;i++) {
na=Math.atan2(ex-px[i]+pxs[i]*61,ey-py[i]+pys[i]*61)*rtd;
pointer[i].rotate(0,0,oa[i]-na);
oa[i]=na;
}
}
}
</SCRIPT>
</HEAD>
<BODY onmousemove="rotatepointer();" onload="init();">

<OBJECT ID="Pointer1" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" CLASS="pointer" STYLE="top:0;left:0">
<PARAM NAME="Line0001" VALUE="setFillColor(255,255,0)">
<PARAM NAME="Line0002" VALUE="Polygon(3, 0, 0, 10, 50, -10, 50, 0)">
<PARAM NAME="Line0003" VALUE="setFillColor(255,0,0)">
<PARAM NAME="Line0004" VALUE="Polygon(3, 10, 50, -10, 50, 0, 60, 0)">
</OBJECT>

<OBJECT ID="Pointer2" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" CLASS="pointer" STYLE="top:0;left:expression(bcw-122)">
<PARAM NAME="Line0001" VALUE="setFillColor(0,255,255)">
<PARAM NAME="Line0002" VALUE="Polygon(3, 0, 0, 10, 50, -10, 50, 0)">
<PARAM NAME="Line0003" VALUE="setFillColor(0,255,0)">
<PARAM NAME="Line0004" VALUE="Polygon(3, 10, 50, -10, 50, 0, 60, 0)">
</OBJECT>

<OBJECT ID="Pointer3" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" CLASS="pointer" STYLE="top:expression(bch-122);left:0">
<PARAM NAME="Line0001" VALUE="setFillColor(0,255,255)">
<PARAM NAME="Line0002" VALUE="Polygon(3, 0, 0, 10, 50, -10, 50, 0)">
<PARAM NAME="Line0003" VALUE="setFillColor(0,255,0)">
<PARAM NAME="Line0004" VALUE="Polygon(3, 10, 50, -10, 50, 0, 60, 0)">
</OBJECT>

<OBJECT ID="Pointer4" CLASSID="CLSID:369303C2-D7AC-11D0-89D5-00A0C90833E6" CLASS="pointer" STYLE="top:expression(bch-122);left:expression(bcw-122)">
<PARAM NAME="Line0001" VALUE="setFillColor(255,255,0)">
<PARAM NAME="Line0002" VALUE="Polygon(3, 0, 0, 10, 50, -10, 50, 0)">
<PARAM NAME="Line0003" VALUE="setFillColor(255,0,0)">
<PARAM NAME="Line0004" VALUE="Polygon(3, 10, 50, -10, 50, 0, 60, 0)">
</OBJECT>

</BODY>
</HTML>

To begin the fun, move the mouse pointer into the active document.

Jon Perry is a Freelance Author and Programmer from the UK.
Suits PonytailsPropheadsContact WDJDiscussWeb AudioSearch

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers