INFO 424 SCHEDULE

Lab 1: Olympic medals

continued...

a

 

Phase 11: Put the data in XML and fix the info box

This phase is a bit of tidying up loose ends - and a chance to practice some of what you've learned.

You've just automated the process of drawing the circles, but now there is data embedded within the code (position, size and color of the circles) that should be pulled out into the XML data file where it belongs. And now that the circles are being drawn dynamically, they're ending up on top of the infobox and obscuring it.

Step 4: Modify the XML file

Here's a chance to exercise your basic XML knowledge again.

Your existing XML structure looks like this:

<countries>
   <country id=''>
      <year id=''>
         <totalMedals></totalMedals>
         <goldMedals></goldMedals>
         <silverMedals></silverMedals>
         <bronzeMedals></bronzeMedals>
      </year>
   </country>
</countries>

You need to incorporate this information:

country x y radius color
Canada 124.55 157.8 26 0x4D8390
Japan 814.55 225.80 31 0x979D6D

To do this, think about the fact that the radius depends upon 2 conditions: which country and year it is, while the position (x & y) depends upon 3 conditions: which country, which year, AND which view you're in (geographic or by ranking). The color only depends upon 1 condition: which country it is.

a. Write an expanded XML structure that accomodates this new info. You can jot it on paper or use a text editor Don't look at my answer yet, the point is to give yourself a little practice in thinking about how to represent something in XML.

b. Then compare it with what I've come up with (this is only one answer, yours may be different and still work). If you understand why this works, then good, move on. If you don't, spend some time getting your head around it before moving on:

<countries>
   <country id='' color=''>
      <year id=''>
         <totalMedals></totalMedals>
         <goldMedals></goldMedals>
         <silverMedals></silverMedals>
         <bronzeMedals></bronzeMedals>
         <ranking>
            <x></x>
            <y></y>
         </ranking>
         <geographic>
            <x></x>
            <y></y>
         </geographic>
         <radius></radius>

      </year>
   </country>
</countries>

I've done the tedious work of adding this info to the file for you (no problem, don't mention it, really, it was my pleasure).

c. Download the file

Note that this file has some new information, but it hasn't changed the old information. So it should work with your existing code.

d. Open your 'MedalCopy_10.fla' file and save it as 'MedalCopy_11.fla'. Change the name of the xml file in your existing code to the new name ("medalXML_2.xml")

e. Test your application to be sure it works. Nothing should have changed (those circles that you created with ActionScript should still be sitting there on top of the ones you put on the stage).

f. [The x,y coordinate values I use in the XML file assume that your stage is 958 px wide and 467px high - make sure that these are the dimensions of your stage or the positions will be wrong. Right click on or near the stage and select 'document properties' to bring up the dialog box where you can check/change these values]

STEP 5: Pull values from the new file

This next series of steps is all about changing hard-coded code into dynamic code. In this case, turning the hard-coded instructions for drawing the two Canada circle and the Japan into generic instructions that can make a circle for every country included in your XML file.

Right now the code for drawing the circles runs as soon as the application loads. You're going to modify the circle-drawing code so that it pulls data from the XML file, so you need to be sure the XML file has been loaded and is available. To do that...

a. Move the code for drawing the circles (starting with 'japanCircle_graphics... and ending with stageAddChild(canadaCircle') into the 'loadedCompleteHandler' function (after the line that populates the 'medalXML' variable).

b. Test your code to be sure it still works. It would be a good idea to make a backup at this point so that if you get stuck later you can start over with this version.

Now you're ready to pull values from the XML file

c. Go to the first line of code that has a hard-coded value. That's this one:

japanCircle.graphics.beginFill(0x979D6D);

The color is now defined in the XML file, so let's start by replacing that reference.

You're wanting to find the element that has 'japan' as the 'id' attribute value and find out what the value of the 'color' attribute is.

That reference looks like this:

medalXML.country.(@id=='Japan').@color)

d. Replace '0x979D6D' with the above reference and test your code. It should look the same.

e. Now go to this line:

japanCircle.graphics.drawCircle(0,0,31);

