Menu:

Sponsor

Place your advertising here
casininio casino online casino online Buy and sell flash files

 

Forum's topics

Latest Files

Archives

Top Rated

Categories

Photo Gallery


Flickr SlideShow with SWX

Introduction

In this example we will create a very simple slideshow of images taken from a flickr user account using SWX.

1. What's SWX?

SWX is the native data format for Flash. Data is stored as SWF bytecode (you can't get more native than that on the Flash Platform) that is interpreted by the Flash Player. The SWX format is a subset of the SWF format (just like JSON is a subset of JavaScript) [from swxformat.org].

For more informations about SWX and the installation steps follow this link.

2. The Final Example

Ok, first of all let's take a look at what we're currently going to create. As you can see it's a very very simple image slideshow:

3. Server side Setup

SWX is shiped with a Flickr service already installed, hence you have to do nothing in the server side.
For a complete list of methods in the Flickr service use the SWX service explorer ( see the swxformat.org service explorer, and select "Flickr" ). If you've already used amfphp you're familiar with swx service explorer too.

The Flickr methods we will use for this tutorial are:

  • getUserPhotos
  • photosGetContext

with getUserPhotos we will get the first photo for the passed username, then we will use photosGetContext to get the next photo. If you need to know which parameters are required for a certain method use the service explorer and select the method you want to call:

4. Flash side

As you've seen the server side setup wasn't difficult at all :)
Also the actionscript code we'll create isn't too complicated. It's just a basic slideshow....

4.1. Create the project

For this tutorial I've used FlashDevelop as editor, so you don't need to have Flash installed to compile the swf by your own.
Open Flashdevelop and create a new Actionscript 2 default project.
Open the "Main.as" file and write down this code:


import mx.transitions.easing.None;

import mx.transitions.Fade;
import mx.transitions.Transition;
import mx.transitions.TransitionManager;
import org.swxformat.SWX;
import mx.utils.Delegate;

class Main
{
    private var swx:SWX;
    private var username:String = "";
    private var timeout:Number;
    private var gateway:String;
    private var loader:MovieClipLoader;
    private var holder:MovieClip;
    private var next_depth:Number = 1;
    private var currentPhoto:Object;
    

    public function Main( path:String, user:String, ms:Number )
    {
        this.username = user;
        this.timeout  = ms;
        this.gateway  = path;
        
        swx = new SWX();
        swx.gateway = gateway;
        swx.debug   = true;
        
        loader = new MovieClipLoader();
        loader.addListener( this );
    }
    
    /**
     * first call. get the first photo for that user
     */
    public function loop()
    {
        var callParameters:Object =
        {
            serviceClass: "Flickr",
            method:   "getUserPhotos",
            args:     [username, "small", 1]
        }
        initDisplay();
        call( callParameters );
    }
    
    /**
     * load next photo based on the current photo context
     */
    private function loadNext( )
    {
        var callParameters:Object =
        {
            serviceClass: "Flickr",
            method:    "photosGetContext",
            args:      [ currentPhoto.id ]
        }
        call( callParameters );
    }
    
    /**
     * Call a method on SWX
     * @param    params
     */
    public function call( params:Object )
    {
        params.result   = [this, onResult];
        params.fault    = [this, onFault];
        params.timeout  = [this, onTimeout];
        params.progress = [this, onProgress];
        
        swx.call( params );
    }
    
    /**
     * SWX result handler
     * @param    event
     */
    private function onResult(event:Object)
    {
        var result:Array = event.result;
        var method:String = event.target._dataObject.method;
        var imageClip:MovieClip;
        
        imageClip = holder.createEmptyMovieClip("image_" + ++next_depth, next_depth);
        
        if( method == 'getUserPhotos' )
        {
            if(result.photo.length > 0)
            {
                loader.loadClip( result.photo[0].src, imageClip );
                currentPhoto = result.photo[0];
            }
        } else if(method == 'photosGetContext')
        {
            currentPhoto = result.prevphoto.id != undefined ? result.prevphoto : result.nextphoto;
            loader.loadClip("http://farm" + currentPhoto.farm + ".static.flickr.com/" + currentPhoto.server + "/" + currentPhoto.id + "_" + currentPhoto.secret + "_m.jpg", imageClip );
        }
    }
    
    /**
     * SWX error handler
     * @param    event
     */
    private function onFault(event:Object)
    {
        trace('onFault!');
    }

    /**
     * SWX timeout handler
     */
    private function onTimeout()
    {
        trace("Call timed out!");
    }
    
    /**
     * SWX progress handler
     * @param    event
     */
    private function onProgress( event:Object )
    {
        trace('onProgress: ' + event.target.url + ", " + event.type + ", " + event.bytesLoaded + ", " + event.bytesTotal + ", " + event.clip);
    }
    
