Friday 17 June 2011

Simple preloader for the Loader Class

I use the Loader class mainly to... well, load an image. It's also used to load external SWF, but at this time, I didn't had the need to use it like that.

My main job, at this point, as an AS3 developer is to produce infographies for a news agency. Some processes ahve change in the way I must now deliver the work, and one big change is that all the assets like images, videos, sounds and xml files, must be in a remote server.

This carries a problem which is a possible lag in time while the SWF tries and loads the assets remotely. You have to take care of this, because the web readers of these infos must have some sort of feedback, or else, nothing happens, and they may think something is broken.

So this time I'll tell you a simple way of making a preloader bar for the Loader class.

Make a simple class to load the image:

package{
     import flash.display.MovieClip;
     import flash.display.Loader;
     import flash.display.URLRequest;


     public class LoadPhoto extends MovieClip{
          private var photoURL:URLRequest;
          private var photoLoader:Loader;


          public function LoadPhoto(url:String){
              photoURL=new URLRequest(url);
              photoLoader=new Loader();
              photoLoader.load(photoURL);
              addChild(photoLoader);
         }
     }
}

This is the minimum to load an image or SWF with the Loader.

If you want to show a progress bar while the data is accessed, you have to draw it. You can add a text field to show the percentage value, but that it's a natural evolution from this progress bar.

Inside the the LoadPhoto function add the necessary code to make a simple line using a Sprite:

progressBar=new Sprite();
progressBar.graphics.lineStyle(3, 0x0000CC); //define thickness and color
progressBar.graphics.moveTo(0,0); //initial point of the line
progressBar.graphics.lineTo(imageWidth, 0); //the line will be on top
progressBar.scaleX=0; //in the beggining the progressBar will be a dot
addChild(progressBar);

Then we have to catch the size of the data that is been received, and of course it's total amount. We have to associate an event to the Loader to catch these values. For that we have to use the ProgressEvent class. So First of all add to the imports block import.events.ProgressEvent.
Then add this line after the end of the LoadPhoto function:

photoLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);

Then define a new function that handles this event:

private function progressHandler(evt:ProgressEvent):void{
     progressBar.scaleX=(evt.bytesLoaded/evt.bytesTotal);
}

This last function will receive the loaded bytes and the total byte size, and turn them into a value between 0 and 1, which is what we need to define the scaleX of the Bar. You can later add an event listener to remove the progressBar and show the asset.

In the end the Class with the Loader and a progress bar, will be something like this:


package{
     import flash.display.MovieClip;
     import flash.display.Sprite;
     import flash.display.Loader;
     import flash.display.URLRequest;
     import flash.events.ProgressEvent;

     public class LoadPhoto extends MovieClip{
          private var photoURL:URLRequest;
          private var photoLoader:Loader;
          private var progressBar:Sprite;

          public function LoadPhoto(url:String){
              progressBar=new Sprite();
              progressBar.graphics.lineStyle(3, 0x0000CC); //define thickness and color
              progressBar.graphics.moveTo(0,0); //initial point of the line
              progressBar.graphics.lineTo(imageWidth, 0); //the line will be on top
              progressBar.scaleX=0; //in the beggining the progressBar will be a dot
              addChild(progressBar);

              photoURL=new URLRequest(url);
              photoLoader=new Loader();
              photoLoader.load(photoURL);
              addChild(photoLoader);
 photoLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
         }
         
         private function progressHandler(evt:ProgressEvent):void{
              progressBar.scaleX=(evt.bytesLoaded/evt.bytesTotal);
         }
     }
}

Monday 6 June 2011

Proxy to read information

Hi,

In a situation where Flash needs to get information from another server, normally a text based information, like XML, there are security issues that need to be overcomed.

If you try to load a URLRequest using a URLLoader object, it will run normally locally, but if you publish it on the net, it won't work. That's because on network the Flash player request a security file to catch the information, from the server it wants to access.

That file is called crossdomain.xml (Maybe I'll do a article about this later), which has to be on the root of the accessed server.

But what if you don't have privileged access to the server and the administrator doesn't want to put that file for you? Probably yesterday I could ask that, but at the time it would involve a lot of people and too much time spent.

So I had to come up with an alternative solution. That solution is by making this request through a PHP (or ASP) script. In my case I'm more comfortable with PHP, and that's what I'm presenting.

It works this way:
1- Flash will make the request, including the url that it wants to access to the PHP file;
2- The PHP file will ask the url given for the information we want to read;
3- Once it gets to the PHP, it will return the information to the Flash.

The PHP won't ask for any crossdomain.xml, so is like someone making the request directly through the address bar of the browser. I read also that there maybe some servers that prevent this mechanism to work, but usually, no. In this case, there's no chance (not that I know of) to get the data unless you can get a privilege to that.

I know that Adobe has a web page with several proxy script for PHP and ASP, but yesterday I couldn't find it, but another did... and I think it's a much better script that the one of Adobe.

So here it is. This code is in http://xmlrpcflash.mattism.com/proxy_info.php

Just copy and paste to a PHP file. Call it "proxy.php" for example.



 
$post_data = $HTTP_RAW_POST_DATA;

$header[] = "Content-type: text/xml";
$header[] = "Content-length: ".strlen($post_data);

$ch = curl_init( $_GET['url'] ); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

if ( strlen($post_data)>0 ){
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}

$response = curl_exec($ch);     
$response_headers = curl_getinfo($ch);     

if (curl_errno($ch)) {
    print curl_error($ch);
} else {
    curl_close($ch);
    header( 'Content-type: ' . $response_headers['content-type']);
    print $response;
}


?>


On the Flash side, just make the call has you would normally, like this:


var xmlLoader:URLLoader = new URLLoader();

var xmlData:XML = new XML();

 

xmlLoader.addEventListener(Event.COMPLETELoadXML);



xmlLoader.load(newURLRequest("proxy.php?url=http://www.infoimafter.com/net/files/xmlinfo.xml"));



In the last line please regard "proxy.php?url=" followed by the url of the data you want to fetch.



After all this it worked very well. I thisnk this also insures that the data will be forced to refresh. I don't know if is that some servers I use, but it seems that sometimes cleaning the browser cache it's not enough to refresh data, being requested the normal way.



Cheers.