Archive for February, 2008

ActionScript 3 Full Browser XML Slideshow

An ActionScript 3 implementation of my AS2 Full Browser XML Cross fading slideshow.

One of the main areas of concern for me when making this file is memory usage. It is pretty easy if no clean up routines are used to push the Flash player memory usage right up and over 100 megs due to the size of the images that are loaded in. To get around this I’ve used bitmap objects which I dispose of after every image cycle. This keeps memory usage to the bare minimum and frees up memory from Flash player instantly, rather than waiting around for the garbage collector to do its thing. If the bitmap approach is ditched and just a pure object deletion approach is used the garbage collector will keep the memory usage of this example down around 40-50 megs, with peaks up to 70 and lows of around 25. With the bitmap approach coupled with the object deletion memory peaks at around 30 (depending on image size) and drops down to lows of 15. Much better I think. This class attempts to keep memory usage down by creating bitmapdata objects from the loaded images. It then runs a routine to keep track of each bitmap loaded so that they can be removed when no longer needed. At most there are only ever two bitmaps in memory. As soon as a new slide is fully displayed, the old slide is removed and all vars pointing to it set to null. Memory usage stays fairly low using this approach, around 20 megs or so depending on the size of the images loaded in.

The slideshow supports a clean up routine, that deletes all objects and disposes of the current bitmap objects. The slideshow dispatches a Loaded, Beginning Load and progress event. Along with various other utility events related to changing slideshow settings.

Purpose and Intent
This class is designed for creating fullscreen background images that can be set to change or transition in the same manner as a traditional slideshow. It is however not really intended as a stand alone slideshow and as a result does not support text descriptions etc. The main idea is that this should be unobtrusive to the end user. The methods for manually loading new slides etc are primarily for developers and not really end user features. With that in mind, the slideshow does work fine if its methods are exposed to a user of your site.

Class Features

  • Change image source Array at runtime
  • Image Alignment within Stage
  • Various Public Methods for loading, pausing, resuming slideshow
  • Random or linear image progression
  • Manual or automatic (timer) image shuffling
  • Various Events
  • Memory Management
  • Looping or non looping
  • Definable Image Time
  • Definable Cross Fade Time
  • Definable Min scale size at which point the images are clipped

This is a fairly complex class. Read the class documentation and look at the included document class for the .fla for examples of how to use the various methods and respond to the various events the class dispatches. If you encounter bugs, please post them here

The download includes a .fla, a document class for that .fla, the main slideShow class and a couple of utility classes, one for parsing XML, one for creating a FullScreen Contextual menu and one for flexibly laying out the button on the stage. Along with the font used and the images used

Feel free to hit that donate button, this was a fair bit of work! Enjoy!

Updates
27 Feb, 2008: Initial Release.
01 Aug, 2008: New methods, clean up of properties, documentation, moved to using NpFSObjectResize class for scaling of images.

In this demo, the slides are displayed for 25 secs, cross fade time of 2 secs. Slideshow is in automode and fullscreen is enabled in the host swf.

View Example
Here is an example; http://www.noponies.com/dev/as3_fullbrowser_slide/

Source Files Here are the examples source files; http://www.blog.noponies.com/wp-content/uploads/npfullbrowserxfade.zip

Dependencies
This class uses the NpFSObjectResize Class (via composition) to handle stage alignments and scaling etc.

Class ActionScript

/* AS3
*Copyright 2008 noponies.
*/

