<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="http://feedproxy.google.com/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feedproxy.google.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>The Tech Labs » Interfaces</title>
	
	<link>http://www.thetechlabs.com</link>
	<description>Adobe Air, Flash and Flex Tutorials</description>
	<pubDate>Thu, 23 Oct 2008 22:58:12 +0000</pubDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feedproxy.google.com/TheTechLabs_interfaces" type="application/rss+xml" /><item>
		<title>Simulating PicLens with Flex and Away3D – Part 3</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/7_m_KGon7n0/</link>
		<comments>http://www.thetechlabs.com/xml/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-3/#comments</comments>
		<pubDate>Thu, 23 Oct 2008 22:57:17 +0000</pubDate>
		<dc:creator>Alejandro Santander</dc:creator>
		
		<category><![CDATA[3D]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[Latest]]></category>

		<category><![CDATA[XML]]></category>

		<category><![CDATA[adobe flash]]></category>

		<category><![CDATA[adobe flex]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[caurina]]></category>

		<category><![CDATA[loading images]]></category>

		<category><![CDATA[oop]]></category>

		<category><![CDATA[photo viewer]]></category>

		<category><![CDATA[PicLens]]></category>

		<category><![CDATA[planes]]></category>

		<category><![CDATA[scene]]></category>

		<category><![CDATA[skinning]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[tweener]]></category>

		<category><![CDATA[web-design]]></category>

		<category><![CDATA[web-development]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=121</guid>
		<description><![CDATA[<p>Step by step guide for creating a PicLens type 3D photo viewer with Flex and Away3d. This is step 3, of a 3 part tutorial that will sweep many useful techniques used in web application design, Flex, and Flash 3D design.</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/3d/">3D</a> by Alejandro Santander <a href="http://www.thetechlabs.com/xml/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-3/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>Step by step guide for creating a PicLens type 3D photo viewer with Flex and Away3d. This is step 3, of a 3 part tutorial that will sweep many useful techniques used in web application design, Flex, and Flash 3D design. You will make <a title="See the final Application" href="http://thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Demos/Finished/"  target="_blank">this</a>.</p>
<p><strong>Requirements:</strong></p>
<ul>
<li><a title="Try / Buy Adobe Flash CS3" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" href="http://www.adobe.com/products/flash/" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" target="_blank">Adobe Flash CS3</a></li>
<li><a title="Try / Buy Adobe Flex Builder 3" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flex/?promoid=BPDEQ');" href="http://www.adobe.com/products/flex/?promoid=BPDEQ" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flex/?promoid=BPDEQ');" target="_blank">Adobe Flex Builder 3</a></li>
<li><a title="Download Away3D Library" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/away3d.zip');" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/away3d.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/away3d.zip');" target="_blank">Away3d Library</a> (I recommend using the version I used)</li>
<li><a title="Download Tweener Library" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/caurina.zip');" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/caurina.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/caurina.zip');" target="_blank">Tweener Library</a></li>
<li><a title="Download Source Files" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Sources/Part1.zip');" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Sources/Finished.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Sources/Finished.zip');" target="_blank">Source Files</a></li>
</ul>
<p><strong>Pre Requisites:</strong></p>
<ul>
<li>Having done Part 1 and 2 of this tutorial.</li>
<li>Intermediate programming skills.</li>
<li>Moderate knowledge of AS3.</li>
<li>Basic Familiarity with OOP.</li>
<li>Basic knowledge of Flash CS3.</li>
</ul>
<p style="text-align: center;"><img class="aligncenter" src="http://www.thetechlabs.com/wp-content/uploads/2008/09/image0011.jpg" alt="Pic Lens" width="541" height="196" /></p>
<h3>Step 0:</h3>
<p>This is the last section of the tutorial we’ve been working on. We’re going to wrap up everything we’ve done so far and make our work a solid, working application, which we can use and even extend in the future. First, we will centralize all arbitrary parameters into what’s known as a model, then, we’re going to connect the photo gallery into an external xml so we can load images dynamically, and finally we’re going to enhance our graphics a little bit by adding a reflection effect to the 3D scene.</p>
<h3>Step 1 – Centralizing data:</h3>
<p>As I stated before, we will start by creating a place holder for all arbitrary variables used so far. With arbitrary variables I mean values that we’ve chosen such as the camera’s tween time in the “moveTo()” method within CameraController, or the Z position of the cameraTarget that can greatly affect the nature of the camera’s motion. All these will be placed in a class that will hold these static constants and will also be used to hold dynamic variables further on, so they can be accessed easily from anywhere in the application. So, go ahead and create a new folder next to “view” called “model”. In it, create a new Actionscript Class called “Model.as”.</p>
<p>Now, I need you to work alone for a while. The job to do is recognise all the values you have used so far throughout the application, that you think would be a good idea to name into a variable and control from this central class. Then, all these variables will be declared in Model.as as static constants. This is how my class looks after doing just that:</p>
<pre>package  com.li.photoviewer.model

{ 

     public class Model

     {

          public static const  CAMERA_Z:Number = -2000;

          public static const  CAMERA_Z_ZOOMED:Number = -1500;

          public static const  CAMERA_ZOOM_TIME:Number = 1;

          public static const  CAMERA_ZOOM_EASE:String = "easeoutexpo";

          public static const  CAMERATARGET_FRICTION:Number = 0.95;

          public static const  CAMERATARGET_BOUNCE_FACTOR:Number = 0.5;

          public static const  CAMERATARGET_DRAG_FACTOR:Number = 0.1;

          public static const CAMERATARGET_SPEED_FACTOR:Number  = 0.05;

          public static const  CAMERATARGET_Z:Number = -100;

          public static const  CAMERATARGET_MOVETO_TIME:Number = 1;

          public static const  CAMERATARGET_MOVETO_EASE:String = "easeoutexpo";

          public static const  PHOTO_PLANE_SEGMENTS:Number = 3;

          public static const  PHOTO_MATERIAL_SMOOTH:Boolean = true;

          public static const  PHOTO_FADEIN_TIME:Number = 0.25;

          public static const  PHOTO_SPACING:Number = 750;

          public static const  BG_COLOR1:uint = 0x222222;

          public static const  BG_COLOR2:uint = 0x000000;

          public static const  BG_COLOR_RATIO:uint = 80

          public function Model()

          {

          }

     }

}</pre>
<p>“public  static const” is a way to declare a variable that will be accessible from the  outside of the class, can be accessed without instantiating the holder class,  and will not change. If you don’t what Im talking about, you should see how we  are going to use these variables and then come back to what I’ve just said and  you should get it right away.</p>
<h3>Step 2 – Connecting to the centralized  data:</h3>
<p>So far all  this is completely useless unless we connect our classes to Model.as, so that  the constants can be used. This is done very easily; for instance to connect  the “0.05” value representing a camera velocity factor, we do as in the  following code:</p>
<pre>private function followTarget(evt:Event):void

