Loader class with content scaling

Some time ago I needed a loader object that would allow scaling the content. So I simply created a class that extends the Loader class itself and adds that extra feature to it. The scaling occurs write after the content has been loaded and during resizing. I’ve named the class SimpleLoader and it has a Boolean property that allows the scaling when set to true, otherwise it just behaves like the standard Loader class.

I thought I should share it with you, so here it is. The class is documented so you should have no problem understanding it. Feel free to use it as you like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package {
 
	import flash.display.Loader;
	import flash.events.Event;
 
 
	/**
	 * class SimpleLoader
	 * 
	 * @author negush
	 */
	public class SimpleLoader extends Loader {
 
		/**
		 * The width and height setters have effect only after the content has been loaded.
		 */
 
		private var _scale:Boolean = false;
		private var _width:Number = 0;
		private var _height:Number = 0;
 
		private var scaleRatio:Number;
 
 
		/**
		 * Constructor.
		 */
		public function SimpleLoader() {
			super();
			this.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
		}
 
 
		/**
		 * Handler function for the Event.COMPLETE event. Initializes the width and height of the
		 * content and calculates the scale ratio of the image, used when the loader is resized
		 * with the content being scaled. Catches the Loader's event and dispatches it as SimpleLoader.
		 */
		private function completeHandler(evt:Event):void {
			// The initial size of the content.
			this._width = this.contentLoaderInfo.width;
			this._height = this.contentLoaderInfo.height;
			// The scale ratio content_width / content_height.
			this.scaleRatio = this.contentLoaderInfo.width / this.contentLoaderInfo.height;
			if (this.scale) scaleToWidth();
			var newEvent:Event = new Event(Event.COMPLETE);
			dispatchEvent(evt);
		}
 
 
		/**
		 * Resizes the loader keeping the aspect ratio according to the new width. In this case the
		 * new height is calculated so that the content keeps its aspect ratio according to the
		 * loader's new width.
		 */
		private function scaleToWidth():void {
			this._height = Math.round(this.width / this.scaleRatio);
			super.width = this._width;
			super.height = this._height;
		}
 
 
		/**
		 * Resizes the loader keeping the aspect ratio according to the new height. In this case the
		 * new width is calculated so that the content keeps its aspect ratio according to the
		 * loader's new height.
		 */
		private function scaleToHeight():void {
			this._width = Math.round(this.height * this.scaleRatio);
			super.width = this._width;
			super.height = this._height;
		}
 
 
		//***********************************************************************
		//
		//	getters and setters
		//
		//***********************************************************************
 
		/**
		 * Setter/getter for the _scale property. Activates or deactivates the scaling for the
		 * current loader instance. If the scale is set to true, the content's height will be
		 * recalculated so that the content keeps the current width but will have the original
		 * aspect ratio.
		 * 
		 * true = resize keeping content aspect ratio
		 * false = resize without keeping content aspect ratio
		 * 
		 */
		public function set scale(value:Boolean):void {
			if (this._scale == value) return;
			this._scale = value;
			if (value) scaleToWidth();
		}
 
		public function get scale():Boolean {
			return this._scale;
		}
 
 
		/**
		 * Overrides the Loader's width setter and getter. The setter resizes the content
		 * according to the scale property's value.
		 */
		override public function set width(value:Number):void {
			if (this._width == value) return;
			this._width = value;
			if (this.scale) scaleToWidth();
			else super.width = value;
		}
 
		override public function get width():Number {
			return this._width;
		}
 
 
		/**
		 * Overrides the Loader's height setter and getter. The setter resizes the content
		 * according to the scale property's value.
		 */
		override public function set height(value:Number):void {
			if (this._height == value) return;
			this._height = value;
			if (this.scale) scaleToHeight();
			else super.height = value;
		}
 
		override public function get height():Number {
			return this._height;
		}
 
	}
 
}

UPDATE:
And here is how you can use it. It works just like the Loader class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import SimpleLoader;
 
var ldr:SimpleLoader = new SimpleLoader();
ldr.load(new URLRequest("myimage.jpg"));
ldr.x = 20;
ldr.y = 20;
ldr.scale = true;
addChild(ldr);
 
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
 
function completeHandler(evt:Event):void {
	ldr.width = 300;
	ldr.height = 100;
	trace("loader size: "+ldr.width+" x "+ldr.height);
}

ActionScript 3.0 code performance tester

I just found a cool Flex application that shows some tests for various ActionScript 3.0 code blocks like loops, increments, division or Array instantiation. This might be good to know when you work on a project that should have code that executes fast. Here’s the link: http://businessintelligence.me/projects/performance_tester/performanceTester.html

