Thursday 25 August 2011

Access modifiers

Hello everyone,

This post is somehow a way to remember some things that might pass you by, specially if you don't use them very often.

Normally when I define my classes, everything is private unless some method or variable must provide values to another class. Even at this point I consider on putting a callback instead of a public value.

But recently I had the need to explain what a "protected" class was.

Well first of all, in AS3, all classes must be declared public, but their methods or variables can be public, private, internal and protected.

So what's the difference between them?

I'll make a brief description of each one. Then you have useful links if you want further explanations.

Public - These are accessible by everyone. Other classes in the same or another package can access these methods or variables.

Private - Only the class can access them. External class can't see them

Protected - These methods and variables are only accessible for subclasses. If you declare a class by inheriting from another with protected methods or variables, this children class can access these. If it's not a children class these methods or variables are inaccessible.

Internal - All methods and variables declared as "internal" are only shared across the same package.

I think is very straightforward, and only depends of what you're doing and how you plan to do things.

The following links can enlighten you a bit more:
Greenthumb
Adobe
Article on Kirupa.com from Senocular

Hope this helps... it did for me ;)

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.

Thursday 12 May 2011

Loading and resizing image

This is a simple task to achieve. The AS3 has already a component that does this, but if you want to keep your SWF footprint to a minimum, you must consider this solution.

Nothing to it, but I seem to keep always forgetting, since I don't deal with this problem very often.

But here it is for future reference.

First of all we will be using two classes. One is URLRequest, that will capture the HTTP request for a file with its url. The other is the Loader which is used to load external SWF or image files (PNG, JPG or GIF).

First of all import these two classes:

import flash.display.Loader;
import flash.net.URLRequest;

Then instantiate the Loader class outside any function, because we will need it to resize later on.

private var myLoader:Loader;


Inside the loadImage function instantiate the URLRequest class by giving it the file url you which (the url can be a relative path. In this case there's no need to place the HTTP protocol).


Associate the Loader with this URLRequest, and finally add it to the DisplayList.


private function loadImage(file:String):void{
     var myRequest:URLRequest = new URLRequest(file);
     myLoader = new Loader();
     
     myLoader.load(myRequest);
     addChild(myLoader);
}

loadImage("mypicture.jpg");

If you run this, you will see the image "mypicture.jpg" in the stage.

The next step is to scale the image. Try and write the following lines inside the previous function:

myLoader.width=20;
myLoader.height=40;

What happens? The image doesn't appear. So what's going on?

We are trying to scale an object when the object does not have any contents yet.

We have to listen to the myLoader object to see if it has already load the picture and then we can scale.

Write the previous function like this adding the line in red:


private function loadImage(file:String):void{
     var myRequest:URLRequest = new URLRequest(file);
     var myLoader:Loader = new Loader();
     myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, resizeImage);
     myLoader.load(myRequest);
     addChild(myLoader);
}

Don't forget to add the Event class on the import statements.

The function for resizing by now you should have guessed it:

private function resizeImage(evt:Event):void {
myLoader.width = 45;
myLoader.height = 40;
}

Simple, right?

Happy resizing.


Thursday 6 January 2011

Usability: Click and Drag cursor

Although it's a common feature in many flash applications a little feedback for users is always welcome... specially when you have a "click and drag" situation.

Recently I came across this request for an infography for a client. I make the infography, but the application didn't have a feedback for the user that that area was meant to be draggable, only a small phrase stating that.

I agreed that this would make sense and made the change.

To substitute the regular Windows mouse icon with one of your own, you must first import the class that controls the mouse UI options, like this:

import flash.ui.Mouse;

This class let's you use two important features for mouse icon... the hide and show options.

If you put it like this:
Mouse.hide();

The mouse icon will disappear, although the mouse still works, but you don't know where it is.

The reverse option will be the show option, like this:
Mouse.show();

You must import also the MouseEvent class, to set the listeners later:
import flash.events.MouseEvent;

Now that we have our hide and show options, how can you make a custom icon and make it follow the mouse position?

Making it simple you have to add a listener for the mouse position, but this is made indirectly, since we are going to listen for any mouse move, and then see where it is.
Making an EnterFrame event can be costly specially if you're application has many pictures or video, like the one I had to make, so we're listening for any mouse move, which is triggered when... you guessed it... the mouse is moved.

First of all, make a movieclip with the icon you wish to appear, and place it in the library with a export actionscript name. I will call it MyLibraryCursor (remember that when making the movieclip, the "plus" sign indicates where will be the click spot for the mouse).

Make a new object with this Library Class:
public var myCursor:MyLibraryCursor;

Then on the init() function of your main class, define your new object, along with two important options:
myCursor = new MyLibraryCursor();
myCursor.mouseEnabled = false;
myCursor.mouseChildren = false;

mouseEnable tells flash if this object receives mouse behaviours. Usually that's a problem when you have many movieclips on the stage, where you can have problems with object focus (this will not disable mouse events).

mouseChildren is put there to prevent event bubbling. Has you know AS3 has a great feature, but sometimes difficult to control and understand, which is the propagation of events between children of a display object (bubbling). This prevents it from happening (a typical case of this is when you have a text box with text, and the mouse is only active when you pass by the line of a letter).

Next we will add the mouse movieclip to the stage:
addChild(Global.myCursor);

Make the "windows" mouse disappear:
Mouse.hide();

And then listen to the MOUSE_MOVE to make it follow the mouse:
this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);

This calls the mouseMoveHandler function which will move the custom icon to the mouse position:
public function mouseMoveHandler(evt:MouseEvent):void
{
myCursor.x = evt.stageX;
myCursor.y = evt.stageY;
}

And that's it, the basics for replacing the windows cursor, for one of you're own.

Possibly in a future post I will explain other option for this, cleaning a bit the behaviours about this.

You can make a Global class to easy the control of the mouse behaviour if you have to hide, show and turning off and on, between different display objects across your application... this maybe will to go for a later post.

Cheers.