Published: Wednesday, November 13, 2002
Real-time Animated Graphing using Flash MX, Part 2
By Pallav Nadhani
Read Part 1
In Part 1 we saw examined the basic architecture for FunkyCharts.
In this part we'll look specifically at the XML structure used to communicate plotting data from
the Web server to the FunkyCharts Flash movie, which runs on the client's computer.
The XML Structure
Recall that the FunkyChart flash file, which executes on the client's machine, communicates with the
Web server to obtain the data it needs to plot. This data is exchanged in an predefined XML format. An
example of this format is given below:
<graph bgcolor="E1F5FF" caption="Hits for the first half (in thousands)"
xaxisname="Month" yaxisname="Hits" yaxisminvalue="0" yaxismaxvalue="50">
<set name="Jan" value="20" color="3300FF" />
<set name="Feb" value="9" color="FF0000" />
<set name="Mar" value="7" color="009966" />
<set name ="Apr" value="40" color="FFCC00" />
<set name="May" value="23" color="CC0033" />
<set name="Jun" value="34" color="CCCC33" />
<set name="Jul" value="19" color="FF9900" />
</graph>
|
As you can see, the root element, <graph>, has a number of attributes worth discussing:
bgcolor - specifies the background color of the graph. The bgcolor value
is the hexidecimal value of a color without the # prefix.
caption - specifies the caption (heading) of the graph, which is displayed on the
top of the graph canvas.
xaxisname - specifies the x-axis caption of the graph
yaxisname - specifies the y-axis caption of the graph
yaxisminvalue - determines the y-axis lower limit value - i.e., the origin value for
y-axis. This is an optional value as we'll see later. If this value isn't provided to the graph, the
graph will automatically select the lowest value provided in the data to be the y-axis lower limit.
yaxismaxvalue - determines the y-axis upper limit value - i.e., the maximum value
for the y-axis. This is an optional value, in the same manner as the yaxisminvalue attribute
The <graph> node's attributes merely specify aesthetic settings.
The actual plotted data for the graph is contained within individual <set> elements,
which is a childnode of the root <graph> element. The attributes used to define
the data are:
name - The value displayed on the x-axis for the particular data point
value - The value displayed on the y-axis for the particular data point
color - The color in which this set of data will be displayed.
Now that we've looked at the format of the data exchanged between the Web server and the Flash movie,
let's look at the code needed in the Flash movie to actually render the graph from the XML data.
Creating the Flash Movie
Before we examine the actual creation of the graph, let's take a second to look at the various visual
elements of the graph, so that we know what we're working toward. The screenshot to the right shows
the output of a FunkyChart line graph with various pieces of the graph labeled by their attribute
name. That is, the caption up at the top, "Hits for the first half (in thousands)," has
a red box around it and a label "Graph Caption." Normally this red box and label wouldn't be present in
the output - it is included to indicate how the value of the caption attribute of the
<graph> node is rendered.
Now that we know what we are aiming for, start by creating a new Flash movie with the dimensions of
350 px (width) x 300 px (height). Set the fps (Frames per second) to 120. (We increase the fps to
increase the speed of animation.) Next, rename the default scene to "Graph". To rename a scene, go
to Modify > Scene, click the scene name twice and then rename it.
In the graph create a background that is a movie clip with a rectangle of size 350 x 300 px.
Place an instance of this movie in the main timeline and use ActionScript to change the color of this
movie clip by utilizing the color object in Flash. These things can be accomplished by performing the
following detailed steps:
- To create the movie clip, go to
Insert > New Symbol menu.
- In the pop-up dialog, enter the Name as
MCBg and select the Behaviour as Movie Clip.
- You'll be provided with a blank screen. In the default layer and frame provided, draw a rectangle
of size 350 x 300 px (using the rectangle drawing tool from the toolbox). Give the rectangle any color
which you wish to be initially set as the background, until the XML document has been loaded -
after the XML document has been loaded, we will change the color of this movie clip to the one
provided in the XML document.
- Now, get back to the main timeline i.e., the timeline of Scene Graph.
- Rename the default layer to Background
- On the frames of this layer, place the newly created movie clip to cover up the entire stage and
name its instance as
MCIBg - instance names in Flash are like ID's in JavaScript - each
object has an ID assigned to it to be accessible via the DOM. To place the movie clip on the timeline,
you'll have to drag and drop it from the Library (Window > Library or Ctrl + L) onto the
stage (stage in Flash means the working area) with the default keyframe selected. And to change the
instance name, select the movie clip placed on the stage, bring up the Properties window (
Window > Properties or Ctrl + F3) and enter MCIBg in the Instance Name field.
At this point we have the background setup that can be later altered via ActionScript. Next, we need to
look at the code needed for parsing the XML document that contains the data to plot.
Loading and Parsing the XML document
Macromedia Flash MX provides an excellent native XML Object to deal with XML data. Using this object,
one can load, send, and parse etc XML documents inside Flash. For our application, we just need to
load the XML data from the URL provided to the graph (using the OBJECT/EMBED method which
we had earlier seen), parse it and then use the parsed information to build the graph.
Specifically, to load XML data, perform the following steps:
- Create a new layer named
Labels. This layer is intended to contain keyframes with labels.
- Create three keyframes in this layer and name them as
LoadXML, LoadingXML and
ParseXML, respectively.
- Create another layer Actions and create another three keyframes in this layer also. This layer is
meant to contain all ActionScripts of the movie.
- Now, we need to show the user some splash/loading screen while the data is being fetched from the
server. So, to achieve this, create a new layer called "Loading Contents" and on the frames of this
layer, place anything which you want your users to see while the data is being loaded. The picture
until now should look something like:
Now, let's move on to render the ActionScript required for loading the XML data. First, we'll see the
ActionScript required to load the XML document. The ActionScript required to load the XML data is
contained in the frame LoadXML, so pop up the Actions Panel for this frame (right click
on it and select Actions) and enter in the following script:
XMLDoc = new XML();
XMLDoc.onLoad = fnloaded;
xmldocurl = _root.dataurl;
if (xmldocurl.length < 1) {
xmldocurl = "Data.xml";
}
XMLDoc.load(xmldocurl+"?curr="+getTimer());
function fnloaded() {
gotoAndPlay("ParseXML");
}
play();
|
The above ActionScript first initializes an instance of the XML document, storing it in the local variable
XMLDoc. We then instruct Flash that as soon as the XML document has been completely
downloaded in the movie, the function fnloaded should be invoked. Next, we get the path
of the XML document that has to be loaded. The path is passed to the movie by the page in which
this movie is embedded as we had earlier seen using the OBJECT/EMBED method. The
dataurl passed to the Flash movie from the ASP page in the format
FunkyCharts.swf?dataurl=Data.asp is now accessible in Flash via
_root.dataUrl.
The following if statement, which is optional, specifies that a default XML file should
be loaded in the event that no dataurl path has been provided.
We invoke the load method of the XML object to load the document. We append the
time at the end of the file name so that it is not cached.
The function fnloaded, which is invoked when the XML file is loaded,
simply sends the control to the ParseXML keyframe wherein the XML document will be parsed
to retrieve the information. Finally, the play() command keeps the movie playing,
which moves the Flash movie on to the next keyframe.
Recall that our next keyframe is
LoadingXML - the frame that is displayed until the XML document has been completely
downloaded by Flash. So, in the Actions Panel of this frame, we just ask Flash to keep on playing, by adding the
following one-line of ActionScript: play();.
When the play() function is called in the LoadingXML keyframe the control
is transferred to the keyframe ParseXML. In
this frame, we first check if the XML document has been successfully downloaded or not. If it hasn't
been downloaded, we send the control back to LoadingXML to display the loading Frames.
If it has been downloaded and it doesn't contain any errors, we continue with the parsing process by
invoking the custom function parseXML(); however, if there is an error in parsing the
XML file we transfer the control to a keyframe XMLError, which displays an
error message to the user stating that the XML received was malformed. The following ActionScript, which
should be placed in the ParseXML keyframe, accomplishes these tasks:
//If the document is loaded and it's not empty
if (XMLDoc.loaded and XMLDoc.hasChildNodes) {
//Check for errors in XML document
if (XMLDoc.status == 0) {
//If no errors present then parse it
parseXML();
} else {
//If errors present, show an error message
gotoAndPlay("XMLError");
}
} else {
// If the document has not been loaded, we just send
// the control a li'l back to waste some time
gotoAndPlay("LoadingXML");
}
|
The following function, parseXML helps in parsing the XML and retrieving the data from
the XML document. Parsing the XML document using the XML object in Flash is similar to the
XMLDocument() class in ASP.NET or the MSXML Parser in ASP. We have to traverse down the
tree using the methods and properties exposed by the XML object.
function parseXML() {
//This functions parses the XML Data passed to it.
//cldNodes array will contains the child nodes of
//the XML Doc passed to it.
cldnodes = new Array();
cldnodes = XMLDoc.childNodes;
num = 0;
dataset = new Array();
dataname = new Array();
datavalue = new Array();
datacolor = new Array();
for (j=0; j<=cldnodes.length; j++) {
if (cldnodes[j].nodeName.toUpperCase() == "GRAPH") {
bgcolor = cldnodes[j].attributes.bgcolor;
caption = cldnodes[j].attributes.caption;
xaxisname = cldnodes[j].attributes.xaxisname;
yaxisname = cldnodes[j].attributes.yaxisname;
yaxisminvalue = cldnodes[j].attributes.yaxisminvalue;
yaxismaxvalue = cldnodes[j].attributes.yaxismaxvalue;
dataset = cldnodes[j].childNodes;
for (k=0; k<=dataset.length; k++) {
if (dataset[k].nodeName == "set") {
num = num+1;
dataname[num] = dataset[k].attributes.name;
datavalue[num] = dataset[k].attributes.value;
datacolor[num] = dataset[k].attributes.color;
}
}
}
}
play();
}
|
The parseXML() function starts by creating an array to hold the childnodes of the XML
document. XMLDoc.childNodes returns a pointer to the root element of the XML document.
Next, we declare a variable num to store the count of the datasets passed to the movie
(via the XML document). We then iterate through the first level children of the XML Doc to search for
the <graph> element.
If the element is <graph> element, then we access the graph attributes. To access
the attributes we use the attributes collection in Flash.
First, we get the background color of the graph and store it in the variable bgcolor,
and then the caption and so on.
Next, we iterate through the data set. A check is made if the node name is set i.e., a
graph data set. If the element is <set> then we retrieve and collect the values.
Now, we need to make another frame in both the Actions and Labels layer. Name this frame as
setDefaults. This frame will calculate the default values for the variables whose values
were not supplied in the XML document. (For example, the bgcolor attribute in the
<graph> element is optional; the setDefault frame will provide a default
value for this attribute should it not be supplied.) Once you've created the setDefaults
frame, bring up the Actions panel for this frame and enter the following ActionScript:
// specify a default background color
if (bgcolor == null || bgcolor == undefined || bgcolor == "") {
bgcolor = "FFFFDD";
}
// calculate the max and min values in case the yaxisminvalue
// and yaxismax values are not supplied
intmin = Number(datavalue[1]);
intmax = Number(datavalue[1]);
for (i=2; i<=num; i++) {
if (Number(datavalue[i])Number(intmax)) {
intmax = Number(datavalue[i]);
}
}
if (yaxisminvalue == null || yaxisminvalue == undefined ||
yaxisminvalue == "" || Number(yaxisminvalue)>Number(intmin)) {
yaxisminvalue = Number(intmin);
}
if (yaxismaxvalue == null || yaxismaxvalue == undefined ||
yaxismaxvalue == "" || Number(yaxismaxvalue)
|
Now, that we have the defaults for the graph calculated and stored in variables, it's time to apply
them. First, we'll see how to create the graph canvas. We'll examine how to do this in
Part 3.
Read Part 3!