Syntax highlighting for WordPress

Finally managed to install this neat syntax highlighter plugin for WordPress. I wanted to do that for some time but didn’t really have the time for that. Now, it’s done… I’ve installed it… See the proof below.

import fl.controls.Button;
 
/**
 * This is a simple function that creates a button on the stage. Really, there's
 * nothing interesting about it.
 */
function foo():void {
	var newButton:Button = new Button();
	this.addChild(newButton);
	newButton.x = 100;
	newButton.y = 100;
	newButton.label = "Hit me!";
	newButton.addEventListener(MouseEvent.CLICK, clickHdl);
}
 
// This is when you know that the button was clicked.
function clickHdl(evtObj:MouseEvent):void {
	trace("Can you read this ?");
}
 
// Calling the main function.
foo();

Maybe I’ll find some time to customize it a little

Loader is not resizing

In ActionScrirpt 3.0 the way to load external media content like images or .swf files is to use the Loader class. The instance of this class is a DisplayObject too (actually a DisplayObjectContainer) which loads the content inside it and has to be added to display list to be viewed, just like any other DisplayObject.

The way you have to load the external content is a little bit different in AS3 using the Loader class than in AS2, using the well known MovieClip.loadMovie() method or loadMovieNum(). It resembles more on using the MovieClipLoader class from AS2.

Here is an example. If you want to load an image called flower.jpg and display it, here’s what you have to do:

  • - create the loader object:
    var loaderObject:Loader = new Loader();

  • - set the coordinates:
    loaderObject.x = 150;
    loaderObject.y = 45;

  • - add the loader to the display list:
    addChild(loaderObject);

At this point, anything you load inside it will be visible on the stage. If you would load the content without adding the loader object to the stage, there wouldn’t be anything displayed until the addChild() method call.

  • - you need to create a URLRequest object which is based on the URL of the content itself:
    var request:URLRequest = new URLRequest("flower.jpg");

  • - now you can instruct the Loader instance to load the image:
    loaderObject.load(request);

You could use a shortcut and combine the previous two lines into a single line of code:

loaderObject.load(new URLRequest("flower.jpg"));

Sometimes the content you want to load has a larger size than the stage or the area where you want to display it. So, you’ll have to resize the loader. Doing it write after the load() method call would result in not displaying anything, even if the content has been successfully loaded. This is because the loader gets resized after the load() method but before the content gets fully loaded (especially if it has a larger file size).

The solution for this problem is to always resize the Loader object after the content has completely loaded. To do this, you need to listen for the event the loader dispatches when it finishes loading the content: Event.COMPLETE:

loaderObject.contentLoaderInfo.addEventListener(Event.COMPLETE, resizeLoader);

function resizeLoader(evtObj:Event):void {
    loaderObject.width = 400;
    loaderObject.height = 300;
}

How to use Timer class instead of setInterval()

In ActionScript 3.0, the preferred way to execute actions at specific time intervals is the use of the new Timer class. In ActionScript 2.0, we had the setInterval() function and this was the way to use it:
- write a function that would be called every time the time interval passed the limit
- call the setInterval() function that would receive as parameters the object that has the target function defined (not always necessary), the name of the function (or a reference to it), the time interval at which to call the target function and the list of parameters for the target function (also not necessary)
- to stop the time interval there should have also been a variable defined to hold the interval id and then call clearInterval() with the interval’s id as parameter.

AS2 example – call a function 10 times

For example, the next piece of code will call timeHandler 10 times and then interrupt the repeated calls of the function:

var counter:Number = 0;
var intervalID:Number;