    /**
     * Image load completed
     * @param    target
     */
    private function onLoadComplete( target:MovieClip )
    {
        if( target._parent.getInstanceAtDepth(target.getDepth()-2) != undefined)
        {
            target._parent.getInstanceAtDepth(target.getDepth()-2).removeMovieClip();
        }
        target._alpha = 0;
    }
    
    /**
     * Image display
     * @param    target
     */
    private function onLoadInit( target:MovieClip )
    {
        target._alpha = 100;
        TransitionManager.start(target, { type:Fade, direction:Transition.IN, duration:2, easing:None.easeNone } );
        _global.setTimeout( Delegate.create(this, loadNext), 2000 + this.timeout );
    }
    
    /**
     * Initalize the movie display
     */
    private function initDisplay()
    {
        holder = _root.createEmptyMovieClip("holder", 1);
    }
    
    /**
     * Main entry point
     */
    public static function main():Void
    {
        var app:Main = new Main( _root.path, _root.username, 2000 );
        app.loop();
    }
}

5. Flash code explanation

This is the full list of the Main class methods:

  • public function Main( path:String, user:String, ms:Number )
  • public function loop( )
  • private function loadNext( )
  • public function call( params:Object )
  • private function initDisplay()
  • public static function main():Void
  • SWX handers:
    • private function onResult(event:Object)
    • private function onFault(event:Object)
    • private function onTimeout()
    • private function onProgress( event:Object )
  • MovieClipLoader handlers:
    • private function onLoadComplete( target:MovieClip )
    • private function onLoadInit( target:MovieClip )

We don't have any .fla file here, only this as class. The class entry point will be the static function main, that's because in the FlashDevelop project properties I've checked the "Use Main entry point" preference, under the Compiler option (see next figure):

Screenshot of the Flash Flickr SWX project properties panel in FlashDevelop

For this reason the "main" static function will be our entry method.
In this main function we will create a new instance of the Main class and we'll call the first ,ethod execution "loop".

As you can see I'm passing "_root.path" and "_root.username" to the constructor, that's because I define these variables in the flashvars object tag.
In the class constructor I will create an instance of the SWX class:

swx = new SWX();
swx.gateway = gateway;
swx.debug   = true;

When "swx.debug" property is set to true, you can debug your swf using the SWX Data Analyzer.

The second instance created in the class constructor is the MovieClipLoader, which is just responsible of the external images loading:

loader = new MovieClipLoader();
loader.addListener( this );

Using "addListener( this )" means that all the handlers called within the MovieClipLoader will be redirected to the Main class itself. And in our case the methods called are "onLoadInit" and "onLoadComplete", which simply make the Fade transition using:

TransitionManager.start(target, { type:Fade, direction:Transition.IN, duration:2, easing:None.easeNone } );

5.1. How SWX is working

In our Main class there are 2 methods which in some way interact with the SWX instance: loop and loadNext. The "public function loop" is the first called method (as you can see into the static main function) and just ask to flickr whic is the last published image for the given user, then every swx call is made by the loadNext method asking flickr for the next user image. This is the loop method:

public function loop()
    {
        var callParameters:Object =
        {
            serviceClass: "Flickr",
            method:   "getUserPhotos",
            args:     [username, "small", 1]
        }
        initDisplay();
        call( callParameters );
    }

In this method we're going to prepare the object parameter to be passed to the SWX instance.
This object must define the name of the service we're calling ( Flickr ), the method name ( getUserPhotos ) and the passed parameters ( [username, "small", 1] ).
In this case we're trying to get the latest photo available for the passed flickr username and with the size of "small". Then this object is passed to the "call" method which will update the callParameter object ( adding the correct handlers ) and finally invokes SWX.call:

public function call( params:Object )
    {
        params.result   = [this, onResult];
        params.fault    = [this, onFault];
        params.timeout  = [this, onTimeout];
        params.progress = [this, onProgress];
        
        swx.call( params );
    }

All is done here is to define which will be the handlers assigned in the next swx.call. We'll just care about the onResulthandler:

private function onResult(event:Object)
    {
        var result:Array = event.result;
        var method:String = event.target._dataObject.method;
        var imageClip:MovieClip;
        
        imageClip = holder.createEmptyMovieClip("image_" + ++next_depth, next_depth);
        
        if( method == 'getUserPhotos' )
        {
            if(result.photo.length > 0)
            {
                loader.loadClip( result.photo[0].src, imageClip );
                currentPhoto = result.photo[0];
            }
        } else if(method == 'photosGetContext')
        {
            currentPhoto = result.prevphoto.id != undefined ? result.prevphoto : result.nextphoto;
            loader.loadClip("http://farm" + currentPhoto.farm + ".static.flickr.com/" + currentPhoto.server + "/" + currentPhoto.id + "_" + currentPhoto.secret + "_m.jpg", imageClip );
        }
    }

Within this method the event.result is our result, while event.target._dataObject.method is the string name of the server method we've called. I need this one in order to use only one onResult handler for every swx.call.
In this way I know if the given result is child of the getUserPhotos or photosGetContext method's call.