{

     camera.lookAt(cameraTarget.position);

     var dX:Number = cameraTarget.x - camera.x;

     camera.x  += dX*0.05;

...</pre>
<p>Simply change  to:</p>
<pre>private function followTarget(evt:Event):void

{

     camera.lookAt(cameraTarget.position);

     var dX:Number = cameraTarget.x - camera.x;

     camera.x  += dX*Model.CAMERATARGET_SPEED_FACTOR;

     ...</pre>
<p>As long as the  model has been imported in CameraController of course:</p>
<pre>import com.li.photoviewer.model.Model;</pre>
<p>So this is  what you should do next. Import Model.as in all the view and controller  classes, and connect the values to it. If you’ve imported the model into a  class first, you should get useful codehints from Flex to help you complete  this task. When you’re done, you’ll have the power to very precisely tweak the entire  application from Model.as. You should play around with this to tune it to your  liking.</p>
<h3>Step 3 – Setting up an external XML:</h3>
<p>Now that  our model is set up and working, we will read data from an external xml, and  also use the model to store the data contained in the xml. We will trigger a  service that will read an xml and detail the images that will be loaded in our  application, and once this service is done, the 3D scene will build itself  based on this data. For this, lets start by designing our xml. Create a folder  named “data” and in it a new file named “data.xml”. The folder should be next  to “com” or  “away3d” folders. Then  design the xml structure of data.xml like this:</p>
<pre>&lt;?xml  version="1.0"?&gt;

&lt;imgs&gt;

     &lt;img name="testImage.jpg"/&gt;

     &lt;img  name="1.jpg"/&gt;

     &lt;img  name="2.jpg"/&gt;

     &lt;img  name="3.jpg"/&gt;

     &lt;img  name="4.jpg"/&gt;

     &lt;img  name="5.jpg"/&gt;

     &lt;img  name="6.jpg"/&gt;

     &lt;img  name="7.jpg"/&gt;

     &lt;img  name="8.jpg"/&gt;

     &lt;img  name="9.jpg"/&gt;

     &lt;img  name="10.jpg"/&gt;

&lt;/imgs&gt;</pre>
<p>The xml is extremely  simple, it just contains the name of each image.</p>
<h3>Step 4 – Creating an XML Reader:</h3>
<p>We should  continue by creating a folder called “services” next to “view” and in it a new  Actionscript Class called “XmlReader”, which will take care of extracting the  data from the xml. This class should have two variables in its constructor,  “xmlPath” as a string and “onComplete” as a function, It will also have a  “loader” variable as a URLoader:</p>
<pre>private var xmlPath:String;

private var onComplete:Function;

private var loader:URLLoader;

public function XmlReader(xmlPath:String,  onComplete:Function)

{

     this.xmlPath = xmlPath;

     this.onComplete = onComplete;

     loader = new URLLoader();

     loader.addEventListener(Event.COMPLETE,  completeHandler);

     loader.load(new URLRequest(xmlPath));

}</pre>
<p>The path of  the xml file is stored, (as well as “onComplete” which we will see in a  minute), then the loader is initialized and triggered. The function  “completeHandler()” will, as its name says, handle the loader once it’s done:</p>
<pre>private function completeHandler(evt:Event):void

{

     var xmlDocument:XMLDocument = new  XMLDocument();

     xmlDocument.ignoreWhite  = true;

     var xml:XML = new XML(evt.target.data);

     xmlDocument.parseXML(xml.toString());

     for(var i:uint; i&lt;xmlDocument.firstChild.childNodes.length;  i++)

          Model.data.push(xmlDocument.firstChild.childNodes[i].attributes.name);

     onComplete();

}</pre>
<p>The handler  parses all the data in the xml and injects it in the model. Of course, we need  to go back to Model.as and declare this “data” variable that we are referring  to. Just add it after all the constants:</p>
<pre>public static var data:Array = [];</pre>
<p>Finally  (referring again to the completeHandler method), “onComplete()” gets called as  soon as all the parsing is done. Remember that we designed this XmlReader to  receive a reference to this external function when it is instantiated. This  will simply be the function to be called when the reader has finished its job.</p>
<h3>Step 5 – Using the reader:</h3>
<p>Lets  implement this now in the application’s main class, PhotoViewer3D.as. Carefully  study these modifications:</p>
<pre>package

{

     import com.li.photoviewer.services.XmlReader;

     import com.li.photoviewer.view.PhotoScene;

     import flash.display.Sprite;

     import flash.display.StageAlign;

     import flash.display.StageScaleMode;

     [SWF(backgroundColor="0x000000", frameRate="30")]

     public class PhotoViewer3D extends Sprite

     {

          public function PhotoViewer3D()

          {

               stage.scaleMode  = StageScaleMode.NO_SCALE;

               stage.align  = StageAlign.TOP_LEFT;

               var reader:XmlReader = new XmlReader(&#8221;data/data.xml&#8221;, init);

          }

          private function init():void

          {

               var photoScene:PhotoScene = new PhotoScene();

               addChild(photoScene);

          }

     }

}</pre>
<p>I’ve just  instantiated an XmlReader, pointed it to the xml path, put the creation of the  scene in its own separate method, and also pointed the reader to this method so  its called as soon as its done.</p>
<h3>Step 6 – Loading the images:</h3>
<p>The next  step is pretty obvious. We now have the data array containing all the names of  our images, waiting for us in the model and we’ve also delayed the creation of  the 3D scene till after this data has been obtained. So we just need to alter  the “initObjects()” method of PhotoScene.as to read this data. It’s too simple  actually:</p>
<pre>private function initObjects():void

{

     for(var i:uint; i&lt;Model.data.length; i++)

     {

          var photo:PhotoLoader = new PhotoLoader("imgs/" + Model.data[i]);

          photo.x  = i*Model.PHOTO_SPACING;

          scene.addChild(photo);

          cameraController.maxX  = photo.x;

          photo.addOnMouseDown(photoClickHandler);

     }

}</pre>
<p>That’s it.  Test the application and see how it now loads all the corresponding different  images. We’re practically done now, I just want to add an additional effect to  the app…</p>
<h3>Step 7 – Adding a reflection:</h3>
<p>As it is  usual in many open source projects, many people share their code in classes  that can be very handy and easy to use. You can very often download a class  that does a particular thing, use it, and never know how it actually works. So  that’s what we’ll do, we will greatly enhance the look of our application by  downloading a class, and I will make my point of showing how great it is to use  other people’s classes, or even design classes yourself to be reusable in this  way.</p>
<p><a title="Download Reflection.as" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/reflection.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/reflection.zip');" target="_self">Download Reflection.as</a> and paste it  in the view folder.</p>
<p>The class  should be ready to work, except that its package path is all wrong. This is  pretty logical, since I’ve just used it for another project and it was placed  completely on a different place. Correct this path to the class’ current  location. You can also look into the class, now or later, to understand how it  works and maybe learn new things that could motivate you to other uses or even  new ideas with Away3D.</p>
<h3>Step 8 – Plugging in the reflection:</h3>
<p>Go back to  PhotoScene.as and declare the reflection instance (we don’t need to import  Reflection.as since it is in the same package as PhotoScene.as):</p>
<pre>private var  reflection:Reflection;</pre>
<p>Then, in the “initScene()” method, initialize  it and add it to the display list:</p>
<pre>reflection = new Reflection(scene, camera);
addChild(reflection);</pre>
<p>And  finally, in “renderScene()” add a call to the reflections rendering method:</p>
<pre>private function renderScene(evt:Event):void

{

reflection.render();

view.render();

}</pre>
<p>I also took  the time to connect the Reflection class to the model and drop its arbitrary  variables there. I even set up a USE_REFLECTION constant in the model and  applied this Boolean value in the initialization of the reflection in  “initScene()” and the “renderScene()” method too. All this allows you to, not  only tweak the app to look good, but also to consider performance issues. With  the values that you should have in the model after you do this, you can really  optimize the application.</p>
<pre>public static const USE_REFLECTION:Boolean = false;

public static const REFLECTION_OFFSET:Number = -525;

public static const REFLECTION_BLUR:Number = 8;

public static const REFLECTION_ALPHA:Number = 0.25;

public static const REFLECTION_SCALING:Number = 2;</pre>
<p>So, that’s  it! The application is flexible enough to be extended easily. Maybe a  horizontal scroller could be a good idea, for example… I leave that to your  creativity. I wanted to keep the MVC architecture as simple as I could by  avoiding custom events, singleton classes, etc, but those could be good things  to investigate for future projects. On the other hand, I really recommend  playing with the Away3D engine, the possibilities with it are endless!!</p>
<p>I hope  you’ve enjoyed the tutorial. I’m looking forward to make another one when I can  =)</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" onmouseover="a2a_show_dropdown(this)" onmouseout="a2a_onMouseOut_delay()" href="http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Simulating%20PicLens%20with%20Flex%20and%20Away3D%20%E2%80%93%20Part%203&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fxml%2Fsimulating-piclens-with-flex-and-away3d-%25e2%2580%2593-part-3%2F" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Simulating%20PicLens%20with%20Flex%20and%20Away3D%20%E2%80%93%20Part%203&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fxml%2Fsimulating-piclens-with-flex-and-away3d-%25e2%2580%2593-part-3%2F');"><img src="http://www.thetechlabs.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p><img src="http://feedproxy.google.com/~r/TheTechLabs_interfaces/~4/7_m_KGon7n0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.thetechlabs.com/xml/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-3/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.thetechlabs.com/xml/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-3/</feedburner:origLink></item>
		<item>
		<title>Simulating PicLens with Flex and Away3D – Part 1</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/HC3nPEmO0ww/</link>
		<comments>http://www.thetechlabs.com/3d/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-1/#comments</comments>
		<pubDate>Tue, 16 Sep 2008 23:02:11 +0000</pubDate>
		<dc:creator>Alejandro Santander</dc:creator>
		
		<category><![CDATA[3D]]></category>

		<category><![CDATA[Effects]]></category>

		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[Latest]]></category>

		<category><![CDATA[adobe flash]]></category>

		<category><![CDATA[adobe flex]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[caurina]]></category>

		<category><![CDATA[loading images]]></category>

		<category><![CDATA[oop]]></category>

		<category><![CDATA[photo viewer]]></category>

		<category><![CDATA[PicLens]]></category>

		<category><![CDATA[planes]]></category>

		<category><![CDATA[scene]]></category>

		<category><![CDATA[skinning]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[tweener]]></category>

		<category><![CDATA[web-design]]></category>

		<category><![CDATA[web-development]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=116</guid>
		<description><![CDATA[<p>This tutorial article is a Step by step guide for creating a PicLens type 3D photo viewer with Flex and Away3d. This is step 1, of a 3 part tutorial that will sweep many useful techniques used in web application design, Flex, and Flash 3D design.</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/3d/">3D</a> by Alejandro Santander <a href="http://www.thetechlabs.com/3d/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-1/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>This tutorial article is a Step by  step guide for creating a PicLens type 3D photo viewer with Flex and Away3d.  This is step 1, of a 3 part tutorial that will sweep many useful techniques  used in web application design, Flex, and Flash 3D design.</p>
<p>In the final the result will be <a title="See the Final Application Demo" href="http://thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Demos/Finished/"  target="_blank">this</a>.</p>
<h3>Requirements</h3>
<ul>
<li><a title="Try / Buy Adobe Flash CS3" href="http://www.adobe.com/products/flash/" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" target="_blank">Adobe Flash CS3</a></li>
<li><a title="Try / Buy Adobe Flex Builder 3" href="http://www.adobe.com/products/flex/?promoid=BPDEQ" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flex/?promoid=BPDEQ');" target="_blank">Adobe Flex Builder 3</a></li>
<li><a title="Download Away3D Library" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/away3d.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/away3d.zip');" target="_blank">Away3d Library</a> (I recommend using the version I used)</li>
<li><a title="Download Tweener Library" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/caurina.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/caurina.zip');" target="_blank">Tweener Library</a></li>
<li><a title="Download Source Files" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Sources/Part1.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Sources/Part1.zip');" target="_blank">Source Files</a></li>
</ul>
<h3>Pre Requisites</h3>
<ul>
<li>Intermediate  programming skills</li>
<li>Moderate  knowledge of AS3</li>
<li>Basic  Familiarity with OOP</li>
<li>Basic  knowledge of Flash CS3</li>
</ul>
<p><img src="http://www.thetechlabs.com/wp-content/uploads/2008/09/image001.jpg" alt="" width="541" height="196" /></p>
<h3>Step 0</h3>
<p>In this  tutorial I will assume that you are familiar with the basics of building an  Actionscript Away3D project in Flex. If you haven’t used these two technologies  together before, it would be best if you go through my <a title="Setting up Away3d with Flex" href="http://www.thetechlabs.com/3d/setting-up-away3d-with-flex/"  target="_self">previous tutorial</a> first. Due to the complexity of this  application, I will need to skip some things to go faster. So, if something is  not explained here, or suddenly a large chunk of code is dropped with no  descriptions, it has been covered (hopefully) in the mentioned tutorial.</p>
<h3>Step 1 – New Project</h3>
<p>Lets get  started. Create a new Actionscript Project in Flex and name it “PhotoViewer3D”.  Then, download the libraries I listed in the requirements and paste them in the  project’s folder.</p>
<p>Now, one of  the things that will be covered here is a very simplified application  architecture that could be a good starting point for any project you do that  implies a moderate level of complexity. For this, all code will be placed in a  folder structure, carefully separating functions between different classes, and  hence emulating the basics of a Model View Controller design pattern. You  should have a general grasp of it by the end of this series.</p>
<p>Right click  on the project’s folder in the Flex Navigator and choose New -&gt; Folder, then  type “com/li/photoviewer/view” and press Finish. Naming folders this way is  known as Reverse Domain Syntax, and is a good programming practice.</p>
<h3>Step 2 – Setting up the scene</h3>
<p>Go to  PhotoViewer3D.as and build a basic main class:</p>
<pre><strong>package</strong>
{
     <strong>import</strong> flash.display.Sprite;
     <strong>import</strong> flash.display.StageAlign;
     <strong>import</strong> flash.display.StageScaleMode;

     <strong>import</strong> com.li.photoviewer.view.TestScene;

[SWF(backgroundColor=<strong>"0x000000"</strong>, frameRate=<strong>"30"</strong>)] 

     <strong>public</strong> <strong>class</strong> <span lang="EN-GB">PhotoViewer3D</span><strong> extends</strong> Sprite
     {
          <strong>public</strong> <strong>function</strong> <span lang="EN-GB">PhotoViewer3D</span>()
          {
               stage.scaleMode  = StageScaleMode.NO_SCALE;
               stage.align  = StageAlign.TOP_LEFT;

               <strong>var</strong> testScene:TestScene = <strong>new</strong> TestScene();
               addChild(testScene);
          }
     }
}</pre>
<p>Line 7  imports an away3D holding class that we haven’t made yet, so we should create it  right away. Right click on the “view” folder and choose New -&gt; Actionscript  Class and name it “TestScene”. It should have the following code in it:</p>
<pre><strong>package</strong> com.li.photoviewer.view 

{ 

     <strong>import</strong> away3d.cameras.Camera3D;
     <strong>import</strong> away3d.containers.Scene3D;
     <strong>import</strong> away3d.containers.View3D;
     <strong>import</strong> away3d.core.clip.RectangleClipping;
     <strong>import</strong> away3d.core.math.Number3D; 

     <strong>import</strong> flash.display.Sprite;
     <strong>import</strong> flash.events.Event; 

     <strong>public</strong> <strong>class</strong> TestScene <strong>extends</strong> Sprite
     {
          <strong>private</strong> <strong>var</strong> scene:Scene3D;
          <strong>private</strong> <strong>var</strong> camera:Camera3D;
          <strong>private</strong> <strong>var</strong> view:View3D; 

          <strong>public</strong> <strong>function</strong> TestScene()
          {
               addEventListener(Event.ADDED_TO_STAGE,  init, <strong>false</strong>, 0, <strong>true</strong>);
          } 

          <strong>public</strong> <strong>function</strong> init(evt:Event):<strong>void</strong>
          {
               removeEventListener(Event.ADDED_TO_STAGE,  init); 

               initScene();
               initObjects();
               addEventListener(Event.ENTER_FRAME,  renderScene);
          } 

          <strong>private</strong> <strong>function</strong> initScene():<strong>void</strong>
          {
               scene  = <strong>new</strong> Scene3D(); 

               camera  = <strong>new</strong> Camera3D();
               camera.zoom  = 10;
               camera.focus  = 200;
               camera.z  = -2000; 

               view  = <strong>new</strong> View3D();
               view.camera  = camera;
               view.scene  = scene;
               view.x  = stage.stageWidth/2;
               view.y  = stage.stageHeight/2;
               view.clip  = <strong>new</strong> RectangleClipping(-stage.stageWidth/2,  -stage.stageHeight/2, stage.stageWidth/2, stage.stageHeight/2);
               addChild(view);
          } 

          <strong>private</strong> <strong>function</strong> initObjects():<strong>void</strong>
          {
               <strong> </strong>
          } 

          <strong>private</strong> <strong>function</strong> renderScene(evt:Event):<strong>void</strong>
          {
               camera.x  = 3*(mouseX - stage.stageWidth/2);
               camera.y  = 3*(mouseY - stage.stageHeight/2);
               camera.lookAt(<strong>new</strong> Number3D(0, 0, 0)); 

               view.render();
          }
     }
}</pre>
<p><strong>NOTE: </strong>If any  of this shocked you, it has all been explained in the tutorial mentioned in Step  0.</p>
<h3>Step 3 – Setting up our PhotoLoader  component</h3>
<p>Create a  new Actionscript Class in the view folder and name it “PhotoLoader”. These will  be our 3D photograph object. The class will extend Away3D’s Plane primitive,  with a few additional features, more particularly, the ability to load an  external image. So, lets start by setting up the plane:</p>
<pre><strong>package</strong> com.li.photoviewer.view
{
<strong>import</strong> away3d.primitives.Plane;

<strong>public</strong> <strong>class</strong> PhotoLoader <strong>extends</strong> Plane
     {
<strong>private</strong> <strong>var</strong> urlPath:String;

          <strong>public</strong> <strong>function</strong> PhotoLoader(urlPath:String)
          { 

               <strong>super</strong>();

               <strong>this</strong>.urlPath = urlPath;

               <strong>this</strong>.rotationX = 90;
               <strong>this</strong>.width = 640;
               <strong>this</strong>.height = 480;
               <strong>this</strong>.segmentsH = 4;
               <strong>this</strong>.segmentsW = 4;
          }
     }
}</pre>
<p>As you can  see, we’ve set up the constructor so that when we instantiate a PhotoLoader  object, we pass it the image name it has to load as a parameter. Now, go back  to TestScene, and in the “iniObjects()” method, make an instance of PhotoLoader  and add it to the scene:</p>
<pre><strong>var</strong> testPhoto:PhotoLoader = <strong>new</strong> PhotoLoader(<strong>&#8220;imgs/testImage.jpg&#8221;</strong>);

scene.addChild(testPhoto);</pre>
<p>The urlPath we passed this time will be irrelevant,  but we’ll pass it anyway so no errors are thrown. Go ahead and test the  application, you should see something like this:</p>
<p><img src="http://www.thetechlabs.com/wp-content/uploads/2008/09/image003.jpg" alt="" width="540" height="400" /></p>
<h3>Step 4 – Skinning the plane with Flash</h3>
<p>First of  all, we need to give the plane a skin or texture. Even though it will contain  an image, it needs to contain something else while it’s loading, and somehow  show progress for that load process. For this, we will design some graphics in  Flash, and bring them to Flex with what I find to be a very practical and  simple technique. We will use a fla file to generate a library.swf file that  will contain some graphics for our application, and then embed that swf in Flex  and extract the clips as we need them. This is a very useful technique, and I  definitely recommend it for any Flex projects that contain design based vector  graphics.</p>
<p>Open Flash,  create a new AS3 Flash File and save it in your project’s folder, next to  PhotoViewer3D.as. Once in it, select File -&gt; Publish Settings and type “assets/library.swf” for the swf output path (deselect  the html output). Now, create a new folder next to that fla called “assets”  either from your file explorer or by right clicking the project’s folder in the  Flex Navigator. Now, if you publish the fla you will see that library.swf shows  up in your newly created assets folder.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.thetechlabs.com/wp-content/uploads/2008/09/image005.jpg" alt="" width="283" height="312" /></p>
<h3>Step 5 – Creating and extracting the  graphics created in Flash</h3>
<p>Great, now  I wont be describing how to make the graphics in Flash since I believe you must  be very familiar with this. You should <a title="Download the fla file" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/library.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/library.zip');" target="_self"><strong>download the </strong></a><strong><a title="Download the fla file" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/library.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/library.zip');" target="_self">fla</a></strong> and overwrite the one you just made.  Sorry! Just wanted to make sure you understood what’s going on. Now, open the  downloaded fla. You will see a clip called “LoaderFront” made up of a gray box  and a progressBar clip which has in turn a sub clip. The important thing to  notice here is that LoaderFront has a Linkage and its Base Class was changed to  Sprite. Publish it again, go back to Flex, right click on library.swf in the  assets folder and choose Refresh.</p>
<p>This is the  only code you’ll need to pull those graphics from Flex, type it at the top of  the PhotoLoader class (inside Public class…):</p>
<pre>[<strong>Embed</strong>(source=<strong>"assets/library.swf"</strong>, symbol=<strong>"LoaderFront"</strong>)]
<strong>public</strong> <strong>var</strong> LoaderFront:Class;</pre>
<p>You’ve just  extracted the symbol from the swf’s library and assigned it to a LoaderFront  class. If you create a new instance of this class (and add it to the display  tree), you’ll have a graphics object that extends Sprite! And you can treat it  as any other sprite. Great isn’t it?</p>
<h3>Step 6 – Applying the graphics to the  plane</h3>
<p>Go back to  PhotoLoader.as and create these variables for the class:</p>
<pre><strong>private</strong> <strong>var</strong> materialSprite:Sprite;
<strong>private</strong> <strong>var</strong> progressBar:Sprite;
<strong>private</strong> <strong>var</strong> progressBarSubClip:Sprite;</pre>
<p>And then  this method:</p>
<pre><strong>private</strong> <strong>function</strong> initClips():<strong>void</strong>
{
     materialSprite  = <strong>new</strong> LoaderFront();

     progressBar  = Sprite(materialSprite.getChildByName(<strong>&#8220;progressBar&#8221;</strong>));
     progressBarSubClip  = Sprite(progressBar.getChildByName(<strong>&#8220;subClip&#8221;</strong>));
}</pre>
<p>Now we have references to all the clips that we  need. You have to add the “initClips()” call at the end of the constructor  class.</p>
<p>Next, type this new method under the last one  and also make sure you call it from the constructor:</p>
<pre><strong>private</strong> <strong>function</strong> initMaterial():<strong>void</strong>
{
     <strong>var</strong> material:MovieMaterial = <strong>new</strong> MovieMaterial(materialSprite);
     material.smooth  = <strong>true</strong>;

     <strong>this</strong>.<span style="text-decoration: underline;">material</span> = material;
}</pre>
<p>And Test the application. You should now see that the  plane has taken the graphics as its material. Your PhotoLoader class should  look like this so far:</p>
<pre><strong>package</strong> com.li.photoviewer.view
{
     <strong>import</strong> away3d.materials.MovieMaterial;
     <strong>import</strong> away3d.primitives.Plane;
     <strong>import</strong> flash.display.Sprite;
     <strong>public</strong> <strong>class</strong> PhotoLoader <strong>extends</strong> Plane
     {
         [<strong>Embed</strong>(source=<strong>"assets/library.swf"</strong>, symbol=<strong>"LoaderFront"</strong>)]
          <strong>public</strong> <strong>var</strong> LoaderFront:Class;
          <strong>private</strong> <strong>var</strong> urlPath:String;
          <strong>private</strong> <strong>var</strong> materialSprite:Sprite;
          <strong>private</strong> <strong>var</strong> progressBar:Sprite;
          <strong>private</strong> <strong>var</strong> progressBarSubClip:Sprite;
          <strong>public</strong> <strong>function</strong> PhotoLoader(urlPath:String)
          {
               <strong>super</strong>();
               <strong>this</strong>.urlPath = urlPath;
               <strong>this</strong>.rotationX = 90;
               <strong>this</strong>.width = 640;
               <strong>this</strong>.height = 480;
               <strong>this</strong>.segmentsH = 4;
               <strong>this</strong>.segmentsW = 4;
               initClips();
               initMaterial();
          }
          <strong>private</strong> <strong>function</strong> initClips():<strong>void</strong>
          {
               materialSprite  = <strong>new</strong> LoaderFront();
               progressBar  = Sprite(materialSprite.getChildByName(<strong>&#8220;progressBar&#8221;</strong>));
               progressBarSubClip  = Sprite(progressBar.getChildByName(<strong>&#8220;subClip&#8221;</strong>));
          }
          <strong>private</strong> <strong>function</strong> initMaterial():<strong>void</strong>
          {
               <strong>var</strong> material:MovieMaterial = <strong>new</strong> MovieMaterial(materialSprite);
               material.smooth  = <strong>true</strong>;
               <strong>this</strong>.material = material;
          }
     }
}</pre>
<h3>Step 7 – Loading images into the plane</h3>
<p>The final  thing to do for Part 1 of this tutorial, is implement all the image loading  features of our extended plane. For this, we will use a regular Loader instance  and add a few event listeners to check for progress and complete events.</p>
<p>Add the  loader variable next to the other class variables:</p>
<pre><strong>private</strong> <strong>var</strong> loader:Loader;</pre>
<p>And call a new method under the  “initMaterial()” call in the constructor as “initLoader()”, then build the  method:</p>
<pre><strong>private</strong> <strong>function</strong> initLoader():<strong>void</strong>
{
     loader = <strong>new</strong> Loader();
     loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,  progressHandler);
     loader.contentLoaderInfo.addEventListener(Event.INIT,  initHandler);
     materialSprite.addChild(loader);
     loader.alpha  = 0;
}</pre>
<p>The loader is initialized, two listeners are registered,  then the loader is injected to the plane’s material sprite completely  invisible. I’ve made it invisible because I&#8217;m going to make it fade in once the  image has been loaded into it.</p>
<p>Now, lets set up the handlers and a little  “setProgress()” utilitary method:</p>
<pre><strong>private</strong> <strong>function</strong> progressHandler(evt:ProgressEvent):<strong>void</strong>
{
     setProgress(evt.bytesLoaded/evt.bytesTotal);
}
<strong>private</strong> <strong>function</strong> initHandler(evt:Event):<strong>void</strong>
{
     Tweener.addTween(loader,  {alpha:1, time:1, transition:<strong>&#8220;easeoutexpo&#8221;</strong>});
}
<span lang="EN-GB"> </span>
<strong>private</strong> <strong>function</strong> setProgress(value:Number):<strong>void</strong>
{
     progressBarSubClip.scaleX  = value;
}</pre>
<p>Pretty  straight forward. As the image downloads, the progress handler calls the “setProgress()”  function which in turn sets the horizontal scale of the progress bar, and when  the download completes, or more precisely when the loaded content is  initialized, Tweener makes the loader fade in by animating its alpha. Don’t  forget to import Tweener for this:</p>
<pre><strong>import</strong> caurina.transitions.Tweener;</pre>
<h3>Step 8 – Triggering the load</h3>
<p>Next, lets  trigger the load by adding a “loadImage()” method as the last method called in  the constructor and defining it:</p>
<pre><strong>private</strong> <strong>function</strong> loadImage():<strong>void</strong>
{
     loader.unload();
     loader.alpha  = 0;
     setProgress(0);
     loader.load(<strong>new</strong> URLRequest(urlPath));
}</pre>
<p>Finally,  create the imgs folder in the project, download <a title="Download the images" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/imgs.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flex/asantander/PicLensAway3D/Final/Downloads/imgs.zip');" target="_self">THESE</a> images and paste them in it. Test  the app, you should see the image loaded on the plane:</p>
<p><img src="http://www.thetechlabs.com/wp-content/uploads/2008/09/image007.jpg" alt="" width="540" height="400" /></p>
<p>Watch the Demo <a title="The the Part 1 Demo" href="http://www.thetechlabs.com/tutorials/files/flex/asantander/PicLensAway3D/Final/Demos/Part1"  target="_blank">HERE</a>.</p>
<address><strong>NOTE:</strong> </address>
<address>If  you have any security issues at this point you should disable the compilers  network for now. Do this by right clicking the projects folder, choosing  properties, then clicking on the Actionscript Compiler tab and in the  Additional Compiler Settings, type “-use-network=false”. Don’t forget to  disable this when you go online… This is something anyone using Flex gets to  know one way or the other for quickly getting over any sandbox issues.</address>
<p>Next:</p>
<p>On the next  part we will continue to develop our application by using multiple instances of  this PhotoLoader object, developing advanced camera motion and interactivity.</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" onmouseover="a2a_show_dropdown(this)" onmouseout="a2a_onMouseOut_delay()" href="http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Simulating%20PicLens%20with%20Flex%20and%20Away3D%20%E2%80%93%20Part%201&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2F3d%2Fsimulating-piclens-with-flex-and-away3d-%25e2%2580%2593-part-1%2F" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Simulating%20PicLens%20with%20Flex%20and%20Away3D%20%E2%80%93%20Part%201&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2F3d%2Fsimulating-piclens-with-flex-and-away3d-%25e2%2580%2593-part-1%2F');"><img src="http://www.thetechlabs.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p><img src="http://feedproxy.google.com/~r/TheTechLabs_interfaces/~4/HC3nPEmO0ww" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.thetechlabs.com/3d/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-1/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.thetechlabs.com/3d/simulating-piclens-with-flex-and-away3d-%e2%80%93-part-1/</feedburner:origLink></item>
		<item>
		<title>Extending the AS3/Flash9 Slideshow with XML</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/kTabWLNQ_pg/</link>
		<comments>http://www.thetechlabs.com/xml/extending-the-as3flash9-slideshow-with-xml/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 22:34:00 +0000</pubDate>
		<dc:creator>Rafael Nuenlist</dc:creator>
		
		<category><![CDATA[Effects]]></category>

		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[Latest]]></category>

		<category><![CDATA[XML]]></category>

		<category><![CDATA[adobe flash]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[caurinas engine]]></category>

		<category><![CDATA[how-to]]></category>

		<category><![CDATA[slideshow]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[tweener]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=105</guid>
		<description><![CDATA[<p>In this second part tutorial we&#8217;re going to add some more features to the slideshow application.</p>
<p>Those would be forwarding and rewinding slides, play and pause the slideshow and linkable slides. If you haven&#8217;t read the first part tutorial yet, you should do it before continue. You can read it here.</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/effects/">Effects</a> by Rafael Nuenlist <a href="http://www.thetechlabs.com/xml/extending-the-as3flash9-slideshow-with-xml/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>In this second part tutorial we&#8217;re going to add some more features to <a title="Extended Slideshow" href="http://www.thetechlabs.com/tutorials/files/flash/rnunlist/slideshow2/"  target="_blank">the slideshow application</a>.</p>
<p>Those would be forwarding and rewinding slides, play and pause the slideshow and linkable slides. If you haven&#8217;t read the first part tutorial yet, you should do it before continue. You can read it <a title="Create a AS3 Slideshow with XML Tutorial" href="http://www.thetechlabs.com/xml/create-a-as3-slideshow-with-xml/"  target="_blank">here</a>.</p>
<h3>Requirements</h3>
<p>Adobe Flash CS3</p>
<p><a title="Try / buy" onclick="javascript:pageTracker._trackPageview('/outbound/article/http://www.adobe.com/products/flash/');" href="http://www.adobe.com/products/flash/" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" target="_blank">Try / Buy</a></p>
<p>Sample files:</p>
<p><a title="Source Files" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/cardflip_fp10/CardFlip_FP10_source_files.zip');" href="http://thetechlabs.com/tutorials/files/flash/rnunlist/slideshow2/slideshowprt2.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flash/rnunlist/slideshow2/slideshowprt2.zip');" target="_self">slideshowprt2.zip</a></p>
<h3>Adjust XML structure</h3>
<p>To store the link of each slide, we just add it as an attribute to the xml file, or to be more accurate, on the image nodes. We also set the target window of the link, which might be neccesary to set in some cases. So, our xml is looking now like this:</p>
<pre>&lt;slideshow&gt;
	&lt;image src="images/fly.jpg" desc="Fly" link="http://www.wikipedia.org" target="_self"/&gt;
	&lt;image src="images/mouse.jpg" desc="Computer mouse" link="http://www.google.com" target="_blank"/&gt;
	&lt;image src="images/country.jpg" desc="Country" link="http://www.thetechlabs.com" target="_self"/&gt;
	&lt;image src="images/rope.jpg" desc="Rope" link="http://www.amazon.com" target="_blank"/&gt;
	&lt;image src="images/flower.jpg" desc="Flower" link="http://www.adobe.com" target="_self"/&gt;
&lt;/slideshow&gt;</pre>
<h3>Adding new objects</h3>
<p>Since we know, how the xml looks like, we can move on to the knew stuff on the stage. In the mcInfo movieclip we&#8217;ve added 4 new buttons. Pause/Play and Forward/Rewind, which will later be assigned to event listeners. On the main stage is a invisible button as big as the size of the slides which will be used to open the links defined in the xml.<br />
Alright, that&#8217;s already enough to go on with the coding part.</p>
<h3>Adding new variables</h3>
<p>First of all, we need to add some new variables to our script.</p>
<p>To know, if the slideshow is currently playing or paused, we set a flag:</p>
<pre>var bolPlaying:Boolean = true;</pre>
<p>And we also store the current slide link and target window in a variable:</p>
<pre>var strLink:String = "";
var strTarget:String = "";</pre>
<h3>Init function</h3>
<p>This is all we need for the variable. Now let&#8217;s take a look about what&#8217;s changing in the init function of the slideshow. We added the following two lines at the beginning of the function to prevent the user to click any button as long as the xml file hasn&#8217;t been loaded completely:</p>
<pre>	mcInfo.visible = false;
	btnLink.visible = false;</pre>
<p>We&#8217;ve also changed the function that will be called once the slideTimer event is fired. Now the function nextSlide() will be called, which we&#8217;ll create later:</p>
<pre>	slideTimer.addEventListener(TimerEvent.TIMER, nextSlide);</pre>
<p>On the last line of the initSlideshow() function we add the event listeners for the buttons. The play and button pause event listeners will be assigned to the same function togglePause(). The next and previous button will be asssigned to the nextSlide() and previousSlide() function. And last of all, we connect the invisible link button that covers the slide area with the goToWebsite() function. And since our slideshow will automatically be playing at the beginning, we hide the play button.</p>
<pre>	btnLink.addEventListener(MouseEvent.CLICK, goToWebsite);
	mcInfo.btnPlay.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnPause.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnNext.addEventListener(MouseEvent.CLICK, nextSlide);
	mcInfo.btnPrevious.addEventListener(MouseEvent.CLICK, previousSlide);
	mcInfo.btnPlay.visible = false;</pre>
<h3>onXMLLoadComplete function</h3>
<p>Once the xml is completely loaded, we need to show the mcInfo and the button link again. So we add the following two line of code to the function onXMLLoadComplete()</p>
<pre>	mcInfo.visible = true;
	btnLink.visible = true;</pre>
<p>And since our switchSlide() function will now need to have the index number of the slide, we add a zero as the parameter. We&#8217;ll explain the changes in the switchSlide() function later.</p>
<pre>	switchSlide(0);</pre>
<h3>NextSlide/PreviousSide function</h3>
<p>Let&#8217;s take a look at the nextSlide() and previousSlide() functions. They are called when clicking the next and previous button and the nextSlide() function is also called when the Timer event of the sliderTimer has been fired.<br />
The nextSlide() function checks, if there are any slides left to move on. If so, the current switchSlide() function will be called with the next slide index. If there are no more slides left, then the parameter will be zero standing for the first slide.<br />
The previousSlide() function works the same way. If there are slide we can go back, then the switchSlide() function will be called with the previous slide index. If we&#8217;re already on the first slide, then we start the slideshow from the last slide with calling the switchSlide() function with the parameter of the total slide count minus one since the array count begins with zero.</p>
<pre>function nextSlide(e:Event = null):void {
	if(intCurrentSlide + 1 &lt; intSlideCount)
		switchSlide(intCurrentSlide + 1);
	else
		switchSlide(0);

}

function previousSlide(e:Event = null):void {
	if(intCurrentSlide - 1 &gt;= 0)
		switchSlide(intCurrentSlide - 1);
	else
		switchSlide(intSlideCount - 1);
}</pre>
<h3>SwitchSlide function</h3>
<p>Since the nextSlide() and previousSlide() functions are now handling the checking for the slides, we can take out this part in the switchSlide() function.<br />
To prevent the user from clicking too fast on the next and previous button, we check, if the tweener is still fading in the slides. If so, we just ignore the action. We&#8217;re doing this by adding the following if-statement to the first line of the switchSlide() function.</p>
<pre>	if(!Tweener.isTweening(currentContainer)) {</pre>
<p>Now we only need to set the new link and the target of it. This will be done exactly the same way as setting the description of the slide.</p>
<pre>		strLink		= xmlSlideshow..image[intCurrentSlide].@link;
		strTarget	= xmlSlideshow..image[intCurrentSlide].@target;</pre>
<h3>FadeSideIn function</h3>
<p>The fadeSlideIn() function has also a small addition. We check if the slideshow is currently playing and show the number of seconds to the next slide. If the slideshow is paused, we show a status message. The text will be assigned to the lbl_info label.</p>
<pre>	if(bolPlaying) {
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
	} else {
		mcInfo.lbl_loading.text = "Slideshow paused";
	}</pre>
<h3>OnSlideFadeIn function</h3>
<p>On the onSlideFadeIn() function we now need to check, if the slideshow is playing. If so, we can start the timer again:</p>
<pre>	if(bolPlaying &amp;&amp; !slideTimer.running)
		slideTimer.start();</pre>
<h3>TogglePause function</h3>
<p>The togglePause() function will be called when the user clicks on the play and pause button. First, we check, if the slideshow is playing, if so, we show the play button, set the bolPlaying variable to false, change the status message of the lbl_info label to &#8220;Slideshow paused&#8221; and stop the timer.<br />
If the slideshow is currently paused, we show the pause button, set the bolPlaying variable to true again, show the time to the next slide and restart the timer.</p>
<pre>function togglePause(e:MouseEvent):void {
	if(bolPlaying) {
		mcInfo.btnPlay.visible = true;
		mcInfo.btnPause.visible = false;

		bolPlaying = false;
		mcInfo.lbl_loading.text = "Slideshow paused";
		slideTimer.stop();
	} else {
		mcInfo.btnPlay.visible = false;
		mcInfo.btnPause.visible = true;

		bolPlaying = true;
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
		slideTimer.reset();
		slideTimer.start();
	}
}</pre>
<h3>GotToWebsite function</h3>
<p>The last function we need to define is the goToWebsite() function. This function will be called once the user clicks on the invisible button. It will check, if the strLink variable is empty or null. If not, the link will be opened.</p>
<pre>function goToWebsite(e:MouseEvent):void {
	if(strLink != "" &amp;&amp; strLink != null) {
		navigateToURL(new URLRequest(strLink), strTarget);
	}
}</pre>
<p>We&#8217;ve already reached the end of the second part of the slideshow tutorial. We hope that you enjoyed reading it and we appreciate any kind of feedback.</p>
<h3>Note</h3>
<p>The feature for clicking the invisible button only works, when you&#8217;re running the flash on a webserver or in the flash sdk.</p>
<h3>Full code with comments</h3>
<pre>// import tweener
import caurina.transitions.Tweener;

// delay between slides
const TIMER_DELAY:int = 5000;
// fade time between slides
const FADE_TIME:Number =	1;

// flag for knowing if slideshow is playing
var bolPlaying:Boolean = true;
// reference to the current slider container
var currentContainer:Sprite;
// index of the current slide
var intCurrentSlide:int = -1;
// total slides
var intSlideCount:int;
// timer for switching slides
var slideTimer:Timer;
// slides holder
var sprContainer1:Sprite;
var sprContainer2:Sprite;
// slides loader
var slideLoader:Loader;
// current slide link
var strLink:String = "";
// current slide link target
var strTarget:String = "";
// url to slideshow xml
var strXMLPath:String = "slideshow-data.xml";
// slideshow xml loader
var xmlLoader:URLLoader;
// slideshow xml
var xmlSlideshow:XML;

function initSlideshow():void {
	// hide buttons, labels and link
	mcInfo.visible = false;
	btnLink.visible = false;

	// create new urlloader for xml file
	xmlLoader = new URLLoader();
	// add listener for complete event
	xmlLoader.addEventListener(Event.COMPLETE, onXMLLoadComplete);
	// load xml file
	xmlLoader.load(new URLRequest(strXMLPath));

	// create new timer with delay from constant
	slideTimer = new Timer(TIMER_DELAY);
	// add event listener for timer event
	slideTimer.addEventListener(TimerEvent.TIMER, nextSlide);

	// create 2 container sprite which will hold the slides and
	// add them to the masked movieclip
	sprContainer1 = new Sprite();
	sprContainer2 = new Sprite();
	mcSlideHolder.addChild(sprContainer1);
	mcSlideHolder.addChild(sprContainer2);

	// keep a reference of the container which is currently
	// in the front
	currentContainer = sprContainer2;

	// add event listeners for buttons
	btnLink.addEventListener(MouseEvent.CLICK, goToWebsite);
	mcInfo.btnPlay.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnPause.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnNext.addEventListener(MouseEvent.CLICK, nextSlide);
	mcInfo.btnPrevious.addEventListener(MouseEvent.CLICK, previousSlide);

	// hide play button
	mcInfo.btnPlay.visible = false;
}

function onXMLLoadComplete(e:Event):void {
	// show buttons, labels and link
	mcInfo.visible = true;
	btnLink.visible = true;	

	// create new xml with the received data
	xmlSlideshow = new XML(e.target.data);
	// get total slide count
	intSlideCount = xmlSlideshow..image.length();
	// switch the first slide without a delay
	switchSlide(0);
}

function fadeSlideIn(e:Event):void {
	// add loaded slide from slide loader to the
	// current container
	currentContainer.addChild(slideLoader.content);
	// clear preloader text
	mcInfo.lbl_loading.text = "";

	// check if the slideshow is currently playing
	// if so, show time to the next slide. If not, show
	// a status message
	if(bolPlaying) {
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
	} else {
		mcInfo.lbl_loading.text = "Slideshow paused";
	}

	// fade the current container in and start the slide timer
	// when the tween is finished
	Tweener.addTween(currentContainer, {alpha:1, time:FADE_TIME, onComplete:onSlideFadeIn});
}

function onSlideFadeIn():void {
	// check, if the slideshow is currently playing
	// if so, start the timer again
	if(bolPlaying &amp;&amp; !slideTimer.running)
		slideTimer.start();
}

function togglePause(e:MouseEvent):void {
	// check if the slideshow is currently playing
	if(bolPlaying) {
		// show play button
		mcInfo.btnPlay.visible = true;
		mcInfo.btnPause.visible = false;

		// set playing flag to false
		bolPlaying = false;
		// set status message
		mcInfo.lbl_loading.text = "Slideshow paused";
		// stop the timer
		slideTimer.stop();
	} else {
		// show pause button
		mcInfo.btnPlay.visible = false;
		mcInfo.btnPause.visible = true;

		// set playing flag to true
		bolPlaying = true;
		// show time to next slide
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
		// reset and start timer
		slideTimer.reset();
		slideTimer.start();
	}
}

function switchSlide(intSlide:int):void {
	// check if the last slide is still fading in
	if(!Tweener.isTweening(currentContainer)) {
		// check, if the timer is running (needed for the
		// very first switch of the slide)
		if(slideTimer.running)
			slideTimer.stop();

		// change slide index
		intCurrentSlide = intSlide;

		// check which container is currently in the front and
		// assign currentContainer to the one that's in the back with
		// the old slide
		if(currentContainer == sprContainer2)
			currentContainer = sprContainer1;
		else
			currentContainer = sprContainer2;

		// hide the old slide
		currentContainer.alpha = 0;
		// bring the old slide to the front
		mcSlideHolder.swapChildren(sprContainer2, sprContainer1);

		// create a new loader for the slide
		slideLoader = new Loader();
		// add event listener when slide is loaded
		slideLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, fadeSlideIn);
		// add event listener for the progress
		slideLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, showProgress);
		// load the next slide
		slideLoader.load(new URLRequest(xmlSlideshow..image[intCurrentSlide].@src));

		// show description of the next slide
		mcInfo.lbl_description.text = xmlSlideshow..image[intCurrentSlide].@desc;

		// set link and link target variable of the slide
		strLink		= xmlSlideshow..image[intCurrentSlide].@link;
		strTarget	= xmlSlideshow..image[intCurrentSlide].@target;

		// show current slide and total slides
		mcInfo.lbl_count.text = (intCurrentSlide + 1) + &#8221; / &#8221; + intSlideCount + &#8221; Slides&#8221;;
	}
}

function showProgress(e:ProgressEvent):void {
	// show percentage of the bytes loaded from the current slide
	mcInfo.lbl_loading.text = &#8220;Loading&#8230;&#8221; + Math.ceil(e.bytesLoaded * 100 / e.bytesTotal) + &#8220;%&#8221;;
}

function goToWebsite(e:MouseEvent):void {
	// check if the strLink is not empty and open the link in the
	// defined target window
	if(strLink != &#8220;&#8221; &amp;&amp; strLink != null) {
		navigateToURL(new URLRequest(strLink), strTarget);
	}
}

function nextSlide(e:Event = null):void {
	// check, if there are any slides left, if so, increment slide
	// index
	if(intCurrentSlide + 1 &lt; intSlideCount)
		switchSlide(intCurrentSlide + 1);
	// if not, start slideshow from beginning
	else
		switchSlide(0);

}

function previousSlide(e:Event = null):void {
	// check, if there are any slides left, if so, decrement slide
	// index
	if(intCurrentSlide - 1 &gt;= 0)
		switchSlide(intCurrentSlide - 1);
	// if not, start slideshow from the last slide
	else
		switchSlide(intSlideCount - 1);
}

// init slideshow
initSlideshow();</pre>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" onmouseover="a2a_show_dropdown(this)" onmouseout="a2a_onMouseOut_delay()" href="http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Extending%20the%20AS3%2FFlash9%20Slideshow%20with%20XML&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fxml%2Fextending-the-as3flash9-slideshow-with-xml%2F" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Extending%20the%20AS3%2FFlash9%20Slideshow%20with%20XML&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fxml%2Fextending-the-as3flash9-slideshow-with-xml%2F');"><img src="http://www.thetechlabs.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p><img src="http://feedproxy.google.com/~r/TheTechLabs_interfaces/~4/kTabWLNQ_pg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.thetechlabs.com/xml/extending-the-as3flash9-slideshow-with-xml/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.thetechlabs.com/xml/extending-the-as3flash9-slideshow-with-xml/</feedburner:origLink></item>
		<item>
		<title>Expanding the AS3 Videoplayer</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/EgEFFZ6188o/</link>
		<comments>http://www.thetechlabs.com/video/expanding-the-as3-videoplayer/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 23:40:13 +0000</pubDate>
		<dc:creator>Rafael Nuenlist</dc:creator>
		
		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[Video]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[fullscreen]]></category>

		<category><![CDATA[playlist]]></category>

		<category><![CDATA[progress bar]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[video player]]></category>

		<category><![CDATA[volume]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=88</guid>
		<description><![CDATA[<p>Alright, here&#8217;s the second part of the video player tutorial. We will be adding the following new features:<br />
- Playlist support<br />
- Fullscreen support<br />
- Save volume<br />
- Clickable progress/volume bar</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/flash/">Flash</a> by Rafael Nuenlist <a href="http://www.thetechlabs.com/video/expanding-the-as3-videoplayer/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>Alright, here&#8217;s the second part of the video player tutorial. We will be adding the following new features:<br />
- Playlist support<br />
- Fullscreen support<br />
- Save volume<br />
- Clickable progress/volume bar</p>
<p>You can preview the final result of this tutorial <a title="Video Player Demo" href="http://thetechlabs.com/tutorials/files/flash/rnunlist/videoplayer_prt2/videoplayer_prt2.html"  target="_blank">here</a>.</p>
<h3>Requirements</h3>
<p><strong>Adobe Flash CS3</strong></p>
<p><a title="Try / buy" onclick="javascript:pageTracker._trackPageview('/outbound/article/http://www.adobe.com/products/flash/');" href="http://www.adobe.com/products/flash/" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" target="_blank">Try / Buy</a></p>
<p><strong>Source Files</strong></p>
<p><a title="Download Source Files" onclick="javascript:pageTracker._trackPageview('/downloads/tutorials/files/flash/fcarrera/flickrsearchengine/flickrsearchengine_sfiles.zip');" href="http://thetechlabs.com/tutorials/files/flash/rnunlist/videoplayer_prt2/videoplayer_prt2.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flash/rnunlist/videoplayer_prt2/videoplayer_prt2.zip');" target="_self">Download</a></p>
<p>We also wanted to create a box displaying a message when the video is still buffering. But there has been an issue with the NetStreamEvent. It doesn&#8217;t fire the NetStream.Buffer.Empty event when the player&#8217;s actually buffering. People from the community say that this problem is somehow related with the encoding software of the flash video files. Since we didn&#8217;t find a proper solution, we left this feature out. If someone has an idea how this problem can still be properly solved, feel free to leave us a comment.</p>
<h3>Playlist support</h3>
<p>Ok, let&#8217;s begin with the major new feature. Adding the playlist support is quite simple and nearly implemented the same way as in the slideshow tutorial. So we have our XML file which looks like this:</p>
<pre>&lt;playlist&gt;
	&lt;vid src="video/hancock.flv" desc="Hancock (2008) - Movie Trailer"/&gt;
	&lt;vid src="video/redbelt.flv" desc="Redbelt (2008) - Movie Trailer"/&gt;
	&lt;vid src="video/the_dark_knight.flv" desc="The Dark Knight (2008) - Movie Trailer"/&gt;
&lt;/playlist&gt;</pre>
<p>As you can see, each video has two attributes. One describes the source to the file and the other one is a short description or the title of the movie.<br />
Now it&#8217;s time to go on with coding. We changed the line which defines the source of the flash video file to the following:</p>
<pre>var strSource:String = root.loaderInfo.parameters.playlist == null ? "playlist.xml" : root.loaderInfo.parameters.playlist;</pre>
<p>Like this, flash will look for the flash variable playlist which you can add in the html file. If it&#8217;s defined, then the value will be assigned to the variable strSource. Otherwise we just assign a default location. Like this, you can use one compiled SWF file for every playlist you want to publish.<br />
In order to load this file, we need to add three more variables to our video player:</p>
<pre>var urlLoader:URLLoader;
var urlRequest:URLRequest;
var xmlPlaylist:XML;</pre>
<p>urlLoader will later be used to load and handle the loaded xml file. urlRequest is an object for the urlLoader to load the playlist file. And xmlPlaylist will then contain the loaded xml data from the urlLoader.</p>
<p>We&#8217;ve added these code lines add the bottom to the initVideoPlayer() function:</p>
<pre>	urlRequest = new URLRequest(strSource);
	urlLoader = new URLLoader();
	urlLoader.addEventListener(Event.COMPLETE, playlistLoaded);
	urlLoader.load(urlRequest);</pre>
<p>A new urlRequest will be created with the source location of the xml file. Then we create a new urlLoader, add an event listener when the loading is completed and finally load the file. What&#8217;s also important is that we hide the controls of the video player in the first line of the initVideoPlayer() function since we don&#8217;t want that the user can click anything if the playlist hasn&#8217;t been loaded yet.<br />
As soon as the playlist is loaded we call the playlistLoaded() function which looks like this:</p>
<pre>function playlistLoaded(e:Event):void {
	xmlPlaylist = new XML(urlLoader.data);
	playVid(0, false)
	mcVideoControls.visible = true;
}</pre>
<p>We assign the received data from the loader to the xml object, set the first video source but not play the video and show the video controls since we&#8217;ve loaded all the stuff.</p>
<p>Now we need a back and forward button. We add two event listeners for the buttons in the initVideoPlayer() function:</p>
<pre>	mcVideoControls.btnNext.addEventListener(MouseEvent.CLICK, playNext);
	mcVideoControls.btnPrevious.addEventListener(MouseEvent.CLICK, playPrevious);</pre>
<p>Then we define a new variable that saves the current number:</p>
<pre>var intActiveVid:int;</pre>
<p>Now let&#8217;s take a closer look at the playVid() function</p>
<pre>function playVid(intVid:int = 0, bolPlay = true):void {
	if(bolPlay) {
		tmrDisplay.stop();
		nsStream.play(String(xmlPlaylist..vid[intVid].@src));
		mcVideoControls.btnPause.visible	= true;
		mcVideoControls.btnPlay.visible		= false;
	} else {
		strSource = xmlPlaylist..vid[intVid].@src;
	}

	vidDisplay.visible					= true;

	mcVideoControls.mcVideoDescription.lblDescription.x = 0;
	mcVideoControls.mcVideoDescription.lblDescription.htmlText = (intVid + 1) + &#8220;. <span style="color: #ffffff;">&#8221; + String(xmlPlaylist..vid[intVid].@desc) + &#8220;</span>&#8220;;

	intActiveVid = intVid;
}</pre>
<p>As you can see, it now needs to have a video number and a boolean value if the video should be played or just be set to the strSource variable. The function also sets the new description label of the requested video with the value from the xml object and positions it to zero on the x-axis. And finally the intVid value gets assigned to the variable intActiveVid.<br />
The playNext() and playPrevious() function are now ease to implement. We just check if there there is still a video left we can skip or rewind and call the playVid function with the parameter intActiveVid + 1 or intActiveVid - 1 depending on the direction:</p>
<pre>function playNext(e:MouseEvent = null):void {
	if(intActiveVid + 1 &lt; xmlPlaylist..vid.length())
		playVid(intActiveVid + 1);

}

function playPrevious(e:MouseEvent = null):void {
	if(intActiveVid - 1 &gt;= 0)
		playVid(intActiveVid - 1);
}</pre>
<p>When a video reached it&#8217;s end, we stoped the player. But now we want to play the next video in the playlist if there&#8217;s still one left, if not, ok then we stop the player <img src='http://www.thetechlabs.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> So we change this in the netStatusHandler() function:</p>
<pre>	if(intActiveVid + 1 &lt; xmlPlaylist..vid.length())
		playNext();
	else
		stopVideoPlayer();</pre>
<p>Now there&#8217;s only the vertical scrolling of the video description label left for the playlist feature. It could be that you need an extra long title for your video. In that case, we&#8217;ve just created a very long one lined textfield that&#8217;s masked. On top of that is an invisible button that will be used to know, if the user moves the mouse over the label so we can scroll it if it&#8217;s to long. In order to know if we&#8217;re currently scrolling the label and to know in which direction the scrolling is going, we need to set two new variables:</p>
<pre>var bolDescriptionHover:Boolean = false;
var bolDescriptionHoverForward:Boolean = true;</pre>
<p>Now we need to add an event listener on the invisible button:</p>
<pre>	mcVideoControls.mcVideoDescription.btnDescription.addEventListener(MouseEvent.MOUSE_OVER, startDescriptionScroll);
	mcVideoControls.mcVideoDescription.btnDescription.addEventListener(MouseEvent.MOUSE_OUT, stopDescriptionScroll);</pre>
<p>The functions startDescriptionScroll() and stopDescriptionScroll() are simply setting the bolDescriptionHover variable to true or false depending on the mouse event. startDescriptionScroll() additionally checks, if it&#8217;s even necessary to scroll the text:</p>
<pre>function startDescriptionScroll(e:MouseEvent):void {
	if(mcVideoControls.mcVideoDescription.lblDescription.textWidth &gt; 138)
		bolDescriptionHover = true;
}

function stopDescriptionScroll(e:MouseEvent):void {
	bolDescriptionHover = false;
}</pre>
<p>To actually move the label we just add some new lines of code to the updateDisplay() function which is called by the timer object:</p>
<pre>	if(bolDescriptionHover) {
		if(bolDescriptionHoverForward) {
			mcVideoControls.mcVideoDescription.lblDescription.x -= 0.1;
			if(mcVideoControls.mcVideoDescription.lblDescription.textWidth - 133 &lt;= Math.abs(mcVideoControls.mcVideoDescription.lblDescription.x))
				bolDescriptionHoverForward = false;
		} else {
			mcVideoControls.mcVideoDescription.lblDescription.x += 0.1;
			if(mcVideoControls.mcVideoDescription.lblDescription.x &gt;= 0)
				bolDescriptionHoverForward = true;
		}
	} else {
		mcVideoControls.mcVideoDescription.lblDescription.x = 0;
		bolDescriptionHoverForward = true;
	}</pre>
<p>First, we check if we&#8217;re currently over the label. The we figure out, which way we move the text. Since the updateDisplay() function is called pretty often, we get a smooth motion by incrementing and decrementing the label&#8217;s x value just by 0.1. So, when moving forward, we actualy move the label to the left and check, if we&#8217;ve reached the end. If so, we invert the bolDescriptionForward value and begin to move the field to the right until it reached zero on the x-axis. If the user&#8217;s no hovering over the invisible button, we just reset the position of the label and the direction flag.</p>
<h3>Fullscreen support</h3>
<p>Since flash player version 9,0,28,0 you can use the fullscreen feature. In order to get this to work, you also need to set this in the HTML code. But since Flash does all the HTML stuff for you, you only need to change the mode to allowFullscreen in the publish settings of HTML</p>
<p><img class="aligncenter size-full wp-image-90" title="Flash Fullscreen Publish" src="http://www.thetechlabs.com/wp-content/uploads/2008/08/flash-fullscreen-publish.jpg" alt="" width="461" height="651" /></p>
<p>The implementing of the fullscreen support is rather simple in our case because we don&#8217;t have too much stuff on the stage we need to reposition/resize once we hit the fullscreen mode. So, first of all, we set the scale mode of the stage to no scale because we want to resize the object individualy and not everything. We also set the stage align mode to the top left corner:</p>
<pre>stage.scaleMode	= StageScaleMode.NO_SCALE;
stage.align		= StageAlign.TOP_LEFT;</pre>
<p>Then we add two event listeners for the fullscreen button. One to enter it and one for leaving the full screen mode. We also add an event listener when the fullscreen mode changes. The visibility of the btnFullscreenOff button will be set to false. We do all of this in the initVideoPlayer() function:</p>
<pre>	mcVideoControls.btnFullscreenOn.addEventListener(MouseEvent.CLICK, fullscreenOnClicked);
	mcVideoControls.btnFullscreenOff.addEventListener(MouseEvent.CLICK, fullscreenOffClicked);
	stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullscreen);
	mcVideoControls.btnFullscreenOff.visible = false;</pre>
<p>To actualy enter and leave the fullscreen mode, all you need to do is to set the display state of the stage to the wanted mode. That&#8217;s what we&#8217;re doing when the user clicks the fullscreen buttons:</p>
<pre>function fullscreenOnClicked(e:MouseEvent):void {
	stage.displayState = StageDisplayState.FULL_SCREEN;
}

function fullscreenOffClicked(e:MouseEvent):void {
	stage.displayState = StageDisplayState.NORMAL;
}</pre>
<p>Now we only need to define the resizing action in the onFullScreen() function:<br />
function onFullscreen(e:FullScreenEvent):void {</p>
<pre>    if (e.fullScreen) {
        mcVideoControls.btnFullscreenOn.visible = false;
		mcVideoControls.btnFullscreenOff.visible = true;

		mcVideoControls.x = (Capabilities.screenResolutionX - 440) / 2;
		mcVideoControls.y = (Capabilities.screenResolutionY - 33);

		vidDisplay.height = (Capabilities.screenResolutionY - 33);
		vidDisplay.width = vidDisplay.height * 4 / 3;
		vidDisplay.x	= (Capabilities.screenResolutionX - vidDisplay.width) / 2;
    } else {
        mcVideoControls.btnFullscreenOn.visible = true;
		mcVideoControls.btnFullscreenOff.visible = false;
		mcVideoControls.x = 0;
		mcVideoControls.y = 330;
		vidDisplay.y = 0;
		vidDisplay.x = 0;
		vidDisplay.width = 440;
		vidDisplay.height = 330;
    }
}</pre>
<p>So, first we check if we&#8217;re entering the fullscreen mode. If so, we switch the fullscreen buttons, align the control bar in the bottom center of the screen and size up the video display and center it on to the screen. If we&#8217;re leaving the fullscreen mode, what you can also do by pressing the ESC key on your keyboard, we reset all the stuff to how it was before.<br />
That&#8217;s was already everything for the fullscreen support <img src='http://www.thetechlabs.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Save volume</h3>
<p>This is quite an important feature and really ease to implement in flash. To save the last used volume you can use the flash cookies which will be stored on the computer of the user. They are like normal browser cookies, but can only accessed through flash.<br />
So, the first thing we need to do is creating a new shared object:</p>
<pre>var shoVideoPlayerSettings:SharedObject = SharedObject.getLocal("playerSettings");</pre>
<p>The function getLocal returns the shared object you&#8217;ve requested. In our case we want to have the playerSettings cookie/shared object. Since we want to set the volume on the start, we add the following line to the initVideoPlayer() function:</p>
<pre>	var tmpVolume:Number = DEFAULT_VOLUME;
	if(shoVideoPlayerSettings.data.playerVolume != undefined) {
		tmpVolume = shoVideoPlayerSettings.data.playerVolume;
		intLastVolume = tmpVolume;
	}

	mcVideoControls.mcVolumeScrubber.x = (53 * tmpVolume) + 318;
	mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 371 + 53;
	setVolume(tmpVolume);</pre>
<p>First we assign the DEFAULT_VOLUME to a temporary variable. Then we check if the user has already a cookie with the player volume. If so, we override the value from the variable. Then we update the volume bar and set the volume with the setVolume() function.<br />
In order to store the new volume in the cookie, we add the following two new lines to the setVolume() function:</p>
<pre>	shoVideoPlayerSettings.data.playerVolume = intVolume;
	shoVideoPlayerSettings.flush();</pre>
<p>The function flush() writes the new value immadiately in the flash cookie.</p>
<h3>Clickable progress/volume bar</h3>
<p>This is just a beauty hack for the player. We want to be able to click on the progress or the volume bar to begin with the scrubbing. So, we just added two invisible buttons on the off the bars and added the function to it as when you click the scrub buttons directly:</p>
<pre>	mcVideoControls.mcVolumeScrubber.btnVolumeScrubber.addEventListener(MouseEvent.MOUSE_DOWN, volumeScrubberClicked);
	mcVideoControls.mcProgressScrubber.btnProgressScrubber.addEventListener(MouseEvent.MOUSE_DOWN, progressScrubberClicked);</pre>
<p>And what&#8217;s also changed is, that we now lock the center in the startDrag() function. Like this the scrubber will move to where you clicked on the bars:</p>
<pre>function volumeScrubberClicked(e:MouseEvent):void {
	bolVolumeScrub = true;

	mcVideoControls.mcVolumeScrubber.startDrag(true, new Rectangle(318, 19, 53, 0));
}

function progressScrubberClicked(e:MouseEvent):void {
	bolProgressScrub = true;

	mcVideoControls.mcProgressScrubber.startDrag(true, new Rectangle(0, 2, 432, 0));
}</pre>
<p>We&#8217;ve already reached the end of the second part of the video player tutorial. We hope that you enjoyed reading it and we appreciate every kind of feedback.</p>
<h3>Full code with comments</h3>
<pre>// ###############################
// ############# CONSTANTS
// ###############################

// time to buffer for the video in sec.
const BUFFER_TIME:Number				= 8;
// start volume when initializing player
const DEFAULT_VOLUME:Number				= 0.6;
// update delay in milliseconds.
const DISPLAY_TIMER_UPDATE_DELAY:int	= 10;
// smoothing for video. may slow down old computers
const SMOOTHING:Boolean					= true;

// ###############################
// ############# VARIABLES
// ###############################

// flag for knowing if user hovers over description label
var bolDescriptionHover:Boolean = false;
// flag for knowing in which direction the description label is currently moving
var bolDescriptionHoverForward:Boolean = true;
// flag for knowing if flv has been loaded
var bolLoaded:Boolean					= false;
// flag for volume scrubbing
var bolVolumeScrub:Boolean				= false;
// flag for progress scrubbing
var bolProgressScrub:Boolean			= false;
// holds the number of the active video
var intActiveVid:int;
// holds the last used volume, but never 0
var intLastVolume:Number				= DEFAULT_VOLUME;
// net connection object for net stream
var ncConnection:NetConnection;
// net stream object
var nsStream:NetStream;
// object holds all meta data
var objInfo:Object;
// shared object holding the player settings (currently only the volume)
var shoVideoPlayerSettings:SharedObject = SharedObject.getLocal("playerSettings");
// url to flv file
var strSource:String					= root.loaderInfo.parameters.playlist == null ? "playlist.xml" : root.loaderInfo.parameters.playlist;
// timer for updating player (progress, volume...)
var tmrDisplay:Timer;
// loads the xml file
var urlLoader:URLLoader;
// holds the request for the loader
var urlRequest:URLRequest;
// playlist xml
var xmlPlaylist:XML;

// ###############################
// ############# STAGE SETTINGS
// ###############################
stage.scaleMode	= StageScaleMode.NO_SCALE;
stage.align		= StageAlign.TOP_LEFT;

// ###############################
// ############# FUNCTIONS
// ###############################

// sets up the player
function initVideoPlayer():void {
	// hide video controls on initialisation
	mcVideoControls.visible = false;

	// hide buttons
	mcVideoControls.btnUnmute.visible			= false;
	mcVideoControls.btnPause.visible			= false;
	mcVideoControls.btnFullscreenOff.visible	= false;

	// set the progress/preload fill width to 1
	mcVideoControls.mcProgressFill.mcFillRed.width	= 1;
	mcVideoControls.mcProgressFill.mcFillGrey.width	= 1;

	// set time and duration label
	mcVideoControls.lblTimeDuration.htmlText		= "<span style="color: #ffffff;">00:00</span> / 00:00&#8243;;

	// add global event listener when mouse is released
	stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);

	// add fullscreen listener
	stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullscreen);

	// add event listeners to all buttons
	mcVideoControls.btnPause.addEventListener(MouseEvent.CLICK, pauseClicked);
	mcVideoControls.btnPlay.addEventListener(MouseEvent.CLICK, playClicked);
	mcVideoControls.btnStop.addEventListener(MouseEvent.CLICK, stopClicked);
	mcVideoControls.btnNext.addEventListener(MouseEvent.CLICK, playNext);
	mcVideoControls.btnPrevious.addEventListener(MouseEvent.CLICK, playPrevious);
	mcVideoControls.btnMute.addEventListener(MouseEvent.CLICK, muteClicked);
	mcVideoControls.btnUnmute.addEventListener(MouseEvent.CLICK, unmuteClicked);
	mcVideoControls.btnFullscreenOn.addEventListener(MouseEvent.CLICK, fullscreenOnClicked);
	mcVideoControls.btnFullscreenOff.addEventListener(MouseEvent.CLICK, fullscreenOffClicked);

	mcVideoControls.btnVolumeBar.addEventListener(MouseEvent.MOUSE_DOWN, volumeScrubberClicked);
	mcVideoControls.mcVolumeScrubber.btnVolumeScrubber.addEventListener(MouseEvent.MOUSE_DOWN, volumeScrubberClicked);
	mcVideoControls.btnProgressBar.addEventListener(MouseEvent.MOUSE_DOWN, progressScrubberClicked);
	mcVideoControls.mcProgressScrubber.btnProgressScrubber.addEventListener(MouseEvent.MOUSE_DOWN, progressScrubberClicked);

	mcVideoControls.mcVideoDescription.btnDescription.addEventListener(MouseEvent.MOUSE_OVER, startDescriptionScroll);
	mcVideoControls.mcVideoDescription.btnDescription.addEventListener(MouseEvent.MOUSE_OUT, stopDescriptionScroll);

	// create timer for updating all visual parts of player and add
	// event listener
	tmrDisplay = new Timer(DISPLAY_TIMER_UPDATE_DELAY);
	tmrDisplay.addEventListener(TimerEvent.TIMER, updateDisplay);

	// create a new net connection, add event listener and connect
	// to null because we don&#8217;t have a media server
	ncConnection = new NetConnection();
	ncConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	ncConnection.connect(null);

	// create a new netstream with the net connection, add event
	// listener, set client to this for handling meta data and
	// set the buffer time to the value from the constant
	nsStream = new NetStream(ncConnection);
	nsStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	nsStream.client = this;
	nsStream.bufferTime = BUFFER_TIME;

	// attach net stream to video object on the stage
	vidDisplay.attachNetStream(nsStream);
	// set the smoothing value from the constant
	vidDisplay.smoothing = SMOOTHING;

	// set default volume and get volume from shared object if available
	var tmpVolume:Number = DEFAULT_VOLUME;
	if(shoVideoPlayerSettings.data.playerVolume != undefined) {
		tmpVolume = shoVideoPlayerSettings.data.playerVolume;
		intLastVolume = tmpVolume;
	}
	// update volume bar and set volume
	mcVideoControls.mcVolumeScrubber.x = (53 * tmpVolume) + 318;
	mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 371 + 53;
	setVolume(tmpVolume);

	// create new request for loading the playlist xml, add an event listener
	// and load it
	urlRequest = new URLRequest(strSource);
	urlLoader = new URLLoader();
	urlLoader.addEventListener(Event.COMPLETE, playlistLoaded);
	urlLoader.load(urlRequest);
}
function playClicked(e:MouseEvent):void {
	// check&#8217;s, if the flv has already begun
	// to download. if so, resume playback, else
	// load the file
	if(!bolLoaded) {
		nsStream.play(strSource);
		bolLoaded = true;
	}
	else{
		nsStream.resume();
	}

	vidDisplay.visible = true;

	// switch play/pause visibility
	mcVideoControls.btnPause.visible	= true;
	mcVideoControls.btnPlay.visible		= false;
}

function pauseClicked(e:MouseEvent):void {
	// pause video
	nsStream.pause();

	// switch play/pause visibility
	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}

function stopClicked(e:MouseEvent):void {
	// calls stop function
	stopVideoPlayer();
}

function muteClicked(e:MouseEvent):void {
	// set volume to 0
	setVolume(0);

	// update scrubber and fill position/width
	mcVideoControls.mcVolumeScrubber.x				= 318;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= 1;
}

function unmuteClicked(e:MouseEvent):void {
	// set volume to last used value or DEFAULT_VOLUME if last volume is zero
	var tmpVolume:Number = intLastVolume == 0 ? DEFAULT_VOLUME : intLastVolume
	setVolume(tmpVolume);

	// update scrubber and fill position/width
	mcVideoControls.mcVolumeScrubber.x = (53 * tmpVolume) + 318;
	mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 371 + 53;
}

function volumeScrubberClicked(e:MouseEvent):void {
	// set volume scrub flag to true
	bolVolumeScrub = true;

	// start drag
	mcVideoControls.mcVolumeScrubber.startDrag(true, new Rectangle(318, 19, 53, 0)); // NOW TRUE
}

function progressScrubberClicked(e:MouseEvent):void {
	// set progress scrub flag to true
	bolProgressScrub = true;

	// start drag
	mcVideoControls.mcProgressScrubber.startDrag(true, new Rectangle(0, 2, 432, 0)); // NOW TRUE
}

function mouseReleased(e:MouseEvent):void {
	// set progress/volume scrub to false
	bolVolumeScrub		= false;
	bolProgressScrub	= false;

	// stop all dragging actions
	mcVideoControls.mcProgressScrubber.stopDrag();
	mcVideoControls.mcVolumeScrubber.stopDrag();

	// update progress/volume fill
	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= mcVideoControls.mcVolumeScrubber.x - 371 + 53;

	// save the volume if it&#8217;s greater than zero
	if((mcVideoControls.mcVolumeScrubber.x - 318) / 53 &gt; 0)
		intLastVolume = (mcVideoControls.mcVolumeScrubber.x - 318) / 53;
}

function updateDisplay(e:TimerEvent):void {
	// checks, if user is scrubbing. if so, seek in the video
	// if not, just update the position of the scrubber according
	// to the current time
	if(bolProgressScrub)
		nsStream.seek(Math.round(mcVideoControls.mcProgressScrubber.x * objInfo.duration / 432))
	else
		mcVideoControls.mcProgressScrubber.x = nsStream.time * 432 / objInfo.duration; 

	// set time and duration label
	mcVideoControls.lblTimeDuration.htmlText		= &#8220;<span style="color: #ffffff;">&#8221; + formatTime(nsStream.time) + &#8220;</span> / &#8221; + formatTime(objInfo.duration);

	// update the width from the progress bar. the grey one displays
	// the loading progress
	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcProgressFill.mcFillGrey.width	= nsStream.bytesLoaded * 438 / nsStream.bytesTotal;

	// update volume and the red fill width when user is scrubbing
	if(bolVolumeScrub) {
		setVolume((mcVideoControls.mcVolumeScrubber.x - 318) / 53);
		mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 371 + 53;
	}

	// chech if user is currently hovering over description label
	if(bolDescriptionHover) {
		// check in which direction we&#8217;re currently moving
		if(bolDescriptionHoverForward) {
			// move to the left and check if we&#8217;ve shown everthing
			mcVideoControls.mcVideoDescription.lblDescription.x -= 0.1;
			if(mcVideoControls.mcVideoDescription.lblDescription.textWidth - 133 &lt;= Math.abs(mcVideoControls.mcVideoDescription.lblDescription.x))
				bolDescriptionHoverForward = false;
		} else {
			// move to the right and check if we&#8217;re back to normal
			mcVideoControls.mcVideoDescription.lblDescription.x += 0.1;
			if(mcVideoControls.mcVideoDescription.lblDescription.x &gt;= 0)
				bolDescriptionHoverForward = true;
		}
	} else {
		// reset label position and direction variable
		mcVideoControls.mcVideoDescription.lblDescription.x = 0;
		bolDescriptionHoverForward = true;
	}
}

function onMetaData(info:Object):void {
	// stores meta data in a object
	objInfo = info;

	// now we can start the timer because
	// we have all the neccesary data
	if(!tmrDisplay.running)
		tmrDisplay.start();
}

function netStatusHandler(event:NetStatusEvent):void {
	// handles net status events
	switch (event.info.code) {
		// trace a messeage when the stream is not found
		case &#8220;NetStream.Play.StreamNotFound&#8221;:
			trace(&#8221;Stream not found: &#8221; + strSource);
		break;
		// when the video reaches its end, we check if there are
		// more video left or stop the player
		case &#8220;NetStream.Play.Stop&#8221;:
			if(intActiveVid + 1 &lt; xmlPlaylist..vid.length())
				playNext();
			else
				stopVideoPlayer();
		break;
	}
}

function stopVideoPlayer():void {
	// pause netstream, set time position to zero
	nsStream.pause();
	nsStream.seek(0);

	// in order to clear the display, we need to
	// set the visibility to false since the clear
	// function has a bug
	vidDisplay.visible					= false;

	// switch play/pause button visibility
	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}

function setVolume(intVolume:Number = 0):void {
	// create soundtransform object with the volume from
	// the parameter
	var sndTransform		= new SoundTransform(intVolume);
	// assign object to netstream sound transform object
	nsStream.soundTransform	= sndTransform;

	// hides/shows mute and unmute button according to the
	// volume
	if(intVolume &gt; 0) {
		mcVideoControls.btnMute.visible		= true;
		mcVideoControls.btnUnmute.visible	= false;
	} else {
		mcVideoControls.btnMute.visible		= false;
		mcVideoControls.btnUnmute.visible	= true;
	}

	// store the volume in the flash cookie
	shoVideoPlayerSettings.data.playerVolume = intVolume;
	shoVideoPlayerSettings.flush();
}

function formatTime(t:int):String {
	// returns the minutes and seconds with leading zeros
	// for example: 70 returns 01:10
	var s:int = Math.round(t);
	var m:int = 0;
	if (s &gt; 0) {
		while (s &gt; 59) {
			m++; s -= 60;
		}
		return String((m &lt; 10 ? &#8220;0&#8243; : &#8220;&#8221;) + m + &#8220;:&#8221; + (s &lt; 10 ? &#8220;0&#8243; : &#8220;&#8221;) + s);
	} else {
		return &#8220;00:00&#8243;;
	}
}

function fullscreenOnClicked(e:MouseEvent):void {
	// go to fullscreen mode
	stage.displayState = StageDisplayState.FULL_SCREEN;
}

function fullscreenOffClicked(e:MouseEvent):void {
	// go to back to normal mode
	stage.displayState = StageDisplayState.NORMAL;
}

function onFullscreen(e:FullScreenEvent):void {
	// check if we&#8217;re entering or leaving fullscreen mode
    if (e.fullScreen) {
		// switch fullscreen buttons
        mcVideoControls.btnFullscreenOn.visible = false;
		mcVideoControls.btnFullscreenOff.visible = true;

		// bottom center align controls
		mcVideoControls.x = (Capabilities.screenResolutionX - 440) / 2;
		mcVideoControls.y = (Capabilities.screenResolutionY - 33);

		// size up video display
		vidDisplay.height 	= (Capabilities.screenResolutionY - 33);
		vidDisplay.width 	= vidDisplay.height * 4 / 3;
		vidDisplay.x		= (Capabilities.screenResolutionX - vidDisplay.width) / 2;
    } else {
		// switch fullscreen buttons
        mcVideoControls.btnFullscreenOn.visible = true;
		mcVideoControls.btnFullscreenOff.visible = false;

		// reset controls position
		mcVideoControls.x = 0;
		mcVideoControls.y = 330;

		// reset video display
		vidDisplay.y = 0;
		vidDisplay.x = 0;
		vidDisplay.width = 440;
		vidDisplay.height = 330;
    }
}

function playlistLoaded(e:Event):void {
	// create new xml with loaded data from loader
	xmlPlaylist = new XML(urlLoader.data);

	// set source of the first video but don&#8217;t play it
	playVid(0, false)

	// show controls
	mcVideoControls.visible = true;
}

function playVid(intVid:int = 0, bolPlay = true):void {
	if(bolPlay) {
		// stop timer
		tmrDisplay.stop();

		// play requested video
		nsStream.play(String(xmlPlaylist..vid[intVid].@src));

		// switch button visibility
		mcVideoControls.btnPause.visible	= true;
		mcVideoControls.btnPlay.visible		= false;
	} else {
		strSource = xmlPlaylist..vid[intVid].@src;
	}

	// show video display
	vidDisplay.visible					= true;

	// reset description label position and assign new description
	mcVideoControls.mcVideoDescription.lblDescription.x = 0;
	mcVideoControls.mcVideoDescription.lblDescription.htmlText = (intVid + 1) + &#8220;. <span style="color: #ffffff;">&#8221; + String(xmlPlaylist..vid[intVid].@desc) + &#8220;</span>&#8220;;

	// update active video number
	intActiveVid = intVid;
}

function playNext(e:MouseEvent = null):void {
	// check if there are video left to play and play them
	if(intActiveVid + 1 &lt; xmlPlaylist..vid.length())
		playVid(intActiveVid + 1);

}

function playPrevious(e:MouseEvent = null):void {
	// check if we&#8217;re not and the beginning of the playlist and go back
	if(intActiveVid - 1 &gt;= 0)
		playVid(intActiveVid - 1);
}

function startDescriptionScroll(e:MouseEvent):void {
	// check if description label is too long and we need to enable scrolling
	if(mcVideoControls.mcVideoDescription.lblDescription.textWidth &gt; 138)
		bolDescriptionHover = true;
}

function stopDescriptionScroll(e:MouseEvent):void {
	// disable scrolling
	bolDescriptionHover = false;
}

// ###############################
// ############# INIT PLAYER
// ###############################
initVideoPlayer();</pre>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" onmouseover="a2a_show_dropdown(this)" onmouseout="a2a_onMouseOut_delay()" href="http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Expanding%20the%20AS3%20Videoplayer&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fvideo%2Fexpanding-the-as3-videoplayer%2F" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=Expanding%20the%20AS3%20Videoplayer&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fvideo%2Fexpanding-the-as3-videoplayer%2F');"><img src="http://www.thetechlabs.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p><img src="http://feedproxy.google.com/~r/TheTechLabs_interfaces/~4/EgEFFZ6188o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.thetechlabs.com/video/expanding-the-as3-videoplayer/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.thetechlabs.com/video/expanding-the-as3-videoplayer/</feedburner:origLink></item>
		<item>
		<title>How to build a AS3 Videoplayer</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/OWNpvZJciPE/</link>
		<comments>http://www.thetechlabs.com/video/how-to-build-a-as3-videoplayer/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 22:21:58 +0000</pubDate>
		<dc:creator>Rafael Nuenlist</dc:creator>
		
		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[Video]]></category>

		<category><![CDATA[adobe flash]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[how-to]]></category>

		<category><![CDATA[mute]]></category>

		<category><![CDATA[pause]]></category>

		<category><![CDATA[play]]></category>

		<category><![CDATA[Sound]]></category>

		<category><![CDATA[stop]]></category>

		<category><![CDATA[streaming]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[volume]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=86</guid>
		<description><![CDATA[<p>Today we explain you how to create a videoplayer with some basic features like this one.<br />
These are: - Play/Pause - Stop - Preloading - Scrubbing - Volume handling There will be another tutorial, which will extend this player. So be sure to check it out.<br />
Requirements<br />
Adobe Flash CS3<br />
Try / Buy<br />
Source Files<br />
Download<br />
Constants<br />
As always, we begin with setting [...]</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/flash/">Flash</a> by Rafael Nuenlist <a href="http://www.thetechlabs.com/video/how-to-build-a-as3-videoplayer/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>Today we explain you how to create a videoplayer with some basic features <a title="View Demo" href="http://www.thetechlabs.com/tutorials/files/flash/rnunlist/videoplayer/videoplayer.prt1.html"  target="_blank">like this one.</a></p>
<p>These are: - Play/Pause - Stop - Preloading - Scrubbing - Volume handling There will be another tutorial, which will extend this player. So be sure to check it out.</p>
<h3>Requirements</h3>
<p><strong>Adobe Flash CS3</strong></p>
<p><a title="Try / buy" onclick="javascript:pageTracker._trackPageview('/outbound/article/http://www.adobe.com/products/flash/');" href="http://www.adobe.com/products/flash/" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.adobe.com/products/flash/');" target="_blank">Try / Buy</a></p>
<p><strong>Source Files</strong></p>
<p><a title="Download Source Files" onclick="javascript:pageTracker._trackPageview('/downloads/tutorials/files/flash/fcarrera/flickrsearchengine/flickrsearchengine_sfiles.zip');" href="http://thetechlabs.com/tutorials/files/flash/rnunlist/videoplayer_prt1.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flash/rnunlist/videoplayer_prt1.zip');" target="_self">Download</a></p>
<h3>Constants</h3>
<p>As always, we begin with setting the constants. The BUFFER_TIME constant stores the time to buffer for the video in seconds. This one will later be assigned to the netstream object</p>
<pre>const BUFFER_TIME:Number				= 8;</pre>
<p>DEFAULT_VOLUME holds the start volume when the player starts</p>
<pre>const DEFAULT_VOLUME:Number				= 0.6;</pre>
<p>Our player has a timer, that updates all the visual parts. We store the update delay in milliseconds in a constant.</p>
<pre>const DISPLAY_TIMER_UPDATE_DELAY:int			= 10;</pre>
<p>To make the video a bit smoother, we can the the Video.smoothing variable to true. This may slow down old computers. If you want to deactive the smoothing on runtime, just open the html file in the zip file, right click on the video player and choose low for the quality. This way the smoothing will automaticaly be deactivated by the flash player.</p>
<pre>const SMOOTHING:Boolean	= true;</pre>
<h3>Variables</h3>
<p>Let&#8217;s move on with the variables. We need to know, if the flv has been loaded when clicking the play button in order to load it or just play the video.</p>
<pre>var bolLoaded:Boolean	= false;</pre>
<p>For the timer function we need to know, if we&#8217;re currently scrubbing the volume or the porgress bar.</p>
<pre>var bolVolumeScrub:Boolean	= false;
var bolProgressScrub:Boolean	 = false;</pre>
<p>Our player has also a mute/unmute button. So, we need to store the last used volume. Like this when you click on unmute, the scrubber will jump back to it&#8217;s previous position as the volume does. This value is always greater than zero. We asign the value from DEFAULT_VOLUME.</p>
<pre>var intLastVolume:Number				= DEFAULT_VOLUME;</pre>
<p>Then we need to have a net connection object for net stream and of course also a net stream object.</p>
<pre>var ncConnection:NetConnection;
var nsStream:NetStream;</pre>
<p>To store the received meta data from the flv file, we create an object</p>
<pre>var objInfo:Object;</pre>
<p>You can change your url to the flv file here. We just set it to the sample movie that&#8217;s in the same folder as the swf.</p>
<pre>var strSource:String = "hancock-tsr2_h480p.flv";</pre>
<p>And last of all, we create a timer object for updating the stuff from the player.</p>
<pre>var tmrDisplay:Timer;</pre>
<h3>Functions</h3>
<p>Now we need to initialize our player. First of all, we hide the unmute and pause button. Then we set the width of the progress and preload fill to 1.Our next step is adding a global eventlistener when the mouse button is released and adding event listeners to all buttons. Then we create ourtimer object for<br />
updating all parts of the player and add the event listener. Next we create a new net connection, add the event listener and connect it to null because we don&#8217;t have a media server. The net stream object needs the net connection for initizalizing. Once we have our net stream object ready, we add the event listener, set the client property to this for handling the meta data and set buffer tim eto the value from the constant BUFFER_TIME. Then we attach the net stream to the video object on the stage and set the smoothing property to the value from the constant SMOOTHING. Last of all we set the default volume to the value from the constant DEFAULT_VOLUME. Note that only values from zero to one are allowed.</p>
<pre>function initVideoPlayer():void {
	mcVideoControls.btnUnmute.visible	= false;
	mcVideoControls.btnPause.visible	= false;

	mcVideoControls.mcProgressFill.mcFillRed.width	= 1;
	mcVideoControls.mcProgressFill.mcFillGrey.width = 1;

	stage.addEventListener( MouseEvent.MOUSE_UP, mouseReleased);

	mcVideoControls.btnPause.addEventListener(MouseEvent.CLICK, pauseClicked);
	mcVideoControls.btnPlay.addEventListener(MouseEvent.CLICK, playClicked);
	mcVideoControls.btnStop.addEventListener(MouseEvent.CLICK, stopClicked);
	mcVideoControls.btnMute.addEventListener(MouseEvent.CLICK, muteClicked);
	mcVideoControls.btnUnmute.addEventListener(MouseEvent.CLICK, unmuteClicked);
	mcVideoControls.mcVolumeScrubber.btnVolumeScrubber.addEventListener(MouseEvent.MOUSE_DOWN, volumeScrubberClicked);
	mcVideoControls.mcProgressScrubber.btnProgressScrubber.addEventListener(MouseEvent.MOUSE_DOWN, progressScrubberClicked);

	tmrDisplay = new Timer(DISPLAY_TIMER_UPDATE_DELAY);
	tmrDisplay.addEventListener(TimerEvent.TIMER, updateDisplay);

	ncConnection = new NetConnection();
	ncConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	ncConnection.connect(null);

	nsStream = new NetStream(ncConnection);
	nsStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	nsStream.client = this;
	nsStream.bufferTime = BUFFER_TIME;

	vidDisplay.attachNetStream(nsStream);
	vidDisplay.smoothing = SMOOTHING;

	mcVideoControls.mcVolumeScrubber.x		= (53 * DEFAULT_VOLUME) + 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= mcVideoControls.mcVolumeScrubber.x - 394 + 53;
	setVolume(DEFAULT_VOLUME);
}</pre>
<p>The most important part is now done. We&#8217;ve set all variables and added all event listeners. We&#8217;re now going to go through all button event listeners. When the user hit&#8217;s the play button, we need to check, if the flv download has already begun. If that&#8217;s the case, we resume the playback with the NetStream.resume() function. If not, we call the play() function and add the source to the flv file as the parameter.<br />
Then we show the video display object that&#8217;s on the stage. And finaly we switch the pause/play visibility.</p>
<pre>function playClicked(e:MouseEvent):void {
	if(!bolLoaded) {
		nsStream.play(strSource);
		bolLoaded = true;
	} else {
		nsStream.resume();
	}

	vidDisplay.visible			= true;

	mcVideoControls.btnPause.visible	= true;
	mcVideoControls.btnPlay.visible		= false;
}</pre>
<p>The pause button only calls the pause() function from the net stream object and switches the pause/play visibility.</p>
<pre>function pauseClicked(e:MouseEvent):void {
	nsStream.pause();

	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}</pre>
<p>When the user click&#8217;s the play button, the stopVideoPlayer() function will be called. We&#8217;ll explain this function below.</p>
<pre>function stopClicked(e:MouseEvent):void {
	stopVideoPlayer();
}</pre>
<p>The mute button sets the volume to zero and updates the volume scrubber and fill position/width.</p>
<pre>function muteClicked(e:MouseEvent):void {
	setVolume(0);

	mcVideoControls.mcVolumeScrubber.x		= 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= 1;
}</pre>
<p>The unmute button sets the volume to the last used volume and updates the volume scrubber and fill position/width.</p>
<pre>function unmuteClicked(e:MouseEvent):void {
	setVolume(intLastVolume);

	mcVideoControls.mcVolumeScrubber.x		= (53 * intLastVolume) + 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= mcVideoControls.mcVolumeScrubber.x - 394 + 53;
}</pre>
<p>When the volume scrubber is clicked, the scrub flag will be set to true. Then we start dragging it withing the boundings that are described as a rectangle.<br />
Exactly the same goes for the progress scrubber except that we&#8217;re setting another flag variable and bounding.</p>
<pre>function volumeScrubberClicked(e:MouseEvent):void {
	bolVolumeScrub = true;

	mcVideoControls.mcVolumeScrubber.startDrag(false, new Rectangle(341, 19, 53, 0));
}

function progressScrubberClicked(e:MouseEvent):void {
	bolProgressScrub = true;

	mcVideoControls.mcProgressScrubber.startDrag(false, new Rectangle(0, 2, 432, 0));
}</pre>
<p>Last of all, we have our mouseReleased() handler. This function is needed for knowing, when the user stops the scrubbing. First, we set the progress/volume scrub flag to false. Then we stop all dragging actions and update the width of the progress/volume fill. And if the volume is greater than zero, we store it in the variable intLastVolume.</p>
<pre>function mouseReleased(e:MouseEvent):void {
	bolVolumeScrub		= false;
	bolProgressScrub	= false;

	mcVideoControls.mcProgressScrubber.stopDrag();
	mcVideoControls.mcVolumeScrubber.stopDrag();

	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= mcVideoControls.mcVolumeScrubber.x - 394 + 53;

	if((mcVideoControls.mcVolumeScrubber.x - 341) / 53 &gt; 0)
		intLastVolume = (mcVideoControls.mcVolumeScrubber.x - 341) / 53;
}</pre>
<p>The updateDisplay() function will be called by the timer object 100 times a second. If you want, you can decrease this value by increasing the value from the constant DISPLAY_TIMER_UPDATE_DELAY.<br />
First of all, we check if the user is scrubbing on the progress bar. If that&#8217;s the case, we seek in the video. If not, we just update the position of the scrubber according to the current time.<br />
Then we set the time and duration label. We format the values with the function formatTime() which we explain later.<br />
Now we update the width from the progress bar. The grey one displays the loading progress while the red one shows the progress from the video.<br />
Last of all we update the volume and the red fill width when the user is scrubbing.</p>
<pre>function updateDisplay(e:TimerEvent):void {
	if(bolProgressScrub)
		nsStream.seek(Math.round(mcVideoControls.mcProgressScrubber.x * objInfo.duration / 432))
	else
		mcVideoControls.mcProgressScrubber.x = nsStream.time * 432 / objInfo.duration; 

	mcVideoControls.lblTimeDuration.htmlText 	= "<span style="color: #ffffff;">&#8221; + formatTime(nsStream.time) + &#8220;</span> / &#8221; + formatTime(objInfo.duration);

	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcProgressFill.mcFillGrey.width	= nsStream.bytesLoaded * 438 / nsStream.bytesTotal;

	if(bolVolumeScrub) {
		setVolume((mcVideoControls.mcVolumeScrubber.x - 341) / 53);
		mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 394 + 53;
	}
}</pre>
<p>The onMetaDataFunction will be called as soon as the net stream object gets the meta stuff from the flv file. We store these informations in a object. Now can start the timer object because we have all the neccesary data.</p>
<pre>function onMetaData(info:Object):void {
	objInfo = info;

	tmrDisplay.start();
}</pre>
<p>Once a net status event will be fired, the netStatusHandler() function will be called. The event holds the info code of the event type. We only need to handle NetStream.Play.StreamNotFound in case the stream is not found and NetStream.Play.Stop to know, when the video reached its end to stop the player with the stopVideoPlayer() function.</p>
<pre>function netStatusHandler(event:NetStatusEvent):void {
	switch (event.info.code) {
		case "NetStream.Play.StreamNotFound":
			trace("Stream not found: " + strSource);
		break;
		case "NetStream.Play.Stop":
			stopVideoPlayer();
		break;
	}
}</pre>
<p>There are 2 ways to stop the playback: One is clicking the stop button, the other is reaching the end of the video. That&#8217;s the reason why we&#8217;ve put this in a function.<br />
First we pause the netstream and set the playback position to zero. In order to clear the display where the last frame of the video will be shown we need to set the visibility to false. We can&#8217;t use the Video.clear() function since it has a bug. But this one has already been reported to adobe. This workaround works fine. Finaly we switch the play/button visibility.</p>
<pre>function stopVideoPlayer():void {
	nsStream.pause();
	nsStream.seek(0);

	vidDisplay.visible			= false;

	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}</pre>
<p>To set the volume of the video we use the setVolume() function.<br />
First we create a soundtransform object with the value from the parameter. Then we assign this object to nsStream.soundTransform.<br />
And we hide or show the mute and unmute according to the volume. If it&#8217;s greater than zero, we show the mute button and vice versa.</p>
<pre>function setVolume(intVolume:Number = 0):void {
	var sndTransform	= new SoundTransform(intVolume);
	nsStream.soundTransform	= sndTransform;

	if(intVolume &gt; 0) {
		mcVideoControls.btnMute.visible		= true;
		mcVideoControls.btnUnmute.visible	= false;
	} else {
		mcVideoControls.btnMute.visible		= false;
		mcVideoControls.btnUnmute.visible	= true;
	}
}</pre>
<p>The last function formatTime() is used to format the seconds to the format mm:ss.</p>
<pre>function formatTime(t:int):String {
	var s:int = Math.round(t);
	var m:int = 0;
	if (s &gt; 0) {
		while (s &gt; 59) {
			m++;
			s -= 60;
		}
		return String((m &lt; 10 ? "0" : "") + m + ":" + (s &lt; 10 ? "0" : "") + s);
	} else {
		return "00:00";
	}
}</pre>
<h3>Call init function</h3>
<p>The only thing left to do is calling the init function for the player.</p>
<pre>initVideoPlayer();</pre>
<p>We hope you liked this tutorial. If you have any question don&#8217;t hesitate to ask. Also we&#8217;ve already mentioned be sure to check back for the next part that will be coming soon.</p>
<h3>Full code with comments</h3>
<pre>// ##########################
// ############# CONSTANTS
// ##########################

// time to buffer for the video in sec.
const BUFFER_TIME:Number				= 8;
// start volume when initializing player
const DEFAULT_VOLUME:Number				= 0.6;
// update delay in milliseconds.
const DISPLAY_TIMER_UPDATE_DELAY:int	= 10;
// smoothing for video. may slow down old computers
const SMOOTHING:Boolean					= true;

// ##########################
// ############# VARIABLES
// ##########################

// flag for knowing if flv has been loaded
var bolLoaded:Boolean					= false;
// flag for volume scrubbing
var bolVolumeScrub:Boolean				= false;
// flag for progress scrubbing
var bolProgressScrub:Boolean			= false;
// holds the last used volume, but never 0
var intLastVolume:Number				= DEFAULT_VOLUME;
// net connection object for net stream
var ncConnection:NetConnection;
// net stream object
var nsStream:NetStream;
// object holds all meta data
var objInfo:Object;
// url to flv file
var strSource:String					= "hancock-tsr2_h480p.flv";
// timer for updating player (progress, volume...)
var tmrDisplay:Timer;

// ##########################
// ############# FUNCTIONS
// ##########################

// sets up the player
function initVideoPlayer():void {
	// hide buttons
	mcVideoControls.btnUnmute.visible	= false;
	mcVideoControls.btnPause.visible	= false;

	// set the progress/preload fill width to 1
	mcVideoControls.mcProgressFill.mcFillRed.width = 1;
	mcVideoControls.mcProgressFill.mcFillGrey.width = 1;

	// add global event listener when mouse is released
	stage.addEventListener( MouseEvent.MOUSE_UP, mouseReleased);

	// add event listeners to all buttons
	mcVideoControls.btnPause.addEventListener(MouseEvent.CLICK, pauseClicked);
	mcVideoControls.btnPlay.addEventListener(MouseEvent.CLICK, playClicked);
	mcVideoControls.btnStop.addEventListener(MouseEvent.CLICK, stopClicked);
	mcVideoControls.btnMute.addEventListener(MouseEvent.CLICK, muteClicked);
	mcVideoControls.btnUnmute.addEventListener(MouseEvent.CLICK, unmuteClicked);
	mcVideoControls.mcVolumeScrubber.btnVolumeScrubber.addEventListener(MouseEvent.MOUSE_DOWN, volumeScrubberClicked);
	mcVideoControls.mcProgressScrubber.btnProgressScrubber.addEventListener(MouseEvent.MOUSE_DOWN, progressScrubberClicked);

	// create timer for updating all visual parts of player and add
	// event listener
	tmrDisplay = new Timer(DISPLAY_TIMER_UPDATE_DELAY);
	tmrDisplay.addEventListener(TimerEvent.TIMER, updateDisplay);

	// create a new net connection, add event listener and connect
	// to null because we don't have a media server
	ncConnection = new NetConnection();
	ncConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	ncConnection.connect(null);

	// create a new netstream with the net connection, add event
	// listener, set client to this for handling meta data and
	// set the buffer time to the value from the constant
	nsStream = new NetStream(ncConnection);
	nsStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
	nsStream.client = this;
	nsStream.bufferTime = BUFFER_TIME;

	// attach net stream to video object on the stage
	vidDisplay.attachNetStream(nsStream);
	// set the smoothing value from the constant
	vidDisplay.smoothing = SMOOTHING;

	// set default volume
	mcVideoControls.mcVolumeScrubber.x = (52 * DEFAULT_VOLUME) + 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 394 + 52;
	setVolume(DEFAULT_VOLUME);
}

function playClicked(e:MouseEvent):void {
	// check's, if the flv has already begun
	// to download. if so, resume playback, else
	// load the file
	if(!bolLoaded) {
		nsStream.play(strSource);
		bolLoaded = true;
	}
	else{
		nsStream.resume();
	}

	// show video display
	vidDisplay.visible					= true;

	// switch play/pause visibility
	mcVideoControls.btnPause.visible	= true;
	mcVideoControls.btnPlay.visible		= false;
}

function pauseClicked(e:MouseEvent):void {
	// pause video
	nsStream.pause();

	// switch play/pause visibility
	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}

function stopClicked(e:MouseEvent):void {
	// calls stop function
	stopVideoPlayer();
}

function muteClicked(e:MouseEvent):void {
	// set volume to 0
	setVolume(0);

	// update scrubber and fill position/width
	mcVideoControls.mcVolumeScrubber.x				= 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= 1;
}

function unmuteClicked(e:MouseEvent):void {
	// set volume to last used value
	setVolume(intLastVolume);

	// update scrubber and fill position/width
	mcVideoControls.mcVolumeScrubber.x = (53 * intLastVolume) + 341;
	mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 394 + 53;
}

function volumeScrubberClicked(e:MouseEvent):void {
	// set volume scrub flag to true
	bolVolumeScrub = true;

	// start drag
	mcVideoControls.mcVolumeScrubber.startDrag(false, new Rectangle(341, 19, 53, 0));
}

function progressScrubberClicked(e:MouseEvent):void {
	// set progress scrub flag to true
	bolProgressScrub = true;

	// start drag
	mcVideoControls.mcProgressScrubber.startDrag(false, new Rectangle(0, 2, 432, 0));
}

function mouseReleased(e:MouseEvent):void {
	// set progress/volume scrub to false
	bolVolumeScrub		= false;
	bolProgressScrub	= false;

	// stop all dragging actions
	mcVideoControls.mcProgressScrubber.stopDrag();
	mcVideoControls.mcVolumeScrubber.stopDrag();

	// update progress/volume fill
	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcVolumeFill.mcFillRed.width	= mcVideoControls.mcVolumeScrubber.x - 394 + 53;

	// save the volume if it's greater than zero
	if((mcVideoControls.mcVolumeScrubber.x - 341) / 53 &gt; 0)
		intLastVolume = (mcVideoControls.mcVolumeScrubber.x - 341) / 53;
}

function updateDisplay(e:TimerEvent):void {
	// checks, if user is scrubbing. if so, seek in the video
	// if not, just update the position of the scrubber according
	// to the current time
	if(bolProgressScrub)
		nsStream.seek(Math.round(mcVideoControls.mcProgressScrubber.x * objInfo.duration / 432))
	else
		mcVideoControls.mcProgressScrubber.x = nsStream.time * 432 / objInfo.duration; 

	// set time and duration label
	mcVideoControls.lblTimeDuration.htmlText		= "<span style="color: #ffffff;">&#8221; + formatTime(nsStream.time) + &#8220;</span> / &#8221; + formatTime(objInfo.duration);

	// update the width from the progress bar. the grey one displays
	// the loading progress
	mcVideoControls.mcProgressFill.mcFillRed.width	= mcVideoControls.mcProgressScrubber.x + 5;
	mcVideoControls.mcProgressFill.mcFillGrey.width	= nsStream.bytesLoaded * 438 / nsStream.bytesTotal;

	// update volume and the red fill width when user is scrubbing
	if(bolVolumeScrub) {
		setVolume((mcVideoControls.mcVolumeScrubber.x - 341) / 53);
		mcVideoControls.mcVolumeFill.mcFillRed.width = mcVideoControls.mcVolumeScrubber.x - 394 + 53;
	}
}

function onMetaData(info:Object):void {
	// stores meta data in a object
	objInfo = info;

	// now we can start the timer because
	// we have all the neccesary data
	tmrDisplay.start();
}

function netStatusHandler(event:NetStatusEvent):void {
	// handles net status events
	switch (event.info.code) {
		// trace a messeage when the stream is not found
		case &#8220;NetStream.Play.StreamNotFound&#8221;:
			trace(&#8221;Stream not found: &#8221; + strSource);
		break;

		// when the video reaches its end, we stop the player
		case &#8220;NetStream.Play.Stop&#8221;:
			stopVideoPlayer();
		break;
	}
}

function stopVideoPlayer():void {
	// pause netstream, set time position to zero
	nsStream.pause();
	nsStream.seek(0);

	// in order to clear the display, we need to
	// set the visibility to false since the clear
	// function has a bug
	vidDisplay.visible			= false;

	// switch play/pause button visibility
	mcVideoControls.btnPause.visible	= false;
	mcVideoControls.btnPlay.visible		= true;
}

function setVolume(intVolume:Number = 0):void {
	// create soundtransform object with the volume from
	// the parameter
	var sndTransform	= new SoundTransform(intVolume);
	// assign object to netstream sound transform object
	nsStream.soundTransform	= sndTransform;
	// hides/shows mute and unmute button according to the
	// volume
	if(intVolume &gt; 0) {
		mcVideoControls.btnMute.visible		= true;
		mcVideoControls.btnUnmute.visible	= false;
	} else {
		mcVideoControls.btnMute.visible		= false;
		mcVideoControls.btnUnmute.visible	= true;
	}
}

function formatTime(t:int):String {
	// returns the minutes and seconds with leading zeros
	// for example: 70 returns 01:10
	var s:int = Math.round(t);
	var m:int = 0;
	if (s &gt; 0) {
		while (s &gt; 59) {
			m++;
			s -= 60;
		}
		return String((m &lt; 10 ? &#8220;0&#8243; : &#8220;&#8221;) + m + &#8220;:&#8221; + (s &lt; 10 ? &#8220;0&#8243; : &#8220;&#8221;) + s);
	} else {
		return &#8220;00:00&#8243;;
	}
}

// ##########################
// ############# INIT PLAYER
// ##########################
initVideoPlayer();</pre>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" onmouseover="a2a_show_dropdown(this)" onmouseout="a2a_onMouseOut_delay()" href="http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=How%20to%20build%20a%20AS3%20Videoplayer&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fvideo%2Fhow-to-build-a-as3-videoplayer%2F" onclick="javascript:pageTracker._trackPageview('oclicks/http://www.addtoany.com/share_save?sitename=The%20Tech%20Labs&amp;siteurl=http%3A%2F%2Fwww.thetechlabs.com%2F&amp;linkname=How%20to%20build%20a%20AS3%20Videoplayer&amp;linkurl=http%3A%2F%2Fwww.thetechlabs.com%2Fvideo%2Fhow-to-build-a-as3-videoplayer%2F');"><img src="http://www.thetechlabs.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p><img src="http://feedproxy.google.com/~r/TheTechLabs_interfaces/~4/OWNpvZJciPE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.thetechlabs.com/video/how-to-build-a-as3-videoplayer/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.thetechlabs.com/video/how-to-build-a-as3-videoplayer/</feedburner:origLink></item>
		<item>
		<title>Create a AS3 Slideshow with XML</title>
		<link>http://feedproxy.google.com/~r/TheTechLabs_interfaces/~3/-893iznruTA/</link>
		<comments>http://www.thetechlabs.com/xml/create-a-as3-slideshow-with-xml/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 21:02:04 +0000</pubDate>
		<dc:creator>Rafael Nuenlist</dc:creator>
		
		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Interfaces]]></category>

		<category><![CDATA[XML]]></category>

		<category><![CDATA[adobe flash]]></category>

		<category><![CDATA[as3]]></category>

		<category><![CDATA[caurinas engine]]></category>

		<category><![CDATA[loader]]></category>

		<category><![CDATA[slideshow]]></category>

		<category><![CDATA[tweener]]></category>

		<guid isPermaLink="false">http://www.thetechlabs.com/?p=84</guid>
		<description><![CDATA[<p>This tutorial shows you how to create a simple slideshow using as3/flash and xml</p>
<small><em>posted in <a href="http://www.thetechlabs.com/category/flash/">Flash</a> by Rafael Nuenlist <a href="http://www.thetechlabs.com/xml/create-a-as3-slideshow-with-xml/#comments">Leave A Comment</a><br />&copy;2008 <a href="http://www.thetechlabs.com">The Tech Labs</a>. All Rights Reserved.</em></small>]]></description>
			<content:encoded><![CDATA[<p>This tutorial shows you how to create a simple slideshow using as3/flash and xml like <a href="http://www.thetechlabs.com/tutorials/files/flash/rnunlist/slideshow/slideshow.html"  target="_blank">this one</a>.</p>
<p>In order to complete this tutorial you can download the source files <a title="download source files" href="http://www.thetechlabs.com/tutorials/files/flash/rnunlist/slideshow_tut.zip" onclick="javascript:pageTracker._trackPageview('downloads/tutorials/files/flash/rnunlist/slideshow_tut.zip');" target="_self">here.</a></p>
<p>In our xml file, we want to store the path to the slides and a description for each of it. So let&#8217;s take a look at the example file</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;

  &lt;slideshow&gt;

&lt;image src="images/fly.jpg" desc="Fly"/&gt;

&lt;image src="images/mouse.jpg" desc="Computer mouse"/&gt;

&lt;image src="images/country.jpg" desc="Country"/&gt;

&lt;image src="images/rope.jpg" desc="Rope"/&gt;

&lt;image src="images/flower.jpg" desc="Flower"/&gt;

&lt;/slideshow&gt;</pre>
<p>On the first line we describe the version and the encoding of the file. Flash uses UTF-8 for encoding, so we should edit the file in UTF-8 only to avoid character encoding problems.</p>
<p>The first node defines the root node of the xml file and contains further nodes. These are the images with the attributes src and desc. Okey, that&#8217;s how the structure of the xml looks like, let&#8217;s move on to the flash file.<br />
The stage has a movieclip which contains the textfields which will show us the description of the slides, the loading process and the slide count later. Under it you will find a mask layer which masks an empty movieclip, where o