function timerHandler(param:String):Void {
counter++;
trace(“This function has been called “+counter+” times with the \”"+param+”\” parameter”);
if (counter == 10) clearInterval(intervalID);
}

intervalID = setInterval(timerHandler, 1000, “test”);

AS3 example

For AS3, the steps are similar but setInterval() was replaced by the Timer class. Here is the above code translated into AS3:

import flash.utils.Timer;
import flash.events.TimerEvent;

var counter:int = 0;
var timerObject:Timer = new Timer(1000, 10);
timerObject.addEventListener(TimerEvent.TIMER, timerHandler);
timerObject.start();

function timerHandler(eventObject:TimerEvent):void {
counter++;
trace(“This function has been called “+counter+” times”);
}

AS3 code explained

You can see that when creating a new instance of the Timer class, the constructor has two parameters passed to it: the first is the time interval (in milliseconds) and the second is the number of repetitions, that is the number of times to call the handler function. If the second parameter is not given or it’s 0, then the timer repeats infinitely. Next, you need to define the handler function for the TimerEvent.TIMER event, which gets dispatched every time the time interval is passed. The Timer class also dispatches another event, TimerEvent.TIMER_COMPLETE. This event is dispatched only when the timer object has finished the number of repetitions. If the repeatCount, the second parameter of the Timer constructor is not defined or it’s 0, then the TIMER_COMPLETE event will never get called. Once you create the Timer instance, you need to start it (timerObject.start()) otherwise it won’t have any effect.

As you can see, for the AS3 version, you cannot pass any parameters directly to the timer event handler functions. If you want to get the same result as the AS2 example, then you need to create another function that would be called by the timer event handler and get the parameter passed to this second function:

function timerHandler(eventObject:TimerEvent):void {
callback(“test”);
}

function callback(param:String):void {
counter++;
trace(“This function has been called “+counter+” times with the \”"+param+”\” parameter”);
}

The Timer class

The Timer object is more complex and offers us more information on the current interval calls. We can have access to the number of repetitions the Timer object has reached (timerObject.currentCount), the total number of repetitions (timerObject.repeatCount), the time interval (timerObject.delay) and we can even find out if the Timer object is running or not (timerObject.running).

By using the Timer class, you also have the ability to stop the repetitions (timerObject.stop()) and then resume it, if you call the start() method again. It even has the possibility to reset the counter (timerOject.reset()) and the Timer object will start the repetitions all over again.

Get the number of repetitions from the Timer object

As mentioned previously, you can access different parameters of the Timer object and you can do it even in the timer event handler function. The next example displays the number of times the function has been called, without having to define an extra variable for that:

import flash.utils.Timer;
import flash.events.TimerEvent;

var timerObject:Timer = new Timer(1000, 10);
timerObject.addEventListener(TimerEvent.TIMER, timerHandler);
timerObject.start();

function timerHandler(eventObject:TimerEvent):void {
trace(eventObject.target.currentCount+” repetitions out of “+eventObject.target.repeatCount);
}

As you can see, the Timer class is a welcome addition to the ActionScript 3 framework. Enjoy it.

Promotion for text effect with reflection

Jumpeye has just launched a short promotion for a limited edition of TxEff: TxEff with reflection. All you have to do is to create your own text animation on www.txeff.com, save it and then embed it into your own site using the HTML code provided on txeff.com. Just like I did…

Hurry up ! It’s only available for a few days…

5005: Unknown error optimizing byte code

This is a really “interesting” error message that Flash throws in the Output panel and unfortunately there is no other explanation accompanying the message. At Jumpeye we’ve had to deal a few times with this error message which seems to be generated whenever working with large .fla files that make use of rather large amounts of code.

The solution would be to turn off the Optimizer and then recompile. You can turn the Optimizer off from the Publish Settings dialog box, select Settings for the “ActionScript 3.0″ option and in that dialog box disable the “Reduce file size and increase performance” option. You can do this whenever you are working on a very large project and get this error message. In the rest of the cases, you should leave this option checked.

Another solution I’ve found on the web (didn’t test it) is to delete the .aso files generated by Flash (Control -> Delete ASO Files) .

Access FlashVars parameters with AS3

Many people use FlashVars as a way to send parameters to the flash movie playing in the browser. This way the parameters are imported as root level variables.

Using ActionScript 1 and 2 these variables can be accessed easily from the root level, like this: _root.parameterName. So, if you would send two parameters and their values (xmlFile=setup.xml&imageFile=picture.jpg) to the flash movie, you would access their values like this:

trace(“the xml file is: “+_root.xmlFile);
trace(“the image file is: “+_root.imageFile);

This changes when it comes to ActionScript 3. You cannot access _root.xmlFile or _root.imageFile, simply because these variables do not exist on the root level. They haven’t been declared so the compiler throws an error. The new way to access the FlashVars parameters using ActionScript 3 is to use the LoaderInfo class. Every DisplayObject contains a property called loaderInfo which is an instance of the LoaderInfo class. An object of this class contains a property called parameters. This is an object that enumerates the list of FlashVars parameters and their values. You would access these parameters like this:

var paramList:Object = this.root.loaderInfo.parameters;
trace(“the xml file is: “+paramList["xmlFile"]); // you could also use paramList.xmlFile
trace(“the image file is: “+paramList["imageFile"]); // and paramList.imageFile