VML Q & A

As of December 2011, this topic has been archived. As a result, it is no longer actively maintained. For more information, see Archived Content. For information, recommendations, and guidance regarding the current version of Internet Explorer, see Internet Explorer Developer Center.

Andrew Fiore and Rafael M. Muñoz
Microsoft Corporation

November 6, 2000

Lately, the Web Team Talking has received a lot of mail about Vector Markup Language (VML). While looking for answers, they found Andrew Fiore, an intern with Microsoft Research. This month, we depart from the usual format as Andrew steps through several VML issues, and provides links to additional information. Your regularly scheduled Web Team Talking will be back next month.

Contents

How Do I Create Arbitrary Paths in VML?
Coordinate Systems
Path Notation
Finally, a Cool Trick
How Do I Integrate Text into My Vector Markup Language Drawings on a Web Page?
What If I Want More Control over My Text?
A Couple of Notes About VML

The Web Team in Short

How Do I Create Arbitrary Paths in VML?

A path in Vector Markup Language (VML) comprises a series of coordinates and instructions for connecting them with lines and curves. Paths must be within shape objects to be displayed. You may define a path by adding a v="[your path here]" property inside the opening shape tag or by placing a <v:path> object between the <v:shape> and </v:shape> tags.

Coordinate Systems

The shape object defines the coordinate system in which its path is drawn. By default, the coordinate system's origin (0, 0) is at the upper left-hand corner of the shape object's space on the page, as described by the style attributes left and top. The size of the coordinate system that VML creates by default often seems arbitrary, so I recommend setting it explicitly. When you set the coordinate system size, it is mapped to the real, on-page dimensions of the shape object as described by the style attributes width and height, so you can control the size and detail of your coordinate system as you see fit. I find it helpful to make each unit in the coordinate system equivalent to an on-screen pixel:

<v:shape
style="width: 300px; height: 300px; left: 10px; top: 10px" coordsize="300,300">
[...]
</v:shape>

This one-to-one correspondence between space-object units and screen pixels gives you the greatest control over how your graphics look on screen. Purists will gripe that this introduces a dependence on screen resolution, which will spell bad news for users with very high-resolution screens. However, as long as Web pages include bitmapped images, such as GIFs, JPEGs, and PNGs, resolution dependence isn't going away. Ideally, you should design your vector graphics without assuming anything about the resolution or size of your user's screen; in the real world, it can be good to optimize also for the most commen scenario—currently a screen with a low enough resolution that pixel-level control can make or break the clarity of your images.

If you want to be resolution-independent, though, set the width, height, left, and top attributes of your shape object with points instead of pixels (e.g., "300pt" instead of "300px"). An inch contains 72 points no matter what the resolution of the monitor, whereas the number of pixels in an inch varies depending on the screen's settings. (Typical values range from 96 pixels per inch for common resolutions, to more than 150 pixels per inch for high-resolution displays.)

If you need more precise positioning in your vector drawing, you can specify a coordinate space that is finer than the pixel grid. For example,

<v:shape
style="width: 100px; height: 100px; left: 10px; top: 10px" coordsize="300,300">
[...]
</v:shape>

produces a coordinate system of higher resolution than the screen region in which it is displayed. In this case, a 10-pixel line on the screen would have a length of 30 in the coordinate space. This extra resolution can be useful if you're making graphs or other detailed graphics that might be printed on a high-quality printer or otherwise blown up so that the small details are easier to see. However, it introduces a problem with on-screen viewing. Suppose you make a line of length 28. Since there are three coordinate space units per pixel, lines of length 27 and 30 map directly to 9-pixel and 10-pixel lines, but there's no intuitive way to display a third of a pixel for a line of length 28.

It can be hard to gauge how complex graphics in high-resolution coordinate systems will display on a lower-resolution monitor, and the results can be aesthetically displeasing. Again, purists will say creators of vector graphics shouldn't worry about pixel-level appearance, but the Web designer in me says that we should consider it.

If you're drawing a simple shape, another option is to use a coordinate system with a much lower resolution than that of your monitor. The argument for this is simplicity. Suppose you want to draw a line at a 45-degree downward angle. You could do this.

This code sets up a 200x200-pixel space with a 200x200 coordinate system inside.

But using a 200x200 system for such a simple task seems too complicated. What about this?