...and replace '31' with a reference to the xml object that finds the country with id 'Japan' and looks for the year with id '2008' then gets the radius value. It will be very similar in structure to the references you wrote to get the number of medals:

medalXML.country.(@id==countryName).year.(@id==currentYear).totalMedals

f. Test this to be sure everything still looks the same.

g. Now replace the numbers in the following 2 lines with references to the XML:

japanCircle.x = 814.55;
japanCircle.y = 225.80;

Now all of the data for drawing the japan circle is being pulled from the XML file. But you would have to do the same for the Canada circle and any additional circles you added so go to the next step...

Step 6: Loop through the XML file

Let's back up. The ultimate goal is to do is draw a circle for each country record in your XML file.

As a reminder, the steps for drawing each circle go like this:

  1. Create a sprite
  2. Use the sprite's 'graphic' object to create a circle that is the correct size, color and position (get the size, color and position info from the XML file)
  3. Add a label with the name of the country (get the name from the XML file)
  4. Add the sprite to the stage
  5. Repeat these steps for the next circle

You've seen how to do almost all of these things in code - how to create a sprite, how to create a shape, how to pull data from the XML file, how to add the sprite to the stage.

But you haven't learned how to loop through an XML file. This code module shows you how.

a. When you run this code, you'll see a list of book titles. Notice that there is a commented line that will create a list of book authors. Now comment both of those lines and Modify the code so that it displays a list of book ids:

book ID list

Now go back to MedalCopy_11.fla and look at that code inside the 'loadedCompleteHandler' function. The next step is to replace the two chunks of code that draw the two circles with one chunk of code that loops through the XML object and creates a circle for each country.

b. Start by pasting the 'for each' loop from the code module at the beginning of the function (just after line that populates 'medalXML').

c. Preserve the 'trace' line and remove the other lines inside the loop.

Inside the parentheses is this:

var book:XML in myXML.item

It says "create a variable called 'book' which will hold an XML object and fill it with an 'item' element from the 'myXML' object"

d. Rename the variable 'currentCountry' (it could be anything, but 'currentCountry' is more appropriate than 'book' for this purpose).

e. The xml object you want to pull data from is 'medalXML' so replace 'myXML' with this name.

f. In the trace statement, relace "book" with "currentCountry"

g. Now test your movie. You should get no error messages and you should see the complete "country" elements (which include all of their subelements) in the output panel.

Step 7: Draw a circle with each pass through the loop

Now you want to put the code that draws the circles inside the 'for each' loop. In this steps below, I'll walk you through this.

You currently have lines that draw the 'Japan' circle which pull data from the XML file and lines that draw the 'Canada' circle which are hard-coded.

a. Cut and paste all of the lines that draw the 'Japan' circle inside the 'for each' loop. Delete the lines that draw the 'Canada' circle.

b. The references in this code are still hard-coded to pull out the 'japan' data from medalXML. To make them generic, replace this:

medalXML.country.(@id=='Japan')

with this:

currentCountry

Be sure you understand what you just did. Rather than pulling data from medalXML, you've pulled data from the currentCountry XML variable which only contains information for one country at a time, which is why you don't need to specify (@id=='Japan').

One last thing to change. Right now, you're populating the 'japanCircle' object with every loop. We'll change this to have a more generic name and to create a fresh variable with each loop.

c. Remove these 2 statements from your code:

var japanCircle:Sprite = new Sprite();
var canadaCircle:Sprite = new Sprite();

d. Write this statement as the first line of the 'for each' loop:

var countryCircle:Sprite = new Sprite();

e....and change all of the instances of 'japanCircle' to 'countryCircle'

If you run your code now, you'll get an error message because of the references to 'japanCircle' and 'canadaCircle' in the references to the textField objects. So we need to make those generic too...

f. There are a series of lines that start with "CanadaTextField" and a series that start with "JapanTextField". Cut them and paste them into "loadCompletedHandler", inside the 'for each' loop after all of the other code.

g. Delete all the 'Canada' lines and replace all of the 'JapanTextField' references with 'circleTextField'.

h. Now delete these 2 lines:

var CanadaTextField:TextField = new TextField();
var JapanTextField:TextField = new TextField();

