Michael Wallent
Lead Program Manager, DHTML
Microsoft Corporation
June 7, 1999
The following article was originally published in the MSDN Online Voices "DHTML Dude" column.
The first time I really got excited about software and computers was back in the fall of 1981. (I was 12.) My parents had brought me on vacation to Baltimore. Little geek that I was, I wanted to go to Maryland Science Center . Having just come from the Smithsonian National Air and Space Museum , with its Apollo capsule, I was pretty excited about space and technology.
As lame as this sounds, in their Moon and Space display area, they had an Atari Lunar Lander game . This game allows the player to land a lunar module onto the surface of the moon (somewhat intuitive from the name of the game, isn't it?). I thought it was the coolest thing ever. It even prompted me to want to write my own version on my then state-of-the-art home computer, the snazzy TI-99 4A . Alas, the TI-99 4A didn't have vector graphics, which made it hard to write a version of Lunar Lander in "Extended Basic" with "Sprites," but it was still pretty cool. After all, it's what got me started in this business anyway. A couple of years ago, I finally found an old Lunar Lander machine at John's Jukes in Vancouver BC, and now have it in my own home. (For fun sometime, try bringing a video game across the US-Canadian border. Customs agents aren't too suspicious.)
What could this possibly have to do with the Internet? One of the newest features for Internet Explorer 5 is Vector Markup Language (VML) -- a vector graphics package.
There are many interesting VML samples and documentation at http://msdn.microsoft.com/standards/vml/ref/. However, I'd like to go through a sample that's a little more complex, and uses a combination of XML data binding, VML, and some new document object model (DOM) Level 1 support to produce a stock graphing component.
Check out the sample.
The underlying data is coming from an XML file with the following schema:
<day> <symbol>AADV</symbol> <quotedate>1/7/98</quotedate> <quotelow>82</quotelow> <quotehigh>85</quotehigh> <quoteclose>84</quoteclose> </day>
Instead of using the XML DOM to iterate through the data, I'm using Active Data Objects (ADO). In this case, ADO is providing an abstraction over the data so that no matter what data source object I use, my underlying code will always be the same. For example, if I were using the Tabular Data Control (TDC) or Remote Data Services (RDS), the methodology for iterating through the dataset and getting name/value pairs would be the same.
Here's the declaration of the XML data source:
<XML id="Stock" src="stockdata.xml"> </XML>
To then get an ADO recordset from this data, I do the following:
rs = Stock.recordset;
Many times in this sample, I iterate through all the records (each DAY is considered to be a record).
count = rs.recordcount; rs.moveFirst(); // get min/max for scaling calculation for (i=0; i<count; i++) { cMax = rs.fields("quotehigh").value; tMax = Math.max(cMax, tMax); cMin = rs.fields("quotelow").value; tMin = Math.min(cMin, tMin); rs.movenext(); }
The recordset has a notion of a "cursor" or a pointer to the current location in the recordset. The moveFirst() and movenext() methods are used to change the location of the cursor in the recordset. To get the values of a given record, the fields() method is used to get the field object. Important meta data about that field, as well as its current value is available at that point. For the example code above, I'm only interested in the value set for the field, so I'm only using the value property to get the at the data in the field.
Here's an outline of the method used to draw the graph:
Let's take a closer look at Step 1, how the containing <DIV> gets created.
pDiv = document.createElement("DIV"); pDiv.id = "Graph1"; pDiv.style.width = MaxWidth11; MarginLeft = MaxWidth * 0.05; pDiv.style.height = MaxHeight11; MarginTop = MaxHeight * 0.05; pDiv.style.border = "1px black solid"; pDiv.style.position = "absolute"; pDiv.style.top = 70; pDiv.style.left = 10; insertParent.insertBefore(pDiv, null);
The chain of events here is that the element is created, then properties are set, then the element is inserted into the document. The new element isn't in the main document until the insertBefore() call is made. As a side note, other elements can also be created and parented to an element not yet in the tree. For example, if I wanted to have the <DIV> contain an <IMG>, I could create it, and parent it to the new <DIV> before the <DIV> was inserted into the main document. This is especially helpful when creating new table rows, as you can create the row, and all the cells, before putting the new row into the document.
With Internet Explorer 4.0, if you wanted to insert new elements into a document, you had to insert the HTML content and use the innerHTML property or insertAdjacentHTML() method.The way to write the above code for Internet Explorer 4.0 would be:
insertParent.insertAdjacentHTML("BeforeEnd", "<DIV id='Graph1' style=" ' width: " + MaxWidth11 + ";" + "height: " + MaxHeight11 + ";" + "margin-left: " + (MaxWidth * 0.05) + ";" + "margin-top: " + (MaxHeight * 0.05) + ";" + "border: 1px black solid; top: 70; left: 10; position: absolute ' ");
Some may argue that this code is more compact, but it certainly is less clear. It's also much slower.
Another benefit of the new method of creating elements is that all elements can be created and inserted into the document in the same way. With the innerHTML and insertAdjacentHTML() methods, there were some types of elements that couldn't be inserted that way. For example, table rows and cells or elements in the head of the document couldn't be inserted via the old methods.
One method that is used frequently in the sample is createLineWithDOM(). Here's the code for that method:
function createLineWithDOM(p, color, width, fx, fy, tx, ty) { var l, d, i; l = document.createElement("v:line"); l.strokeweight = width+"pt"; l.strokecolor = color; l.from = fx + "px, " + fy + "px"; l.to = tx + "px, " + ty + "px"; p.insertBefore(l, null); }
Note how the basic outline of this method is the same -- element is created, its properties are set, and then it gets inserted into the document. VML shapes or HTML elements, they all get created and inserted the same way.
The goal for this sample is to show how rich, interactive, data-driven pages can be created. Bringing the sort of interactive applications that developers have been writing with Visual Basic® and C++ to the Web is now very possible. Remember, it's not just HTML, its Dynamic HTML.
Michael Wallent is Microsoft's group program manager for DHTML.