This code sets up the same 200x200-pixel space, but the coordinate system is only 1x1, because that's all we need to draw lines vertically, horizontally, or at a 45-degree angle.

Path Notation

You're probably wondering about the notation in the path="..." attribute. That's what tells VML exactly how to draw the path; the letters represent commands, and the ordered pairs are the parameters for those commands. In the example above,

path="m 0,0 l 200,200 e"

means:

m 0,0: Move to the point (0, 0).
l 200,200: Draw a line from the current position to (200, 200). (That's an L, not a one.)
e: End drawing.

Another example:

path="m 0,0 l 0,200, 200,0 x e"

means:

m 0,0:  Move to the point (0, 0).
l 0,200, 200,0: Draw a line from the current position to (0, 200) and from there to (200, 0).
x: Close the shape by drawing a line from the current position to the starting position.
e: End drawing.

This draws a right triangle. After the vertical side and the hypotenuse have been drawn, the x command closes the shape by drawing the horizontal side.

You're not just limited to straight lines, either. Look at the path documentation from the World Wide Web Consortium (W3C) VML specification for a list of all the commands (such as m, l, x, and e) that you can use in constructing a VML path.

Path descriptions such as these can go in two different places in a VML document. The simpler alternative is to set them as path attributes within <v:shape> tags, as I did above. However, you can also add a <v:path> tag inside your <v:shape> and </v:shape> tags. Remember that the <v:path> tag overrides the path attribute for the shape object. Here's what that syntax looks like:

<v:shape style="width: 200px; height: 200px; left: 10px; top: 10px" coordsize="1,1">
   <v:path v="m 0,0 l 1,1 e">
</v:shape>

This draws the same 45-degree line as my example above.

Finally, a Cool Trick

You can achieve some interesting effects by changing the coordinate space in script. If, for example, you make a shape with coordsize="200,200", then change the coordsize to (100, 100), the size of whatever you've drawn in the shape will double horizontally and vertically. Assuming you've set the ID property of your shape to myShape, the Jscript®; to change the coordinate space is simple:

myShape.coordsize = "100,100";

or:

myShape.coordsize.x = 100;
myShape.coordsize.y = 100;

Note that when the coordsize is smaller, the image is bigger. That's because each unit will be larger in a 100x100 coordinate space than in a 200x200 coordinate space over the same screen area. If you have a line that's 20 units long in 200x200 space, it'll be twice as long in 100x100 space because the units are twice the size.

How Do I Integrate Text into My Vector Markup Language Drawings on a Web Page?

VML provides two mechanisms to display text. They work in similar ways, but their effects are quite different. The TextBox object provides a space for normal HTML text formatted however you want; the TextPath object, on the other hand, converts your text to vector graphics from the font's outlines, and then displays it like any other vector-based VML element.

For most purposes, the TextBox object is easier to use and displays more cleanly. This VML tag (written as <v:textbox>) allows you to fill a rectangular space defined by a shape tag (<v:shape>) with HTML-formatted text. You can specify the size of the rectangle that the text will fill by setting the cascading style sheet (CSS) width and height attributes for the <v:shape> tag. Although shape tags can have "path" attributes that specify the lines that compose the shape, paths have no impact on how text boxes flow their contents. Only the CSS width and height attributes determine the space for the text to fill.

Using the TextBox object to display your text makes it easy to style the text however you want, since you can use simple HTML. You can also position the text box wherever you want by using the usual top and left attributes of the shape object's style property. (See the MSDN Online section on the style object for more information.)

Here's a basic example, first with explicit definitions of the elements inside the <BODY> tag:

   <v:shape style="position: relative; width: 100px; height: 100px">
      <v:textbox>
         <FONT SIZE="1" FACE="Arial">
         a b c d e f g h i j k l m n o p q r s t u v w x y z a 
         b c d e f g h i j k l m n o p q r s t u v w x y z a b 
         c d e f g h i j k l m n o p q r s t u v w x y z a b c 
         d e f g h i j k l m n o p q r s t u v w x y z a b c d 
         e f g h i j k l m n o p q r s t u v w x y z a b
         </FONT>
      </v:textbox>
   </v:shape>

View a sample page with this code.

As you can see, the text fills a 100-pixel square. If there is too much text to fit in the square, as is the case here, the block of text is truncated at the bottom. Changing the height of the shape tag to "200px" reveals the rest of the text, as you can see in the revised sample.

To specify the same text box in script instead of explicitly in your HTML takes a little more work, but you get the same result. Here's the JScript that does it:

   <SCRIPT LANGUAGE="JScript">

   // Since this function refers to the document.body object,
   // it must be called after the body tag in the HTML document
   // has been processed. Thus, we call it from the onload event
   // on the body object.

   function makeTextBox() {

      // Create the shape object.
      var shapeObj = document.createElement("v:shape");
      shapeObj.style.position = "relative";
      shapeObj.style.width = "100px";
      shapeObj.style.height = "100px";

      // Add the shape object to the document.
      document.body.appendChild(shapeObj);

      // Create the TextBox object.
      var textBoxObj = document.createElement("v:textbox");

      // Create the font tag to format the text box's text.
      var fontObj = document.createElement("font");
      fontObj.face = "Arial";
      fontObj.size = "1";

      // Specify what text will appear within the font object.
      fontObj.innerHTML = "a b c d e f g h i j k l m n o p q r s 
      t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w 
      x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a 
      b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e 
      f g h i j k l m n o p q r s t u v w x y z a b";

      // Add the font object to the text box.
      textBoxObj.appendChild(fontObj);

      // Add the text box to the shape object.
      shapeObj.appendChild(textBoxObj);
   }

   </SCRIPT>

What If I Want More Control over My Text?

Use the TextPath object. The TextBox object provides you with a container for putting HTML text in your VML. The TextPath object allows you to treat your text more like a vector graphic and fine-tune its visual properties. Unfortunately, the implementation of VML in Internet Explorer 5 and 5.5 does not render TextPath text nicely at small sizes. For small, readable text, you're almost always better off with a TextBox object. For larger text and special effects, though, the TextPath object can prove quite powerful.

TextPath objects take a little more work than text boxes to set up, but the results can be worth the trouble. A <v:shape> object is still the container for the text, but its shape is defined by a combination of attributes that allow more precise control than CSS size attributes alone can provide, including the path of the shape, the fill attribute, the stroke attribute, and several optional tags such as <v:extrusion>, which gives the text (or any other shape) a three-dimensional look.

Let's step through an example with text along a straight line. We'll start with the code:

    <v:shape style="position: absolute; top: 25px; left: 5px;
       width: 300px; height: 300px; antialias: true"
       coordsize="300,300">
      <v:path textpathok="True" v="m 0,0 l 300,200" />
      <v:fill on="True" color="#999999"/>
      <v:stroke on="false" />
      <v:textpath
         on="True"
         fitpath="true"
         string="Where do you want to go today?"
         style="font:normal normal bold 12pt Arial" />
   </v:shape>

If you'd like, you can take a look at the sample this code produces.

As with a TextBox object, the <v:shape> tag contains the text object—but in a TextPath object, the CSS WIDTH, HEIGHT, TOP, and LEFT positions define only a space in which the text will be drawn along a path. The text will not fill the whole region as it would with a TextBox. To determine how the text will flow, you must attach a path object (<v:path>) to the shape object. Please see the VML path introduction for information on drawing paths. Note that the textpathok property of the path must be set to "True" for the text to be displayed on the path.

Usually, the <v:fill> and <v:stroke> tags inside a shape object define how the line and fill of the path itself will be displayed. When you add a TextPath to the shape object, however, the fill and stroke tags take on a different meaning. The <v:stroke> tag determines how the outline of the text will be displayed and colored. In this example, I turned it off. The <v:fill> tag determines how the interior of each character will be displayed. Here, I turned the fill on and set the color to a medium gray. (You can use color names, such as "red" and "blue", or the hexadecimal RGB specifications, as I've done here.)

No matter how you set the <v:fill> and <v:stroke> tags, your TextPath text's font and size will not look exactly the same as they would in other Windows applications. This is because the VML renderer draws the characters as vector graphics based on their mathematically defined outlines rather than calling standard system routines to display type. In my experience, especially at smaller sizes, using a fill but not a stroke makes characters slightly too thin, but using a fill with a stroke makes them too fat. Using only a stroke produces only outlines.

The TextPath object itself must (rather unintuitively) be turned on explicitly by setting on="True". The text you want to display goes in the string property, and the style property lets you format the text with normal CSS font-styling attributes. See the MSDN Online CSS font documentation for more information on the five-part font specification I used here.

You may have noticed when viewing the sample that the font looks a lot bigger than 12 points. You're absolutely right: Setting fitpath="true" in the TextPath object scales the text so that it is exactly long enough to cover the full length of the path. In this case, "Where do you want to go today?" in 12-point Arial Bold isn't long enough to cover the length of the line, so the VML renderer automatically increases the font size until the string is long enough. You can also view the sample without the fitpath="true" attribute set.

Finally, if you want good-looking text on a path, you need to use VML's built-in antialiasing. (Antialiasing smooths the edges of graphics on the screen by softening the transition along high-contrast lines with a few pixels of intermediate shades.) How to do it? Simply set antialias: true in the style property of the <v:shape> tag, as I've done above.

You can also create text in script on a path, but because it requires more properties to be set than it would in a text box, the code can get messy. If you're interested, though, here is an example of text on a path drawn in script. Take a look, try pointing at the text to see the path drawn in red. If you're curious, view the source to see how it is done.

A Couple of Notes About VML

To see VML objects in a Web browser, you must have Internet Explorer version 5 or higher. Internet Explorer 5.5 includes an improved VML renderer that fixes some bugs present in Internet Explorer 5, so if you notice anomalies in your VML elements, try upgrading your browser to Internet Explorer 5.5.

VML is a behavior in Internet Explorer, so Web pages with VML require two extra bits of code to allow the browser to display them properly. First, since VML is an XML schema, you must include a reference to the XML namespace in the HTML tag at the start of your document:

<HTML xmlns:v="urn:schemas-microsoft-com:vml">

Also, inside the <HEAD> and </HEAD> tags, you must add a style tag that tells the browser how to identify VML tags:

<HEAD>
<TITLE>Your title here</TITLE>
<STYLE>
v\:* { behavior: url(#default#VML); }
</STYLE>
</HEAD>

The Web Team in Short

Q: Narinder Pal Singh wants to send data entered in a form to an e-mail address.

A: Refer to Forms Overview, specifically the Submitting Forms topic.

Q: Boris Zhilin wants to know more about the blank window or frame problem when viewing a Portable Document Format (.pdf) file in Internet Explorer.

A: See Knowledge Base article Q177321, Adobe Acrobat .pdf Files Appear as a Blank Window or Frame.

Q: John Ridick notices that he is not seeing a border around an empty cell in a table.

A: Empty cell = no cell, so an empty cell is not rendered; to show borders, place a non-breaking space (&nbsp) in the cell.

Q: Howard Villard wants the Visual Basic® Scripting Edition (VBScript) equivalent syntax for the try…catch statement in JScript.

A: The VBScript equivalent of the JScript try…catch…finally Statement block is the On Error Statement.

Q: Liz Tedge wants to add a slider control to an ASP page and update a database when the value changes.

A: Refer to the slider behavior and its onchange event; also see the DHTML Dude's article Slip Slidin'.

Q: Naeem Afzal wants to get started building Web pages, and wants to know where to begin.

A: We tend to forget the new folks sometimes. Naeem, for a good tool check out Frontpage 2000; for an excellent article on some basics, see HTML for Beginners.

Andrew Fiore is an intern in the Microsoft Research Collaboration and Multimedia group, where he has been prototyping novel interfaces for finding and reading Usenet newsgroups. When not at Microsoft, Andrew studies at Cornell University in Ithaca, NY.


The Web Team

Heidi Housten is on the MSDN Architectural Samples team. She came to MSDN from the Internet Client team at Microsoft Developer Support. She is convinced that her 14 years of living and working in England were just preparation for the gray and drizzle of Seattle.

Rafael M. Muñoz, when not playing or coaching his favorite pastime (volleyball), provides technical assistance as a full-time developer support engineer for Microsoft Developer Support.

Thomas Moran, when not struggling to maintain some semblance of sanity (working with Rafael certainly doesn't help), toils with a prodigious team that creates articles and other content from Microsoft's Developer Support.

Kusuma Vellanki is one of the few people who like winters in Washington state more than summers. When not working as a Developer Support Engineer for the Internet Client team, she can be found torpedoing out of control down the ski slopes.


  
Show: