INFO 424 SCHEDULE

Olympic Medals, Phase 11 - More XML

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>

It contains the information that needs to go into the info box, but it doesn't yet contain the information used to draw the circles:

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. (You might find it helpful to create a tree diagram like I did in Medals Phase 9. 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.

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 Medals_10_draw.fla file and save it as "Medals_11_XMLtoo.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 - to make sure that these are the dimensions of your stage, 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 Canada circle and the Japan circle 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 (the code that starts with "japanCircle_graphics..." and ends 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 your backup 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);

You'll start by replacing that color code with a reference to the color code in the XML file.

That reference looks like this (it finds the country with an "id" attribute "Japan", then asks for the value of the "color" attribute):

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 that finds the country with id "Japan," then finds the year with the id "2008" and pulls out the radius value. It will be very similar in structure to the reference below, which you wrote earlier to get the number of medals (i.e. you can copy this line and then tweak it):

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 values in the XML file:

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: Learn about looping through an XML file

Let's back up. The ultimate goal is to do is draw a circle for each country in your XML file. The steps for doing so are as follows:

  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. Open the code module and test the code. You'll see a list of book titles.

b. Open the code panel and find the line that will create a list of book authors (it's preceeded by a double forward slash // to disable it. Remove these slashes and add slashes in front of the line that creates a list of book titles to disable it.

c. Run this new version to see that a list of authors appears.

d. Figure out how to modify the code so that it displays a list of book ids (the trick is that the ids are an attribute rather than an element):

book ID list

Now you know how to loop through an XML file. Next, you'll apply that knowledge to the medals app.

Step 7: Loop through the XML file

a. Go back to Medals_11_XMLtoo.fla and look at the code inside the loadedCompleteHandler function. Notice that there are two sections of code, each of which draws 1 circle. You will be replacing those two sections with a single section of code that loops through the XML object and creates a circle for each country.

b. Start by copying the "for each" loop from the code module (the loop starts with the line that begins "for each..." and ends with the closing curly bracket "}"), and pasting it at the beginning of the loadedCompleteHandler function (just after line that populates medalXML).

c. Preserve the "trace" line and remove the other two lines of code inside the loop.

Look at what is inside the parentheses following "for each":

for each (var book:XML in myXML.item){

It directs the code to "create a variable called 'book' which will hold an XML object, and populate it with an 'item' element from the myXML object"

d. Rename the variable from "book" to "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 and the elements you want to loop through are the "country" elements so replace "myXML.item" with "medalXML.country"

f. In the trace statement, replace "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 8: 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 of code that draw the Japan circle which pull data from the XML file and lines that draw the Canada circle that have hard-coded values.

a. Cut the lines that draw the Japan circle and paste them inside the for each loop (this includes the line that creates the japanCircle variable). 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 every instance of:

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

with:

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').

c. Run your code. It should work just as before.

d. To make the code more logical, replace every instance of the name 'japanCircle' with 'countryCircle'

There is a similar situation with the text field code.

e. Delete the lines that start with "CanadaTextField" and move the "JapanTextField" lines inside the for each loop as well (including the line that creates the JapanTextField variable.

f. To make the names more appropriate, replace all of the "JapanTextField" references with "countryTextField."

g. There is one hard-coded line that needs to be updated. It is the line that reads:

circleTextField.text = "Japan";

... figure out how to replace "Japan" with a reference to the XML object (HINT: think about what is in currentCountry and then figure out how to extract "Japan" from that).

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

 

******** SPOILER ALERT: The answer is below***********

 

 

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

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

a. Comment out the code which adds event listeners to the Japan button and the Canada button.

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, but the only name the circles have now is the one that Flash assigns. To give them names that you can then reference them by, add this line that will assign the name of the country:

countryCircle.name = currentCountry.@id;

d. This now allows you to simplify the code in the showInfoBox function 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 and Canada layers into the trash.

f. Test your code. The info box should appear. But there are 3 problems. 1. The info box will be behind your circles, 2. When you move your mouse over the text, the data will disappear and the name will say something like "instance33" and, 3. The tabs and slider no longer work since you deleted the circles in the timeline, (but you'll be fixing that in another lab).

Step 10: Fix the infobox 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: if your line currently reads "addChild(infoBox;", change it to "stage.addChild(infoBox);".

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 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 its 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.

Don't be alarmed if your animations are gone, that will be done in the next phase.

Please submit the xml file and fla file as a zip

FINAL PRODUCT: Medals_11_XMLtoo.zip

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){

}