package noponies.display{
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.DisplayObject;
  import flash.display.Loader;
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.IOErrorEvent;
  import flash.events.ProgressEvent;
  import flash.events.TimerEvent;
  import flash.net.URLRequest;
  import flash.utils.Timer
  /**
  * Dispatched as a result of a n image completely loading and completing its alphaFade in. When this event is dispatched, the image is displayed.
  *
  * @eventType NpFullBrowserXShow.BG_LOADED
  */

  [Event(name="bgloaded",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatched when a slide has changed, used to obtain information about slide shows current slide, total slides etc.
  *
  * @eventType NpFullBrowserXShow.SLIDE_CHANGE
  */

  [Event(name="slidechange",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatched as each slide loads in. Simply listen for this event as you would for a normal progress event.
  *
  * @eventType NpFullBrowserXShow.PROGRESS
  */

  [Event(name="progress",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatch this event to the class, and it will load a new slide, eg <code>classInstantiatorVarInstanceName.dispatchEvent(new Event(NpFullBrowserXShow.LOAD_NEW_SLIDE, true));</code>
  *
  * @eventType NpFullBrowserXShow.LOAD_NEW_SLIDE
  */

  [Event(name="loadnewslide",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatch this event to the class, and it will pause the slideshow if the slideshow is in <code>autoPlay</code> mode and is not paused, eg <code>classInstantiatorVarInstanceName.dispatchEvent(new Event(NpFullBrowserXShow.PAUSE, true));</code>
  *
  * @eventType NpFullBrowserXShow.PAUSE
  */

  [Event(name="pause",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatch this event to the class, and it will play the slideshow if the slideshow is in <code>autoPlay</code> mode and is not playing, eg <code>classInstantiatorVarInstanceName.dispatchEvent(new Event(NpFullBrowserXShow.PLAY, true));</code>
  *
  * @eventType NpFullBrowserXShow.PLAY
  */

  [Event(name="play",type="noponies.display.NpFullBrowserXShow")]
  /**
  * Dispatch this event to the class, and it will unload itself, destroying all internal instances, timers etc, eg <code>classInstantiatorVarInstanceName.dispatchEvent(new Event(NpFullBrowserXShow.UNLOAD_BG, true));</code>
  *
  * @eventType NpFullBrowserXShow.UNLOAD_BG
  */

  [Event(name="unloadbg",type="noponies.display.NpFullBrowserXShow")]
 
  /**
   *  <strong>NpFullBrowserXShow</strong>
   * <p>The NpFullBrowserXShow Class is designed to create Full Web Browser Background Image SlideShows</p>
   * <p> Check the various methods and properties of the class to explore its functionality</p>
   *  <p>This class file is abstracted from its data source, which is an array of images. The class does not handle any XML parsing, remoting etc. Simply pass it an array of images.</p>
   *  <p>Configure the class user defineable vars to change its behaviour.</p>
   * <p>Class has a number of playback settings. You can set it to loop, display its passed images sequentially
   *  or randomly. Set the playback to automatic, or manual. etc. To achieve this finer grained control over the class review its various properties</p>
   *  <p>This class attempts to keep memory useage down by creating bitmapdata objects from the loaded images. It then
   *  runs a routine to keep track of each bitmap loaded so that they can be removed when no longer needed. At most
   *  there are only ever two bitmaps in memory. As soon as a new slide is fully displayed, the old slide is removed
   *  and all vars pointing to it set to null. Memory useage stays fairly low using this approach, around 20 megs or so
   *  depending on the size of the images loaded in.</p>
   * <b>Author:</b> noponies - <a href="http://www.blog.noponies.com/" target="_blank">www.blog.noponies.com</a><br />
   * <b>Class version:</b> 1<br />
   * <b>Actionscript version:</b> 3.0 Player Version 9.0.28.0<br />
   * <b>Copyright:</b>
   * Creative Commons AttCreative Commons Attribution 3.0 New Zealand License<br />
   * <a href="http://creativecommons.org/licenses/by/3.0/nz/" target="_blank">http://creativecommons.org/licenses/by/3.0/nz/</a><br />
   * You can use this class how you like, except as a base for Flash Components or for Flash Template sites.<br />
   * <br />
   * <b>Date:</b> 30 July 2008<br />
   *  @langversion ActionScript 3.0
   *  @playerversion 9.0.28.0
   */


  public class NpFullBrowserXShow extends Sprite {

    //--------------------------------------
    // PUBLIC CONSTANTS
    //--------------------------------------
    //class events
    /**
     * The <code>NpFullBrowserXShow.BG_LOADED</code> constant defines the value of the <code>type</code> property of the event object for a <code>bgloaded</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"bgloaded"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType bgloaded
       */

    public static  const BG_LOADED:String  = "bgloaded";
    /**
     * The <code>NpFullBrowserXShow.SLIDE_CHANGE</code> constant defines the value of the <code>type</code> property of the event object for a <code>slidechange</code> event.
     *  @example Flash CS3 Timeline Based Demo.  
     * <listing version="3.0">
     *    classInstantiatorVarInstanceName.addEventListener(NpFullBrowserXShow.SLIDE_CHANGE, slidesChanged)
     *   
     *    function slidesChanged(event:Event){
     *      status_txt.text = "You are currently viewing slide "+classInstantiatorVarInstanceName.currentSlide+ " of "+classInstantiatorVarInstanceName.slidesTotal+" slides";
     *    }
     * </listing>  
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"slidechange"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType slidechange
       */

    public static  const SLIDE_CHANGE:String = "slidechange";
    /**
     * The <code>NpFullBrowserXShow.LOAD_NEW_SLIDE</code> constant defines the value of the <code>type</code> property of the event object for a <code>loadnewslide</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"loadnewslide"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType loadnewslide
       */
  
    public static  const LOAD_NEW_SLIDE:String  = "loadnewslide";
    /**
     * The <code>NpFullBrowserXShow.UNLOAD_BG</code> constant defines the value of the <code>type</code> property of the event object for a <code>unloadbg</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"unloadbg"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType unloadbg
       */
   
    public static  const UNLOAD_BG:String  = "unloadbg";
    /**
     * The <code>NpFullBrowserXShow.PAUSE</code> constant defines the value of the <code>type</code> property of the event object for a <code>pause</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"pause"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType pause
       */
   
    public static  const PAUSE:String  = "pause";
    /**
     * The <code>NpFullBrowserXShow.PLAY</code> constant defines the value of the <code>type</code> property of the event object for a <code>play</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"play"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType play
       */
   
    public static  const PLAY:String  = "play";
    /**
     * The <code>NpFullBrowserXShow.PROGRESS</code> constant defines the value of the <code>type</code> property of the event object for a <code>progress</code> event.
       * <p>
       * The properties of the event object have the following values:
       * </p>
       * <table class="innertable">
       * <tr><th>Property</th> <th>Value</th></tr>
       * <tr><td><code>type</code></td> <td><code>"progress"</code></td></tr>
       * <tr><td><code>bubbles</code></td> <td><code>true</code></td></tr>
       * <tr><td><code>cancelable</code></td> <td><code>false</code></td></tr>
       * </table>
       *
       * @eventType progress
       */
   
    public static  const PROGRESS:String  = "progress";
   
    //--------------------------------------
    // PRIVATE INSTANCE METHODS
    //--------------------------------------
    //via getters / setters
    private var crossFadeTime:uint = 2;//SECONDS
    private var imageTime:uint = 20;//SECONDS
    private var randomXshow:Boolean = true;//random or linear slide progression
    private var looping:Boolean = false;//do the slides loop?
    private var autoSlides:Boolean = true;//Automatic slideshow progression (true), or Manual (false)
    private var imagesArray:Array;//array of images
    private var xPos:Number = 0
    private var yPos:Number = 0
 
    private var p:int;//counter var
    private var loader:Loader;//loader for loading in images
    private var slide:Sprite;//sprite that serves as a content holder for loaders content
    private var slideTimer:Timer
    private var fadeTimer:Timer
    private var bitMapBg:Bitmap;//Bitmap
    private var tweeningAlpha:Boolean = false;//are we tweening the bg alpha
    private var targetSprite:Sprite;
    private var loaderSwap:Boolean = false;//bool to track cycling of slideshow
    private var bitDat1:BitmapData;//bitmap data holders
    private var bitDat2:BitmapData;//bitmap data holders
    private var fadeInc:Number;
    private var LoadedBytes:Number;//loaded bytes of each slide
    private var TotalBytes:Number;//total bytes of each slide
    private var slidesPaused:Boolean = false//bool to track paused state of slides
    //resize class
    private var tempResize:NpFSObjectResize
    private var contentHolderResize:NpFSObjectResize

   
    //--------------------------------------
    // GETTERS/SETTERS
    //--------------------------------------
    /**
     *  Get / Set the position relative to the browsers size (as a percentage of the browsers width) where you would like your slide to scale from on the <code>x</code> axis. This parameter is designed to allow for you to center your objects within the stage.
     *  For instance, a value of <code>0.5</code> will cause your object to be centered on the x axis. A value of <code>0</code> will place your object hard left. This parameter is passed to the <code>NpFSObjectResize.addResizeTarget()</code>
     *  method. Review that Class for more information on this property.
     *  @see #noponies.display.NpFSObjectResize
     *  @return Number
     */

    public function get slideAlignX():Number{
      return xPos;
    }
    /**
    * @private
    */

    public function set slideAlignX(newxPos:Number):void{
      xPos = newxPos
    }
    /**
     *  Get / Set the position relative to the browsers size (as a percentage of the browsers height) where you would like your slide to scale from on the <code>y</code> axis. This parameter is designed to allow for you to center your objects within the stage.
     *  For instance, a value of <code>0.5</code> will cause your object to be centered on the y axis. A value of <code>0</code> will place your object hard top. This parameter is passed to the <code>NpFSObjectResize.addResizeTarget()</code>
     *  method. Review that Class for more information on this property.
     *  @see #noponies.display.NpFSObjectResize
     *  @return Number
     */

    public function get slideAlignY():Number{
      return yPos;
    }
    /**
    * @private
    */

    public function set slideAlignY(newyPos:Number):void{
      yPos = newyPos
    }
    /**
     *  Get / Set (if for some reason you need to change) the array of image URLS that the slideShow pulls it's slides from. Setting this property does not negate the need to pass in an array of image URL's
     *  Class constructor.
     *  @default Array passed in via constructor argument.
     *  @return Array
     */

    public function get slideArray():Array{
      return imagesArray;
    }
    /**
    * @private
    */

    public function set slideArray(newImageArray:Array):void{
      imagesArray = newImageArray
    }
    /**
     *  Get / Set if the slides use a timer to progress through the slideShow. If you set this value to <code>false</code> you must either use the <code>displayNewSlide()</code> method or
     *  dispatch a <code>LOAD_NEW_SLIDE</code> event at the Class.
     *  @default true
     *  @return Boolean
     */

    public function get autoPlay():Boolean{
      return autoSlides;
    }
    /**
    * @private
    */

    public function set autoPlay(newAutoSlides:Boolean):void{
      autoSlides = newAutoSlides
    }
    /**
     *  Get / Set if the slides loop when they reach the end of the possible images available to the class. If the slides are not set to loop, and you are in <code>randomPlayBack</code> mode
     *  the array of possible images is decremented with each new slide. This stops duplicate displaying of slides.
     *  @default true
     *  @return Boolean
     *  @see #randomPlayBack
     */

    public function get slidesLoop():Boolean{
      return looping;
    }
    /**
    * @private
    */

    public function set slidesLoop(newLooping:Boolean):void{
      looping = newLooping
    }
    /**
     *  Get / Set if the slides playback randomly, or in a linear fashion. In random mode and if the slides are not se to loop this property will cause the array of available images to be decremented with
     *  each new slide load. So that over time, the amount of available images to display will reduce to 0.
     *  @default true
     *  @return Boolean
     *  @see #slidesLoop
     */

    public function get randomPlayBack():Boolean{
      return randomXshow;
    }
    /**
    * @private
    */

    public function set randomPlayBack(newRandomXshow:Boolean):void{
      randomXshow = newRandomXshow
    }
    /**
     *  Get the totalBytes of a loaded, or loading Slide. This value reflects the most recently requested, or loaded slide.
     *  @return Number
     */

    public function get bytesTotal():Number{
      return TotalBytes;
    }
    /**
     *  Get the bytesLoaded of a loading Slide. This value can also be accessed via the <code>NpFullBrowserXShow.PROGRESS</code> event provided by the class.
     *  @return Number
     */

    public function get bytesLoaded():Number{
      return LoadedBytes;
    }  
    /**
     *  Get the total Number of slides currently available to the slideShow.
     *  @return Number
     */

    public function get slidesTotal():int{
      return imagesArray.length;
    }
    /**
     *  Get the currently displayed slide
     *  @return int
     */

    public function get currentSlide():int{
      return p+1;
    }
    /**
     *  Get / Set the amount of time in seconds that each slide is displayed for.
     *  @default 20
     *  @return int
     */

    public function get imageDisplayTime():int{
      return imageTime;
    } 
    /**
    * @private
    */

    public function set imageDisplayTime(newImageTime:int):void{
      imageTime = newImageTime
    }  
   
    /**
     *  Get whether or not the slides are currently in a paused state.
     *  @default 2
     *  @return int
     */

    public function get pauseStatus():Boolean{
      return slidesPaused;
    }
    /**
     *  Get / Set the amount of time in seconds that it takes for a new image to cross fade into the previous image.
     *  @default 2
     *  @return int
     */

    public function get imageFadeTime():int{
      return crossFadeTime;
    }
    /**
    * @private
    */

    public function set imageFadeTime(newcrossFadeTime:int):void{
      crossFadeTime = newcrossFadeTime
    }
   
    //--------------------------------------
    // CONSTRUCTOR
    //--------------------------------------
    /**
     *  NpFullBrowserXShow
     *  <p>Review the various properties for the class for controlling the playback of your slideShow.</p>
     *  <p>Call <code>addChild()</code> after you set any Class Properties.</p>
     *  <p>This Class uses the <code>noponies.display.NpFSObjectResize</code> Class to handle the resizing of each slide to browser dimensions.</p>
     *  @param imagesArray Array of image URLS to use as source material for the slideShow.
     *  @see #imageFadeTime
     *  @see #imageDisplayTime
     *  @see #randomPlayBack
     *  @see #slidesLoop    
     *  @see #autoPlay
     *  @see #slideAlignX 
     *  @see #slideAlignY  
     *  @see noponies.display.NpFSObjectResize
     *  @see #pause()
     *  @see #play()
     *  @see #displayNewSlide()  
     *  @return
     * 
     *  @example Flash CS3 Timeline Based Demo.
     * <listing version="3.0">
     *    import noponies.display.NpFullBrowserXShow;
     *    var myImagesArray:Array = ["image.jpg, "image2.jpg", "image3.png"]
     *    var newBgSlideShow:NpFullBrowserXShow = new NpFullBrowserXShow(myImagesArray);
     *    newBgSlideShow.imageFadeTime = 10
     *    newBgSlideShow.imageDisplayTime = 10
     *    newBgSlideShow.randomPlayBack = true
     *    newBgSlideShow.slidesLoop = true
     *    newBgSlideShow.autoPlay = true
     *    newBgSlideShow.slideAlignX  =1 //align slide bottomRight
     *    newBgSlideShow.slideAlignY  =1 //align slide bottomRight
     *    addChildAt(newBgSlideShow,0);
     * </listing>
     */
  
    
    public function NpFullBrowserXShow(imagesArray:Array) {
      //resize Class Instances
      tempResize = new NpFSObjectResize();
      contentHolderResize = new NpFSObjectResize();
      //access our images array
      this.imagesArray = imagesArray;
      //add listeners
      addEventListener(NpFullBrowserXShow.UNLOAD_BG, unloadAll);//listener for unload all event
      addEventListener(NpFullBrowserXShow.PAUSE, pauseSlides)//listener for pausing slideshow
      addEventListener(NpFullBrowserXShow.PLAY, restartSlides)//listener for restarting slideshows
      addEventListener(NpFullBrowserXShow.LOAD_NEW_SLIDE, loadNewSlide)//listener for restarting slideshows   
      addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);//get stage access
    }
   
    //--------------------------------------
    // PUBLIC METHODS - THIS FUNCTIONALITY IS ALSO EXPOSED VIA THE CLASSES EVENTS
    //--------------------------------------
   
    /**
    *   This public method will initiate the loading and display of a new slide.
    * @return
    */

    public function displayNewSlide():void {
      loadBgImage();
    }
    /**
    *   This public method will pause the slideShow if it is in <code>autoPlay</code> mode and it is currently playing.
    * @see #autoPlay
    * @return
    */

    public function pause():void{
      pauseSlides()
    }
    /**
    *   This public method will play the slideShow if it is in <code>autoPlay</code> mode and it has been paused.
    * @see #autoPlay
    * @return
    */

    public function play():void{
      restartSlides()
    }
    /**
    *   This public method will unload and dispose of this Class. This functionally equivalent to the Class recieving a REMOVED_FROM_STAGE event.
    * @return
    */

    public function unloadBg():void{
      unloadAll()
    }

    //--------------------------------------
    // LISTENERS & PRIVATE METHODS - YEEHA
    //--------------------------------------
   
    //--------------------------------------
    // LOAD IMAGE METHOD - LOADS IN NEW SLIDE ASSETS
    //--------------------------------------
    //will attempt to kill any currently downloading images if a new image is requested before the currently downloading image has finished loading.
    private function loadBgImage():void {
      //if an image is currently downloading, and another image is requested, kill the loader and its download.
      if(loader!=null){
        try {
        loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaded);
        loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIOErrorHandler);
        loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
        loader.close()
        loader = null
          } catch (e:Error) {
            trace(e);
          }
      }
     
      loader = new Loader();
      loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
      loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorHandler);
      loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
      loader.load(new URLRequest(String(imagesArray[p])));
    }
   
    //--------------------------------------
    // HANDLE A SUCCESSFUL LOAD OF AN IMAGE
    //--------------------------------------
    private function loaded(event:Event):void {
      //dispatch the settings event
      dispatchEvent(new Event(NpFullBrowserXShow.SLIDE_CHANGE,true));
     
      //check to see what slide mode we are in. If we are in automatic, reset the timer for the next cycle
      if (autoSlides) {
        slideTimer.reset();//reset the timer
      }
      //create the slide holder sprite
      slide = new Sprite();
      slide.alpha = 0;//set the slide content to have an alpha of 0
      slide.x = slide.y = 0
      //bool to track what loader cycle we are in, so we can swap between bitmap vars.
      loaderSwap = !loaderSwap;
      if (loaderSwap) {
        bitDat1 = Bitmap(event.target.content).bitmapData;
        bitMapBg = new Bitmap(bitDat1);
      } else {
        bitDat2 = Bitmap(event.target.content).bitmapData;
        bitMapBg = new Bitmap(bitDat2);
      }
      //unload the loader
      loader.unload();

      //attach and smooth our bitmap object
      bitMapBg.smoothing = true;
      slide.addChild(bitMapBg);
      addChild(slide);

      //remove the eventListeners on the loader object and set it to null
      loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaded);
      loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIOErrorHandler);
      loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
      loader = null;

      //set initial scale of image
      tempResize.addResizeTarget(slide,xPos,yPos);
      //alpha in the content
      //turn on this var, this is a flag that lets the temp resize function run
      tweeningAlpha = true;
      //add the fade time listener
      fadeTimer.addEventListener(TimerEvent.TIMER, fadeTimerListener);
      fadeTimer.start();

      //reset the p counter variable based on if we have a random or linear slide show, and also check to see that the
      //value is not beyond the total number of images we actually have in our array.
      if(!looping && randomXshow){
        if(imagesArray.length ==0){
          pauseSlides()
        }else{
          imagesArray.splice(p,1)
        }
      }
       
      if (!randomXshow) {
        p++;
      } else {
        getUniqueNum()
      }
     
      if (!randomXshow && p==imagesArray.length && looping) {
        p =0;
      }
      if (!randomXshow && p==imagesArray.length && !looping) {
        pauseSlides()
      }
    }
   
    //--------------------------------------
    // CREATE A UNIQUE NUMBER FROM OUR IMAGE ARRAY
    //--------------------------------------     
    private function getUniqueNum():void {
      var tempRandomImg:int = Math.floor(Math.random()*imagesArray.length);
      if (tempRandomImg == p &&imagesArray.length>1 ) {
        getUniqueNum();
      } else {
        p = tempRandomImg;
      }
    }
   
    //--------------------------------------
    // CROSS FADING METHOD
    //--------------------------------------   
    //will run slower if the screen is being resized.
    private function fadeTimerListener(event:TimerEvent):void {
      slide.alpha += .01;
      if (slide.alpha >= 1) {
        fadeTimer.removeEventListener(TimerEvent.TIMER, fadeTimerListener);
        fadeTimer.reset();
        onFinishAlpha();
      }
      event.updateAfterEvent();
    }
   
    //--------------------------------------
    // FADE COMPLETE METHOD - CALLED WHEN A SLIDE HAS FINISHED CROSS FADING
    //--------------------------------------
    //run this when we have displayed the content
    private function onFinishAlpha():void {
      tweeningAlpha = false;//turn off the tweening variable
      tempResize.removeResizeTarget()
      contentHolderResize.addResizeTarget(slide,xPos,yPos);
      //check here to see if we have a two slides existing, delete it if we do
      if (this.numChildren>1) {
        //memory management !Attempt to keep memory useage down
        //Here we check our loaderswap var, which we want to run opposite to what its current value is
        //(so we can access the last bitmap), then we dispose of the old bitmap, which frees up memory immediately.
        //We then run the child removal and the set to null routine for the garbage collector.
        if (!loaderSwap) {
          try {
            bitDat1.dispose();
          } catch (e:Error) {
            trace(e);//
          }
        } else {
          try {
            bitDat2.dispose();
          } catch (e:Error) {
            trace(e);// catch errors
          }
        }
        //access the lowest (oldest) child of the Class Instance, and try to remove it
        try {
          bitMapBg = null;
          removeChildAt(0);
          slide=null;
        } catch (e:Error) {
          trace(e);//catch errors
        }
      }
     
      if (autoSlides&&!slidesPaused) {
        //restart the timer once the image has been loaded and displayed
        if (!looping && p==imagesArray.length) {
          slideTimer.reset();
        } else {
          slideTimer.start();//start the timer again when we have loaded in the slide
        }
      }
      //dispatch the loaded event
      dispatchEvent(new Event(NpFullBrowserXShow.BG_LOADED,true));
    }

    //--------------------------------------
    // LISTENER FOR THE NpFullBrowserXShow.LOAD_NEW_SLIDE EVENT
    //--------------------------------------
    private function loadNewSlide(event:Event):void{
      loadBgImage();
    }
   
    //--------------------------------------
    // LISTENER FOR THE SLIDE TIMER EVENTS
    //--------------------------------------   
    private function slideTime(event:TimerEvent):void {
      loadBgImage();
    }
   
    //--------------------------------------
    // ADDED TO STAGE LISTENER
    //--------------------------------------
    private function addedToStageHandler(event:Event):void {
      //set stage scale modes
      addEventListener(Event.REMOVED_FROM_STAGE, unloadAll);
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
     
      //initial slide start position value
      if (randomXshow) {
        p = Math.floor((Math.random()*imagesArray.length));
      } else {
        p = 0;
      }
      //create timers
      slideTimer = new Timer(imageTime*1000, 1);//timer
      fadeTimer = new Timer((crossFadeTime*1000)*.01, 0);//timer
     
      //timer listener
      if (autoSlides) {
        slideTimer.addEventListener(TimerEvent.TIMER_COMPLETE, slideTime);
      }
      //load the bg image when we have stage access
      loadBgImage();
    }
   
    //--------------------------------------
    // HANDLE IO ERRORS
    //--------------------------------------
    private function onIOErrorHandler(event:IOErrorEvent):void {
      trace("Shit, looks like there has been an ioError: " + event.text);
    }
   
    //--------------------------------------
    // HANLE PROGRESS EVENTS FROM SLIDE LOAD OPERATIONS
    //--------------------------------------
    //progress handler, dispatches an event that can be used to monitor progress outside of this class
    private function progressHandler(event:ProgressEvent):void {
      //dispatch the loading event
      LoadedBytes = event.bytesLoaded;
      TotalBytes = event.bytesTotal;
      dispatchEvent(new ProgressEvent(NpFullBrowserXShow.PROGRESS,false,true,event.bytesLoaded, event.bytesTotal));
    }
   
    //--------------------------------------
    // LISTENER FOR THE NpFullBrowserXShow.PAUSE EVENT
    //--------------------------------------
    private function pauseSlides(event:Event = null):void{
      if(!slidesPaused){
        slideTimer.reset()
        slidesPaused = true
      }
    }

    //--------------------------------------
    // LISTENER FOR THE NpFullBrowserXShow.PLAY EVENT
    //--------------------------------------   
    private function restartSlides(event:Event = null):void{
      if(slidesPaused){
        slideTimer.start()
        slidesPaused = false
      }
    }
   
    //--------------------------------------
    // LISTENER FOR THE REMOVED FROM STAGE EVENT OR THE UNLOAD_BG EVENT
    //--------------------------------------   
    //dispatch an unload event to remove all listeners and set content to null
    private function unloadAll(event:Event = null):void {
      try {
      removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
      removeEventListener(Event.REMOVED_FROM_STAGE, unloadAll);
      removeEventListener(NpFullBrowserXShow.LOAD_NEW_SLIDE, loadNewSlide)
      removeEventListener(NpFullBrowserXShow.PAUSE, pauseSlides)
      removeEventListener(NpFullBrowserXShow.PLAY, restartSlides)

      if (loaderSwap) {
        bitDat1.dispose();
        bitDat1 = null;
        bitDat2 = null;
      } else {
        bitDat2.dispose();
        bitDat1 = null;
        bitDat2 = null;
      }
     
      bitMapBg = null;
      //kill the timers
      slideTimer.stop();
      slideTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, slideTime);
      slideTimer = null;
      fadeTimer.stop();
      fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, fadeTimerListener);
      fadeTimer = null;
      tempResize.removeResizeTarget();
      tempResize = null
      removeEventListener(NpFullBrowserXShow.UNLOAD_BG, unloadAll);
      } catch (e:Error) {
        trace("There was an error when attempting to delete all slide content: "+Error);
      }
    }

  }

}

ActionScript 3 Drag, Zoom, Pan XML Content

ActionScript 3 version of the Actionscript 2 Drag, Pan Zoom example.

Loaded content can be either bitmap, swf or whatver. SWF’s retain their full interactivity. Simply specify what content you want in the XML file. Loaded content pulls an ID parameter from the XML file which is used for sending messages to particular content instances via custom non mouseEvent events. This is demoed as a commented out line as a means of scaling up the content and shuffling a particular instance of content into the center of the screen.

This is a class based implementation of the AS2 timeline implementation. With that in mind, there are 4 core classes in total, with two supporting classes.

Class Breakdown
LayOut.as
This class does the lions work of this demo. It requires two parameters, an XML file, which is provided by the LoadXML class and an integer to specify how many columns to lay the content out into. This class also acts as a mediator in the event dispatch process between content and draggable area. Class handles panning and zooming of loaded content, along with dragging and laying content out in a grid. Within this class are a number of variables that control how the zooming behaves. This class dispatches two other events to indicate loading of content, and content has all loaded. Currently these events do no have listeners, but the framework is there to hook into, should you want to. Loading Started Event dispatchEvent(new Event(LayOut.STARTED_LOADING)); Loading Finished Event dispatchEvent(new Event(LayOut.FINISHED_LOADING));.

ZoomContent.as
This class dispatches events back to the layout class which handles all zooming and panning. eg; dispatchEvent(new Event(ZoomContent.ACTIVE_CONTENT,true));
This class also handles enabling and disabling mouseChildren for loaded content. I didn’t want interactive content to able to recieve mouseEvents when it is scaled down. This is handled by a simple rollOver function which checks the scale of the parentSprite (pass in via the constructor). Class also dispatches events to custom cursor class.”dispatchEvent(new Event(CustomCursor.MOUSE_SHOW, true));” Generally speaking, this class is simply a container class for loaded in content.

CustomCursor.as
Loads in cursor.swf, which is the cursor asset file, with various cursor states. Only the zoom state is used in this demo. You of course can add access the other three states (finger, drag open hand, drag closed hand), if need be.

ContentEvent.as
Use for passing arguments with your custom events. In this instance it passes one parameter, an String, which represents the ID value of a target content instance. This class is used primarily for dispatching events to particular content instances. For instance, this class can be used to create a menu that shuffles and zooms content around independently of mouse Interactivity.

All classes support a method for killing listeners, each class method is fired when a REMOVED_FROM_STAGE event occurs. This of course can be changed for custom listener removal.

Updates 15 Feb, 2008: Adjusted the grid layout function and made the demo more flexible in terms of media it can load.
22 Feb, 2008: Fix for a double click tweening bug.
12 March, 2008: Better fix for double click bug! & Rounding Math Error.

Example Supports

    Mulitple Galleries or content
    Draggable content
    Click Content to scale up
    Double Click to Scale back down
    Scale back to defined point, or point before a scale up operation
    Auto or XML defined Layout
    User defined scale factor
    Custom Cursor

Example
Here is an example. http://www.noponies.com/dev/as3_pan_zoom/ (Click content to zoom, double click to scale back)

Source Files
Here are the various support files; ActionScript 3 Drag Zoom XML Loaded Content V1.5

Dependencies
Demo uses http://www.tweenlite.com for scaling, panning and zooming.

LayOut Class ActionScript

/*******************************************************************************
LAYOUT CLASS FOR PAN ZOOM CONTENT DEMO
********************************************************************************
This class does the lions work of this demo. It requires two parameters, an XML file, which
is provided by the LoadXML class and an integer to specify how many columns to lay the content out into.

Class handles panning and zooming of loaded content. Loaded content can be either bitmap, swf or whatver. SWF's retain their
full interactivity. Simply specify what content you want in the XML file. Loaded content pulls an ID parameter from the XML file which
is used for sending messages to particular content istances via custom non mouseEvent events. This is demoed in
as a means of scaling up the content and shuffling a particular instance of content into the center of the screen.
********************************************************************************
FEATURES
********************************************************************************
Dispatch custom event with parameter (id) to content, targeting a particular instance.
Eg;
newContent.dispatchEvent(new ContentEvent("CONTENT_EVENT","fourth"));
Will make the fourth content element scale and zoom. This is useful if you want to set up a menu to access content
rather than ue clicks on actual content itself. Currently this event is handled by the content by simply dispatching back
the scale event that would be sent via a mouse click.

Dispatches two other events to indicate loading of content, and content has all loaded. Currently these events do no
have listeners, but the framework is there to hook into, should you want to.
Loading Started Event
dispatchEvent(new Event(LayOut.STARTED_LOADING));
Loading Finished Event
dispatchEvent(new Event(LayOut.FINISHED_LOADING));

Content is laid out either by an autoGrid function, or by pulling in layout information from the XML file. Set what method
to use in the user defineable variables section.

Specify auto grid column numbers via constructor. Useful for changing autogrid layout etc

********************************************************************************
SAMPLE USEAGE
********************************************************************************
//load the layout Class - (XML)
var layOutContent:LayOut = new LayOut(contentXML, 3)
********************************************************************************
NOTES
********************************************************************************
Uses tweenLite to handle scaling and content movement

TweenLite from here; http://blog.greensock.com/tweenliteas3

Made in 2008 by noponies
http://www.blog.noponies.com

Terms of use
http://www.blog.noponies.com/terms-and-conditions

********************************************************************************
Version 1.4 - 12 March 2008 (Fix for double click event bug) - again
********************************************************************************/


package noponies.panzoom {

import flash.display.Sprite;
import flash.events.*;
import flash.net.URLRequest;
import flash.display.Loader;
import gs.TweenLite;

public class LayOut extends Sprite {
/*******************************************************************************/
/*USER DEFINABLE VARIABLES
/*******************************************************************************/

private var useAutoGrid:Boolean = true//Use grid function (true), or pull placement from XML file (false)
private var verticalPadding:int = 20;//Padding
private var horizontalPadding:int = 20;//Padding
private static  var scaleFactor:Number = .25;//The scale factor for the loaded content
private static var returnToPoint:Boolean = false;//Specify a point to return to when scaling down(true), or return to point where content was when scaled up(false)
private static var returnXpoint:int = 0//where to return to when scaling down if using returnToPoint above
private static var returnYpoint:int = 0//where to return to when scaling down if using returnToPoint above

/*******************************************************************************/
/*REQUIRED VARIABLES
/*******************************************************************************/


public static  const FINISHED_LOADING:String  = "finishedLoading";
public static  const STARTED_LOADING:String  = "startedLoading";
private var XMLContent:XML;
private var i:int = 0;//counter var
private var loader:Loader;
private var dragArea:Sprite;
private var spacer:int = 0;
private var contentXpos:int = 0;
private var contentYpos:int = 0;
private var originX:int;
private var originY:int;
private var newContent:ZoomContent;
private var scaling:Boolean = false //Booloean to indicate if we are currently tweening the scale
//custom cursor var, delete if not using custom cursor.
private var cursor:Sprite
private var columns:int=3

//constructor
public function LayOut(XMLContent:XML, columns:int) {
this.XMLContent=XMLContent;
this.columns = columns
//create drag sprite
dragArea=new Sprite();
addChild(dragArea);
//set up its listeners
dragArea.doubleClickEnabled=true;
dragArea.addEventListener(MouseEvent.DOUBLE_CLICK,dragDoubleClickHandler);
dragArea.addEventListener(MouseEvent.MOUSE_DOWN,dragDownHandler);
dragArea.addEventListener(MouseEvent.MOUSE_UP,dragUpHandler);
dragArea.scaleX = dragArea.scaleY =  scaleFactor;
dragArea.mouseChildren = true;
//call the layout function
layOutContent();
//add the listener that handles clicks on loaded content
//YOU MAY WANT TO ADD THIS WHEN ALL CONTENT HAS LOADED
//addEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
//dispatch an event indicating that we have started loading
dispatchEvent(new Event(LayOut.STARTED_LOADING));
addEventListener(Event.REMOVED_FROM_STAGE,killListeners);//kill listeners handler
//instantiate the custom cursor class. Remove if not needed
cursor = new CustomCursor()
addChild(cursor)
}
private function layOutContent():void {
//get the content
loader=new Loader  ;
loader.contentLoaderInfo.addEventListener(Event.INIT,initListener);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loadProgress);
loader.load(new URLRequest(String(XMLContent.article.story[i])));
}
private function initListener(e:Event):void {
//pass our content and our ID param from the XML file to this class. The ID param lets us track what we have clicked on, if we need to.
//also pass reference to dragArea sprite, avoids messing around with parent access from content back to this class instance.
newContent =new ZoomContent(loader.content, String(XMLContent.article.story[i]..@id),dragArea);

newContent.x = contentXpos;
newContent.y = contentYpos;

//create a grid of content
if (useAutoGrid) {
spacer++;
if (spacer == columns) {
spacer=0;
contentYpos+= loader.content.height+verticalPadding;
contentXpos= -loader.content.width-horizontalPadding;
}
//increment content x
contentXpos += loader.content.width+horizontalPadding;
} else {
//access XML attributes to layout content. You could also add in say, a rotation var, and rotate the loaded content
newContent.x = int(XMLContent.article.story[i]..@xpos);
newContent.y = int(XMLContent.article.story[i]..@ypos);
}

dragArea.addChild(newContent);

i++;//increment loop through content

if (i &lt; XMLContent.article.length()) {
layOutContent();//create loop
}
if (i == XMLContent.article.length()) {
//set up drag areas size positon etc
dragArea.graphics.beginFill(0x000000,0);
dragArea.graphics.drawRect(0-stage.stageHeight*2,0-stage.stageWidth*2,stage.stageWidth*8,stage.stageHeight*8);
dragArea.graphics.endFill();

//Begin to listen for click events on content
addEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);

//dispatch an event indicating we are all loaded
dispatchEvent(new Event(LayOut.FINISHED_LOADING));
/*******************************************************************************
DEMO EVENT BELOW TO ZOOM A PARTICULAR CLIP
*******************************************************************************/

//demo event dispatch to make content zoom to a particular point when loaded or whenever
//newContent.dispatchEvent(new ContentEvent("CONTENT_EVENT","fourth one"));

}
}

//progress handling of clips
function loadProgress(event:ProgressEvent):void {
//trace("LOADED "+Math.floor(e.bytesLoaded / 1024)+ " OF "+Math.floor(e.bytesTotal/1024));

}

//handle an event dispatch from the content. Sent via a click event on content
private function handleClickOnContent(event:Event):void {
//trace(event.target.id)//access ID prop of ZoomContent Class
//do the math equations for moving content around. Use some bitwise calcs for speed and to remove
//calculations from within tween body
/*******************************************************************************
POSITION POINT CLIPS SCALE TO
*******************************************************************************/

//If you want to move the content to a particular point, rather than center of screen, set the endX and endY values to the position you require
var targetX:int = event.target.x, targetY:int = event.target.y;
var endX:int = (stage.stageWidth&gt;&gt;1) - (targetX+(event.target.width&gt;&gt;1));
var endY:int = (stage.stageHeight&gt;&gt;1) -(targetY+(event.target.height&gt;&gt;1));
//this gets set via rollOver on target sprite, however, a situation can occur when the mouse does not "rollOver" the target sprite, so
//this setting of mouseChildren fixes that small issue
event.target.mouseChildren = true;
//set drag area initial positional vars
//here we set up the scaling up and down tweens. When a user clicks on the content and initiates a tween we remove the various event listeners for
//handling tween events. When the tween is complete we initialise the event listeners again. This stops an annoying triple click bug where a user could
//click on the content rapidly and it would never complete the tween, getting stuck at a scale of around 80% and off its original position.
//scale up
if (dragArea.scaleX==scaleFactor &amp;&amp; !scaling) {
removeEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
scaling = true//we are scaling
originX = dragArea.x;
originY = dragArea.y;
TweenLite.to(dragArea, 1, { x:endX,y:endY, scaleX:1, scaleY:1, onComplete:contentTweenComplete, onCompleteParams:["up"]});//do the scale and pos tween
} else {
//we are scaled, just laterally tween positions
removeEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
scaling = false//reset the scaling flag, we just reposition here, not scale
TweenLite.to(dragArea, 1, { x:endX,y:endY,onComplete:contentTweenComplete, onCompleteParams:["sideways"]});//do positional tween when content is fullscale. no need to dispatch cursor event here
}
}
//function run when tweens have finished on content, use for various things. Whatever your heart desires.
//here we simply dispatch the cursor control events and reattach the event listeners for handling clicks
//on our content items. Do not remove the event attaching and dispatching lines, or this will break!
private function contentTweenComplete(scaleDirection:String):void{
switch(scaleDirection){
case"up" :
dispatchEvent(new Event(CustomCursor.MOUSE_SHOW, true));
addEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
break;
case "down":
dispatchEvent(new Event(CustomCursor.MOUSE_SHOW, true));
addEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
break;
case"sideways" :
addEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
break;
}
scaling = false//reset the scaling flag
}

//scale down function
private function dragDoubleClickHandler(event:MouseEvent):void {
if(dragArea.scaleX==1 &amp;&amp; !scaling){
removeEventListener(ZoomContent.ACTIVE_CONTENT, handleClickOnContent);
scaling = true//we are scaling
!returnToPoint ? TweenLite.to(dragArea, 1, { x:originX,y:originY, scaleX:scaleFactor, scaleY:scaleFactor, onComplete:contentTweenComplete, onCompleteParams:["down"]}) : TweenLite.to(dragArea, 1, { x:returnXpoint,y:returnYpoint, scaleX:scaleFactor, scaleY:scaleFactor, onComplete:contentTweenComplete, onCompleteParams:["down"]});
}
}