i. ...and write a line to create a TextField variable called 'countryTextField' at the beginning of the 'for each' loop (next to the other 'var' line).

j. Now go to this line:

circleTextField.text = "Japan";

...and replace 'Japan' with a reference to the XML object (you should be able to figure out how).

If you test your code now, you'll still get errors because of these lines of code:

CanadaTextField.setTextFormat(circleFormat);
JapanTextField.setTextFormat(circleFormat);
canadaCircle.addChild(CanadaTextField);
japanCircle.addChild(JapanTextField);

k...so cut them and paste them at the end of the 'for each' loop. Delete the Canada ones and replace the Japan ones with the appropriate generic references.

l. Test your code. If something isn't right, try to figure it out using the debugger or trace statements (here's that video showing how to do that). If you still can't get it to work, look at my code below:

Step 8: Add event listeners to the sprites so they trigger the infoBox

Now your circles appear, but they don't allow any interaction.

a. In your code, you add 2 event listeners to the Japan button and 2 to the Canada button. Comment out these 4 lines.

b. You want to add these 2 event listeners to the circles you've created so, within your 'for each' loop, add the two event listeners to the 'countryCircle' object.

c. The 'showInfo' box function identifies each circle by name. So add a line that will replace the generic name that Flash supplies with the name of the country:

countryCircle.name = currentCountry.@id;

d. And you can simplify that code that parses the circle names to pull out the name of the country. Change it from this:

countryName = theEvent.target.substr(0,(theEvent.target.name.length-10));

to this:

countryName = theEvent.target.name;

e. One last thing. The circles that you originally drew and pasted onto the stage are now getting in the way. So delete them by dragging the 'Japan text' and 'Canada text' layers into the trash.

f. Test your code. The info box should appear. But there are 2 problems. 1. The box will be behind your circles, and 2. When you move your mouse over the text, the data will disappear and the name will say something like "instance33"

Step 9: Fix the problems

One way to get the info box to appear in front of the circles, is to add it to the stage after the circles are added:

a. To achieve this, move the line that adds the infoBox (stage.addChild(infoBox);) to just after the 'for each' loop. [NOTE: you may have just 'addChild(infoBox);' in this line, if that's the case, add the 'stage' to the beginning when you move it]

b. Test your code. The info box should now be in front of the circles.

c. The reason you see something like 'instance33' when you move your mouse over the text, is because that is the default name of the textField object. That object's parent is the circle. To get around this, go to the 'showInfoBox' function and add the following lines after the line that sets the countryName:

if (countryName.substr(0,8)=="instance"){
countryName = theEvent.target.parent.name;
}

This is checking to see if the object you're hovering over has a name that starts with 'instance' and if it does, it uses the name of it's parent to populate the countryName variable.

d. Run the code. You should now be able to hover over either the circle or the text and get the correct data in the infoBox. (Of course the tabs and slider no longer work since you deleted the circles in the timeline, but you'll be fixing that soon).

FIRST FINAL PRODUCT: MedalCopy_11.fla

Think back on what you've done in this phase. You pulled data about the circles (their color, size and position) out of your code and put it in the XML file (you had to modify its structure to do that). Then you modified the code so that it looped through the XML file and created a circle for each country. Finally, you moved the code where the info box was added to make it always appear in front of the circles.

The next phase is a major one - you'll learn to create the tweens in ActionScript, but first, solidfy what you've learned by reading the SUMMARY, then do the EXERCISE

SUMMARY

referencing XML objects

looping through elements in an XML object

for each (var theCountry:XML in medalXML.country){

}

changing the display order

 

EXERCISE: Draw a bar chart with ActionScript

a. Download this .fla file. It contains only comments

b. Download this XML file.

b. Write code based on the comments. This code will closely follow elements of the the code in MedalCopy_11.fla - but much simpler (which isn't to say that this task will be easy - the idea is to help you understand the code better by working with it).

c. When you test your code, it should look like this:

d. Try changing the variables that determine where the bars begin and how thick they are, then test your code to see the results.

e. If you get stuck, you can look at my code.

SECOND FINAL PRODUCT: xmlExercise.fla