New Health Supplement Site in Development.
Talks have begun with a client to design a Web Site advertising a number of nutritional supplements. It will be heavy on images and information in order to be visually appealing to visitors.
synthetic-mind: Greenleaf Designs company blog
Talks have begun with a client to design a Web Site advertising a number of nutritional supplements. It will be heavy on images and information in order to be visually appealing to visitors.
A new website is being developed for an award-winning documentary filmmaker from the Ottawa area. A Flash micro site will first be created with a more feature-rich site to follow shortly after. Stay tuned, more to come in the future..
One other thing…I will not be touching on anything regarding CSS styling. You will notice in a couple of steps where HTML markup is outputted (the ‘add item’ form and the default index view) that I make use of classes. If you aren’t familiar enough with HTML and CSS to understand what is happening, educate yourself further as it is outside the scope of this tutorial. The main points I want to get across are : manipulating and reading XML using PHP [this tutorial] and reading XML and animating using the caurina Tweener class [Part 1 of this series].
Anyways, let’s dispense with the formalities and get this thing going!
STEP ONE – SETUP FOLDER STRUCTURE
First, we lay the groundwork for all of the steps in this tutorial. There will be five folders. The ‘images’ folder will hold, you guessed it, all images relating to this tutorial. The ‘XML’ will hold the ‘items.xml’ file which we will be working with. ‘js’ will contain any scripts being used. ‘flash’ will contain the complied .swf movie and finally ‘css’ will contain the stylesheet we will be using. That’s it, we’re now ready to dive into some coding.
STEP TWO – BEGINNING TO CODE THE INDEX PAGE
Alright, let’s start coding. The first section is by far the most complex area of the document, the code required to add a new item to our ‘items.xml’ file.
if($_POST['action'] == 'update_file') { $product = trim($_POST['product']); $filename = basename( $_FILES['uploadedfile']['name']); $price = trim($_POST['price']); $metric = trim($_POST['metric']); $description = trim($_POST['description']);
This first section loads up variables the results of our yet-to-be-coded ‘add items’ form. It makes use of PHP’s ‘$_POST function. This function contains information submitted from a form in name/value pairs. For example, if you had a text field named ‘product’ and the user entered ‘beans’, then the name/value pair would be product=beans. Notice that the ‘if’ statement tests to see if ‘action’ has a value of ‘update_file’. The ‘action’ variable is set to ‘update_file’ using a hidden input field in our yet-to-be-coded form. This logic is what instructs the ‘if’ statement that we are looking to update the XML file. The next few lines makes further use of the $_POST function by loading up variables with the data from the submitted form.
$errors = false; $err_msg = ""; $image_err = false; $target_path = "images/"; $target_path = $target_path . basename( $_FILES['uploadedfile']['name']);
Next, we create a variable to hold all of our error messages and set it to a blank string. This variable is a string which is populated with messages based on our field validation. As any field tested fails validation, the associated error message is concatenated to the string giving us a listing of errors. the ‘image_err’ is a boolean variable which is set to ‘false’. If a field fails validation, this variable is set to ‘true’ which will basically prevent the a new item being created based on another ‘if’ statement we will see shortly. In our yet-to-be-coded form, one of the fields is a file upload control to upload an image. This presents the user with a ‘browse’ button and enables the user to browse for a file on their hard drive. The last 2 lines seen here set the target path to ‘images/
if ($_FILES['uploadedfile']['type'] != "image/jpeg" || $_FILES['uploadedfile']['type'] != "image/gif" || $_FILES['uploadedfile']['type'] != "image/png") { $err_msg .= "\\nImage must be a .GIF, .JPG or .PNG"; $image_err = true; $errors = true; }
This is the first of our validation conditions. The ‘if’ statement tests to see if the file selected using the file upload control is either a .JPG, .GIF or a .PNG. If it fails this test, then the error message is concatenated to the ‘err_msg’ variable using .= notation. Then, two boolean variables are set to true.
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) { list($width, $height, $type, $attr) = getimagesize($target_path); if($width > 50 && $height > 50) { $err_msg .= "\\nImage must be no more than 50 x 50 pixels in size"; $image_err = true; $errors = true; } if($image_err == true) { unlink($target_path); } }
The next ‘if’ statement checks to ensure that the file designated by the file upload control is a valid upload file (meaning that it was uploaded via PHP’s HTTP POST upload mechanism). If the file is valid, it will be moved to the target path. Keep in mind that until the move_uploaded_file function is executed successfully, the file selected using the yet-to-be-coded form will NOT exist in the target path (the images folder). Next, a list is created which is populated by the results of the getimagesize() function. The getimagesize function is used to retrieve information about an image such as width, height, type etc. We will be using it to determine the images’ dimensions. For this tutorial, we want to ensure that the images are no larger than 50 x 50 pixels. As you can see in the next ‘if’ statement, we test to see that the width and height are no larger than 50 pixels. If they are, then again, an error message is concatenated to the err_msg variable, boolean variables are set to true and execution continues. The last line basically deletes the file using ‘unlink’ if the image_err boolean variable is set to true. For example, if the user used the file upload control to select, say, an .EXE file…the image validations would fail. The image_err boolean would be set to ‘true’ because of this, and the file would subsequently be deleted. Only valid image formats that are no larger than 50 x 50 pixels will be kept..exactly what we want. I’m going to skip the next few lines because they are all basically the same. Using the strlen function, which tests the length of a string, the other fields are validated to make sure they are at least 1 character long. Also, the ‘price’ field is tested to make sure it is a numeric value using the ‘is_numeric’ function.
if($errors == false) { $items = array(); $items [] = array( 'name' => $product, 'id' => rand(0, 1500), 'image' => $filename, 'price' => $price, 'metric' => $metric, 'description' => $description );
This ‘if’ statement check to see if the ‘errors’ boolean variable is set to ‘false’. If all field validations checked out, this will be the case. In the event that the ‘errors’ boolean variable is indeed ‘false’, then a new array is created and populated with all of the necessary information to create a new item in our XML file. Notice the addition of the ‘id’ item. Because we are not using a database to save our information, we don’t have the benefit of a primary key to provide unique identifiers to our data. If the XML file were generated from database data, then this ‘id’ field could be set to some sort of primary key, but in this case I’m making the assumption that database data isn’t entering into the equation so keys aren’t an option. To help out with this, i’m creating an ‘id’ value which will be a random number between 1 and 1500. You could make the range larger but in the case of this relatively small tutorial, I figured an upper-limit of 1500 would suffice. This isn’t as fool-proof as a primary key, but it helps us slightly.
$xml = new SimpleXMLElement('XML/items.xml', NULL, TRUE); foreach( $items as $item ) { $item_xml = $xml->addChild('product'); $item_xml->addAttribute("name", $item['name']); $item_xml->addAttribute("id", $item['id']); $item_xml->addChild('image', $item['image']); $item_xml->addChild('price', $item['price']); $item_xml->addChild('metric', $item['metric']); $item_xml->addChild('description', $item['description']); } $doc = new DOMDocument('1.0'); $doc->preserveWhiteSpace = false; $doc->loadXML($xml->asXML()); $doc->formatOutput = true; $doc->save('XML/items.xml'); header("Location: index.php");
Next, a new SimpleXML element is created using the ‘items.xml’ file. A ‘foreach’ loop is instantiated which loops through the contents of the file. Before proceeding, let’s take a look at the structure of the ‘items.xml’ file.
<?xml version="1.0" encoding="utf-8"?> <advertisements name="Coffee Cups"> <product name="Hamburger" id="1345"> <image>burger.png</image> <price>9.99</price> <metric>1 pound</metric> <description>Enjoy our lean-cut, all-beef patties on your BBQ today. All of our choice-cut meat is 100% Grade-A beef taken from only the most trusted and respectable distributors.</description> </product> </advertisements>
Every product has a name, and a (hopefully) unique identifier, then all of the nested nodes are related to that product. Now back to the code…First, a new ‘product’ node is created then the two attributes ‘name’ and ‘id’ are added using the values of our recently created array. Then the image, price, metric, and description nodes are added. The last few lines basically convert our SimpleXML element to a DOM (Document Object Model) object. The only real reason this is done is because that, if we didn’t, our newly added nodes wouldn’t be nicely indented like the rest of the content in the ‘items.xml’ file. The ‘preserveWhiteSpace = false’ and ‘formatOutput = true’ statements ensure that everything will be nicely indented. The document is then saved and boom, we have our updated XML file. The ‘header(Location: index.php)’ line redirects us back to the index page once the XML file is rewritten. Worth note, the ‘header’ function cannot be used if any markup is displayed before it. Notice that before this line, no markup is outputted to the page. Javascript alerts are displayed if validation fails, but in that case the header function isn’t executed because all of the XML functions don’t execute if any one of the validations fail. Keep in mind that if any markup is displayed before the header function is called, it will throw an error which is not a good thing. Now that the most complex code is done, let’s look at the easy stuff.
STEP THREE – FINISHING THE INDEX.PHP PAGE
Now comes what is one of the easier parts of the code…the ‘delete’ area.
if($_GET['action'] == 'delete') { if(isset($_GET['id'])) { $doc = new SimpleXMLElement('XML/items.xml', NULL, TRUE); foreach($doc->product as $item) { if($item['id'] == $_GET['id']) { $dom=dom_import_simplexml($item); $dom->parentNode->removeChild($dom); } } $doc->saveXML('XML/items.xml'); header("Location: index.php"); } }
First, we use the $_GET function to test and see if the ‘action’ variable has a value of ‘delete’. The $_GET function also has a name/value basis but it is not based on form submission, it’s based on URL contents. In this case, if the ‘if’ statement passes the test the URL would look something like this ‘index.php?action=delete’
The question mark signifies the start of name/value content, and then the data follows. Next, if the ‘action’ is in fact ‘delete’, another ‘if’ statement checks to see if a variable ‘id’ has been set. We will see how the ‘action’ and ‘id’ variables are set in the coming steps. Assuming both ‘if’ statements pass, we are now ready to delete the associated XML nodes. First, using SimpleXML we load up the ‘items.xml’ file. Then, we instantiate a ‘for each’ loop to loop through the contents of the file. Within the loop, we test to see whether the XML node ‘id’ equals the ‘id’ from the $_GET contents. If they are equal, the SimpleXML element is firstly converted to a DOM object, and then subsequently deleted on the next line. Lastly, the file is saved again (minus the delete element) and the user is redirected back to the index page.
Then next step will be the default state of our ‘index.php’ page which displayed both the contents of the XML file, and the Flash banner add which uses the data from this file.
STEP FOUR – DEFAULT INDEX STATE
<?php define("IMAGE_LOCATION", "images/"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta name="Author" content="Andrew Grant, andrew_grant@rogers.com"> <link rel="stylesheet" href="css/styles.css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>XML Management Script</title> </head> <body> <?php if($_GET['action'] == 'view' || !isset($_GET['action'])) { ?> <script type="text/javascript" src="js/swfobject.js"></script> <script type="text/javascript"> var flashvars = {}; var params = {}; var attributes = {}; swfobject.embedSWF("flash/ad.swf", "flash_content", "336", "280", "10.0.0", false, flashvars, params, attributes); </script> <?php $xml = simplexml_load_file("XML/items.xml"); echo "<div id=\"left_col\">"; foreach($xml->product as $item) { echo "<div class=\"item_container clearfix\">"; echo "<img src=\"" . IMAGE_LOCATION . $item->image . "\" class=\"float_left item_image\" />"; echo "<div class=\"item_container_inner\">"; echo "<strong>Product</strong> : " . $item['name'] . "<br />"; echo "<strong>Price</strong> : $" . $item->price . "<br />"; echo "<strong>Metric</strong> : " . $item->metric . "<br />"; echo "<strong>Description</strong> : " . $item->description . "</div>"; echo "<div class=\"delete_item\"><a href=\"index.php?action=delete&id=" . $item['id'] . "\">delete this item</a> | "; echo "<a href=\"index.php?action=add\">add new item</a></div>"; echo "</div>"; } echo "</div>"; echo "<div id=\"flash_content\"></div>"; } ?>
First a constant for our images folder path is created. This is basically a variable that cannot be changed using code. It points to our images folder and will be used to display them. Next our DOCTYPE and other header information is outputted. Recall that in the previous steps, other than the javascript ‘alert’ statements there is no markup being displayed. That’s because all of the code was involved in processing and not the display of data. Now we want to output markup for the display of information so we need this information. Just after the BODY tag, we have another ‘if’ statement. It check to see if either ‘action’ is set to ‘view’ or if ‘action’ is not set at all. Next, we embed the Flash content in our page. First the swfobject script is embedded, and then we actually embed the content using the embedSWF function. I won’t get into the specifics of using swfobject, just know that is much easier on the eyes than the script output by the Flash IDE. The first parameter of the embedSWF function is the path to the movie itself, and the second parameter is the DIV id it will be embedded in. The last few lines again work with the XML file. First, a SimpleXML object is instantiated and set to the contents of the ‘items.xml’ file and then a ‘for each’ loop is started which loops through each elements in the file. After seeing what you have in the tutorial thus far, these lines should be fairly straightforward. After the description is outputted, we then output two links. These will be seen for every item…an ‘add’ and a ‘delete’ link. The ‘delete’ link is formed using the unique ‘id’ from the XML file. The href for the link looks like this : ‘index.php?action=delete&id=’ . $item['id'] First, the question mark signifies that name/value pairs are to follow. Then ‘action’ is set to ‘delete’ and the ‘id’ is set to the items’ id from the XML file. This URL information is then used to delete an item which saw previously. The ‘add’ link is much the same. It uses a name/value pair of ‘action=add’ to tell the script that we wish to add an item to the file. The last bit is the DIV which will hold our embedded .SWF movie. With this setup, we have a nice listing of our file as well as the Flash movie itself floated to the right of it. This way, anytime the content is updated and the user is redirected back to the index page, they will see the animation scrolling through the new content. Okay, we’re almost done…let’s look at the last step.
STEP FIVE – NEW ITEM FORM
This step is fairly easy, we’re just outputting the markup needed to display our form.
<?php if($_GET['action'] == 'add') { echo "<div id=\"update_form\">"; echo "<form method=\"post\" enctype=\"multipart/form-data\" action=\"index.php\">\n"; echo "<div class=\"input_label\">Product</div><div><input type=\"text\" class=\"input_field\" name=\"product\" /></div>"; echo "<input type=\"hidden\" name=\"max_file_size\" value=\"50000\" />"; echo "<div class=\"input_label\">Image [50 x 50 - .PNG .JPG .GIF]</div><div><input name=\"uploadedfile\" class=\"input_field file_upload\" type=\"file\" /></div>"; echo "<div class=\"input_label\">Price</div><div><input type=\"text\" class=\"input_field\" name=\"price\" /></div>"; echo "<div class=\"input_label\">Metric [1 pound, 5 dishes etc..]</div><div><input type=\"text\" class=\"input_field\" name=\"metric\" /></div>"; echo "<div class=\"input_label\">Description</div><div><textarea class=\"input_field textarea\" name=\"description\" cols=\"10\" rows=\"20\"></textarea></div>"; echo "<div><input type=\"hidden\" name=\"action\" value=\"update_file\"/></div>"; echo "<div class=\"submit\"><input type=\"submit\" value=\"Add Item\" /></div>"; echo "</form></div>"; echo "<div class=\"update_link\"><a href=\"index.php\">View All Items</a></div>"; } ?> </body> </html>
First we have an ‘if’ statement checking to see if the ‘action’ variable has been set to ‘add’ (which is done using the ‘add’ link in the last step). Notice that in the FORM declaration, there is an ‘enctype=multipart/form-data’ statement. This is needed for the file upload control to work. Everything else is pretty straightforward. Form elements are added, each with their own unique names. The name will be the variable name in the $_POST name/value pair. The values will be what the user inputs in the form. The last item worth mention is the hidden text field. These fields are not visible to the user in the form but are still included in the name/value pair listing of POST data. This field is what tells our script that we want to update the file.
That’s basically all there is to it. We now have a decidedly basic backend to edit and view our XML file and Flash animation.
One other note : I will not be touching on any of the CSS styling. You will see in the steps where markup is outputted (the ‘add new item’ form and the default view) that I make use of classes. Pour over the stylesheet to see the stylings. If you aren’t familiar enough with HTML and CSS then you might want to educate yourself further as it is outside the scope of this tutorial.
This is a simple tutorial which illustrates how to scroll content into view randomly. The code also prevents the same item from being displayed twice in a row. There is one MovieClip in the library which contains one dynamic MovieClip. This textfield will be set at runtime to help differentiate each clip from one another. Be aware that I have not included the caurina Tweener package in the .ZIP archive of files. Visit google code to download the package and view the documentation. Also, I have used swfObject to embed the Flash in the example index.html file. It’s very straightforward to use and MUCH cleaner than the garbage HTML which Flash generates by default. You can also visit google code to find out more about it.

Also, here’s an example using XML data
Now let’s get to it.
STEP ONE – The Import and Global Variables
import caurina.transitions.Tweener; var last_item:Number; var first_item:Boolean = true; var rand_num:Number; var timer:Timer = new Timer(4000, 1); // Create MovieClips for(var i=0; i<8;i++) { var newNum = i + 1; var clip = new Array(); clip[i] = new item(); clip[i].name = "clip" + newNum; clip[i].x = 337; clip[i].dyn_text.text = newNum; addChild(clip[i]); } // Begin scrolling of content auto_scroll();
First, we import the caurina Tweener package. This will be used to animate the scrolling of our MovieClips. Next, a number of global variables are instantiated. last_item will store the name of the last presented clip. first_item is a boolean variable which is initially set to true. Once the first clip is animated into view, it will be set to false. rand_num will hold a random number between 1 and the total number of clips, which in the case of this tutorial, will be 8. Then a timer variable is instantiated. This will help offset the time that each clip is visible, in this tutorial it will be 4 seconds. Lastly, a ‘for’ loop is started. This loops 8 times, each time creating new MovieClips, setting various properties then adding each to the stage. The name of each clip is set, it’s ‘x’ property set and then the dynamic text field within each is set to the ‘for’ loops current counter number. Now we have 8 clips each with a different number visible ready to be animated. The last line calls the ‘auto_scroll’ function which will animate all of the scrolling of content.
STEP TWO – Scrolling of Content
function auto_scroll():void { //Generate random number between 1 and array length rand_num = randomNumber(1, clip.length); //Generate another random number until is doesn't equal the last one while(rand_num == last_item) { rand_num = randomNumber(1, clip.length); } //Only scroll in content if item is the first one if(first_item == true) { Tweener.addTween(getChildByName("clip" + rand_num), {x: 10, time:1, transition:"Linear"}); first_item = false; last_item = rand_num; } timer.addEventListener(TimerEvent.TIMER, transition_items); timer.start(); }
Here is our auto_scroll function. First, the rand_num variable is set to the result of a call to the randomNumber function. This function, which we will see shortly, accepts 2 parameters : the lower number limit and the upper number limit. It will return a random number in between the 2 limits. Next, a ‘while’ loop is begun which tests whether the last clip (it’s number) displayed is equal to the random number which was generated. If they are equal, the randomNumber function is called again in effect generating a new random number. This ‘while’ loop ensures that the next clip to be displayed will never be the same clip that was just displayed. Now an ‘if’ statement tests to see whether the ‘first_item’ variable is ‘true’. If it is, then content is only scrolled in, not out, because no items are currently being displayed. The first_item boolean variable is then set to ‘false’ because the first item has now been displayed. last_item is then set to the value of rand_num in preparation for further scrolling. Lastly, an event listener is added to the timer telling is to call the transition_items function once the preset time elapsed (4 seconds) and the timer is subsequently started.
function transition_items(event:TimerEvent):void { // Scroll last item out of view and scroll new content in Tweener.addTween(getChildByName("clip" + last_item), {x: -336, time:1, transition:"Linear", onComplete: function():void { getChildByName("clip" + last_item).x = 337;} }); Tweener.addTween(getChildByName("clip" + rand_num), {x: 10, time:1.2, transition:"Linear", onComplete: function():void { last_item = rand_num; auto_scroll()} }); } function randomNumber(low:Number=0, high:Number=1):Number { return Math.floor(Math.random() * (1+high-low)) + low; }
Here we have the transition_items function. We make use of the caurina Tweener package to animate the scrolling. The first parameter the addTween function accepts is the targeted MovieClip for the animation. In this case, we use the getChildByName(“clip” + last_item) statement to target the clip to be scrolled out. Remember that in the ‘for’ loop from Step One, we assigned the name of each clip to the word ‘clip’ followed by a number. In this case, that number will be the contents of the last_item variable. Next, the addTween function accepts which property and coordinate it should animate to : x:-336. This will make the tween animated off screen to the left of the stage. Then the ‘time’ it should take to animate, and the transition type are used. An optional parameter onComplete..this instructs the tween to execute a function on completion. I’ve opted to use what is called an anonymous function..I basically create function without a name which is executed when the tween has completed. In this case, the clip which was just scrolled off-screen is moved off and to the right of the stage in preparation to be scrolled into view again. Next, we again make a call to the addTween function, this time targeting a random clip. The clip is scrolled in along the x-axis to position 0, basically putting it right in view. It also has an onComplete anonymous function. This time it sets the last_item to the value of rand_num because this clip will now be scrolled out as the code executes further. The auto_scroll function is then called again, repeating all of our code which keeps the train rolling. The last function is randomNumber. It speaks for itself and the code is pretty straightforward.
That’s it folks, a decidedly basic tutorial on how to randomly scroll content into view. Ideal for banner advertisements and the like. For all you keeners out there, this could be applied to the Flash Banner Ad using XML tutorial I posted awhile ago. Instead of adding each item to a big container which is subsequently scrolled, each item could be scrolled into view randomly using this technique.
Have you been charged with designing a banner advertisement but size restrictions are getting you down? Well, this tutorial could help you out a bit. All information is grabbed from an XML file, and images are loaded externally cutting down on overall file size. There is not one asset in the library for this project. I make use of the caurina Tweener class, but if you want to use the built-in Flash Tween class it could further decrease overall file size. I opted for the Tweener package because over time I have found the native Flash Tween class to be a bit buggy and unreliable. If you make use of the Transition Manager it compounds the problem as animations freeze many times. Anyways, in part one of our tutorial we will show users how to grab the data from XML, preload many of the images and present it in a scrolling movieclip. Part two will involve designing forms and code in PHP to let users add and remove elements from the XML file. Well, let’s get to it!
STEP ONE – Image Creation
I chose to create an advertisement using the size of a large rectangle (336 x 280). This allows for the presentation of textual information in a fairly pleasing manner. You can forego image creation until the end if you like, but I prefer to have as many visual assets at my disposal before diving into Flash. You could always use the images included in the archive as well. Be aware that product images were relatively small (50 x 50) and all are 8-bit .PNGs. Choose whichever format you deem best for the task.
STEP TWO – Setting the Stage
You’ll want to edit the document properties to be in line with the advertisement size which has been chosen. There won’t be any visual assets in the library at all. You’re going to want to put you’re directory structure in place as well. There’s an images folder for, you guessed it, the graphics we’ll be using. A flash folder to hold the .FLA and generated .SWF files, and lastly an XML folder which will hold our XML file. Once that is complete, go ahead and save the .FLA in the flash folder and we can proceed.
STEP THREE – Begin Creating the Elements
Allrighty! Now we begin coding.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import caurina.transitions.Tweener; // Load XML data var xml_basepath = "../XML/"; var xmlLoader:URLLoader = new URLLoader(); var xmlData:XML = new XML(); xmlLoader.addEventListener(Event.COMPLETE, LoadXML); xmlLoader.load(new URLRequest(xml_basepath + "items.xml")); // Load BG image var image_basepath = "../images/"; var BGImageLoader:Loader = new Loader(); var BGImage:URLRequest = new URLRequest (image_basepath + "BG.jpg"); BGImageLoader.load(BGImage); var speed:int = 0; |
In line 1, we import the Tweener package. We will be using this to scroll the content once it’s loaded. Lines 3 to 7 are the necessary steps to load the XML file into Flash. Notice the xml_basepath variable… you would change the basepath to the appropriate directory the file resides in. It is always relative to the directory the generated document which embeds the .SWF resides in. In this case, we want to go into the ‘XML’ and ‘images’ folders respectively. You will find that if you compile and test the project within Flash, you will have to add ‘../’ to each basepath in order to traverse the directory structure correctly. Because it isn’t being embedded in this case, the basepaths are relative to the .SWF itself so you have to actually go up a directory THEN go into each respective directoy, hence the ../ notation. We add an Event Listener to execute the LoadXML function once all data has been retrieved from the XML file. This function is where all of our code will be executed. The last few lines setup variables necessary to load the main background image as well as set the speed of the scrolling animation. Notice that a) no event listener was added and b) the image hasn’t been added to the stage yet. I opted not to add Event Listeners for the images given their relatively small file sizes. Let’s keep this moving, on to the LoadXML function..
STEP FOUR – The LoadXML function
This is where all the magic happens. Let’s take a look..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function LoadXML(e:Event):void { xmlData = new XML(e.target.data); var xml_data:XMLList = xmlData.product; var counter = 1; var yVal:int = 0; var yMax:int = 0; var output = ""; var main_container:MovieClip = new MovieClip(); main_container.x = 0; main_container.y = 280; // Create BG image container and add BG image BGImageLoader.alpha =.2; var BGcontainer:MovieClip = new MovieClip(); BGcontainer.addChild(BGImageLoader); addChild(BGcontainer); |
Line 2 creates a new XML object from the data which was passed to the LoadXML function after it completed loading. Line 3 parses this data into an XMLList object using every ‘product’ node (and it’s child nodes) in the XML Document. Lines 4 to 8 create variables which will be used later in the function. Line 9 created a new MovieClip which will be the main container for all of the products which will be displayed. Finally the next two lines position it just below the stage which will be the starting point for the scrolling animation. The last lines set the alpha transparency of the background image to .2, creates a new MovieClip then adds the background image to it, and finally this newly created MovieClip is added to the stage. In effect, we’ve added our first visual asset to the stage. All done using coding…feels good doesn’t it?
Pretty easy so far, let’s keep going.
STEP FIVE – The FOR EACH Loop
This is by far the most complex step in the tutorial. All of the ‘meat’ of the project takes place in this loop. Let’s take a look..
1 2 3 4 5 6 | for each (var xml_item:XML in xml_data) { // Create Array and populate with unique container variable names var part:Array = new Array(); part[counter] = "container" + counter; part[counter] = new MovieClip(); |
The first line instantiates the loop. It takes two parameters, the first is the variable name which is of type XML. The second is the data source which, if you remember, was the xml_data variable which was created at the start of the LoadXML function. This is of data type XMLList. The first few lines of the loop create the ‘part’ Array. It will contain unique variable names for each product container. It makes use of the ‘counter’ variable which was instantiated and set to 1 at the start of the LoadXML function. Every time the loop completes (once for each product in the XML file), the counter increases by one in effect giving us unique variable names for each product container contained in the ‘part’ array.
1 2 3 4 5 6 7 8 9 10 11 12 | // Create dynamic text field and set properties var xml_format:TextFormat = new TextFormat(); xml_format.size = 12; xml_format.font = "Arial"; var xml_text:TextField = new TextField(); xml_text.width = 260; xml_text.wordWrap = true; xml_text.x = 20; xml_text.y = 20; xml_text.defaultTextFormat = xml_format; xml_text.autoSize = TextFieldAutoSize.LEFT part[counter].addChild(xml_text); |
Next up, the dynamic text field which will contain the information retrieved from the XML file. First, a TextFormat object is instantiated. This will help us set properties like the font type and font size. Then the actual text field is created. We set properties like the width, starting x and y coordinates and wordWrap to equal true. If wordWrap weren’t set to equal true, our text would just extend to the right until the end. The final property to be set is autoSize. This ensures that the height of the text field automatically changes based on how much text there is…this is an important point which comes into play later in the loop when we want to determine the height of the main container. The last 3 lines set the defaultTextFormat to be our TextFormat values which were set. The newly formatted TextField is then added to the ‘part’ container for the product. Now we’re cooking with fire!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Load up variables with XML element data var item_data:Array = new Array(); item_data[0] = xml_item.attribute("name"); item_data[1] = xml_item.image; item_data[2] = xml_item.price; item_data[3] = xml_item.metric; item_data[4] = xml_item.description; // Load product image var imageLoader:Loader = new Loader(); var image:URLRequest = new URLRequest (image_basepath + item_data[1]); imageLoader.load(image); imageLoader.x = 235; imageLoader.y = 20; // Load item separator image var separatorImageLoader:Loader = new Loader(); var separatorImage:URLRequest = new URLRequest (image_basepath + "separator.png"); separatorImageLoader.load(separatorImage); |
Now, an array is created to hold the XML element data for the product called item_data. Each array position is set to a specific element in the xml_item variable which is an XMLList. Every product node in the file has a ‘name’ attribute which identifies the name of the product which is grabbed using the xml_item.attribute(“name) syntax. Every other element are simply text between opening-and-closing element tags so they are all grabbed in the same way. Next, we create the necessary items to retrieve each product image. First the loader is created, then a URLRequest is made which is the basepath with the filename added to it. Then the image is loaded. Notice that we haven’t added it to the container clip yet. We also set the x and y coordinates of the image placing it in the top-right corner of every ‘part’ container.
We then do much the same thing for the separator image. This will be the background image for every ‘part’ container lending a sense of separation between each product.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // Set output variable output = "<b>Product</b> : " + item_data[0] + "\n"; output += "<b>Price</b> : $" + item_data[2] + "\n"; output += "<b>Metric</b> : " + item_data[3] + "\n"; output += "<b>Description</b> : " + item_data[4] + "\n\n"; // Set dynamic text field htmlText to that of output variable part[counter].getChildAt(0).htmlText = output; // Add separator image to container part[counter].addChild(separatorImageLoader); // Add product image to container part[counter].addChild(imageLoader); // move separator image to the back of display list for part[counter] movieclip part[counter].setChildIndex (part[counter].getChildAt(0), (part[counter].numChildren - 1)); part[counter].x = 13; // only offset every item after the first one if(counter > 1) { yVal = this.getChildAt(this.numChildren - 1).height + 45; part[counter].y = yVal; } // Add product to main scrolling movie main_container.addChild(part[counter]); // Add main scrolling movie to the stage addChild(main_container); yMax = main_container.height; speed = yMax / 30; counter++; |
The next part assigns string content to the output variable. Notice that bold tags were used to style each product label…text can be styled using a limited number of CSS tags (bold) being one of them. The htmlText property of the dynamic text field is set to the contents of the output variable. HTML can only be styled if it is htmlText. If we chose instead to set the .text to equal the output string, the labels wouldn’t be in bold face. This assignment is done using part[counter].getChildAt(0).htmlText = output; Because the text field was the last item added to the ‘part’ container, we can access it using that code. It basically accesses the most recent child clip of the ‘part’ container and sets the htmlText property to the contents of the output variable. Having previously loaded the product image and separator image, we then add these items to the ‘part’ container. This line of code : part[counter].setChildIndex (part[counter].getChildAt(0), (part[counter].numChildren – 1)); essentially moves the separator image to the back of the ‘part’ display list. If we didn’t execute this, the separator image would appear above the text field and product image making things look decidedly weird. The IF statement which follows is used to offset each product, except the first one, by the height of the previous ‘part’ container plus 45 pixels. If we didn’t include this bit of code, every ‘part’ container would be stacked on top of each other again making things look weird.
This last few lines basically add all of the main generated content to the stage. First, the ‘part’ object is added to the main container. Remember that we’re doing this within a FOR EACH loop so every product node in the XML file has a corresponding ‘part’ object which is added until the end of the document is reached. After that, the main container is added to the stage and we’re basically done. The yMax variable is set to the height of the main container, the speed variable is set (which is used by the auto_scroll function to determine scrolling speed) and the counter variable is iterated as the loop moves through the XML content. Now all that is left is to scroll the content, which we’ll do now.
1 2 3 4 5 6 7 8 9 10 11 12 | // Begin scrolling of main container auto_scroll(); function auto_scroll():void { // Scroll content to maximum y value Tweener.addTween(main_container, {y:-yMax, time:speed, transition:"Linear", onComplete:reset_container }); } function reset_container():void { // Return main container to starting position and begin scrolling again. main_container.y = 280; auto_scroll(); } |
We then call our auto_scroll function. This begins the scrolling animation of our main container. Remember that we positionned the main container just below the threshold of the stage so it’s just out of view right now. We then define the auto_scroll function which makes use of the Tweener package. It takes a number of parameters. First, the targeted movie clip we want to animate, which is the main_container. Next is the y-value we want to animate to. This is set to the negative value of yMax, yMax being the height of the main container. The origin of our movie is (0,0), the top-left corner of the movie. If we want to move up, a negative y-value is needed which is why we want the negative value of yMax. The time value is the amount of time it should take for the animation to complete. In this case it is set by the predetermined ‘speed’ variable which was calculated at the end of the LoadXML function. Transition could be one of many preset transition types which could be used and finally, the onComplete statement calls the reset_container function which basically moves the main container back to its starting position once scrolling is complete. You can read the documentation on the caurina Tweener class here.
That’s basically all there is to it. Comb over the code and soak up the references. File constraints shouldn’t be a factor now…most ad servers impose anywhere from 30KB to 50KB size restrictions for Flash animations. The overall filesize (with Tweener package) is just about 12KB. This same project with visual assets in the library would be upwards or 50KB+ depending on how big the XML file is and the number of accompanying images. No matter how many items there are, the filesize will always remain constant using this approach. Tune in for Part Two of the tutorial coming soon. We will detail how to create a simple back-end application to edit the XML file using PHP. Concepts such as using both SimpleXML and Document Object Model (DOM) to add or delete XML elements, uploading and saving image files and simply viewing your XML file will be covered.
Click herefor part two of this tutorial. Thanks for tuning in!