Flex tutorial: Setting tile image as background

This tutorial shows you how to fill a Canvas background with repeated images. We will make use of the BitmapData.draw() function to achieve this. Note that if the image to be repeated is from another domain (i.e. a cross domain image), you have to ensure that the domain has a cross domain policy file, and you have to set checkPolicyFile=true in order to get it working. Otherwise, you will get a security sandbox error. More explanation here.

Demo:
Tile Image Background (view source enabled)

Source Codes: main application


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:alekkus="com.alekkus.*"
	layout="absolute"
	backgroundColor="#F8F8F8">

<mx:Script>
  <![CDATA[
  	import mx.controls.Image;

	private function onClick() : void
	{
		// 1. for crossdomain images, we need to create a LoaderContext object and set its checkPolicyFile to true.
		var loaderContext : LoaderContext = new LoaderContext ();
		loaderContext.checkPolicyFile = true;

		// 2. assign that loaderContext object to an Image object
		var image : Image =  new Image();
		image.loaderContext =  loaderContext;

		// 3. set source and load
		image.source = "http://alekkus.com/flex3/extra/images/duck.jpg"
		image.addEventListener( Event.COMPLETE, onImageLoaded  );
		image.load();
	}

	private function onImageLoaded( event : Event ) : void
	{
		var image : Image = Image( event.currentTarget );

		// 1. set as tile image background
		cvsMain.setTileImage( image );
	}

  ]]>
</mx:Script>

	<alekkus:TileImageCanvas id="cvsMain" width="100%" height="100%" />
	<mx:Button x="10" y="10" label="Set background as tile image" click="onClick()" />

</mx:Application>

Source Codes: TileImageCanvas class


<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
	xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Script>
<![CDATA[
	import mx.controls.Image;

	private var _image : Image = null;

	public function setTileImage( image : Image ) : void
	{
		this._image = image;
		this.invalidateDisplayList();
	}

    override protected function updateDisplayList( unscaledWidth : Number, unscaledHeight : Number ) : void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight );

        if ( _image != null )
        {
	        var bitmap : Bitmap = Bitmap( _image.content );
	        var bitmapData : BitmapData = new BitmapData( bitmap.width, bitmap.height );
	        bitmapData.draw( bitmap );      

	        graphics.clear();
	        graphics.beginBitmapFill( bitmapData );
	        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
	        graphics.endFill();
	    }
    }
]]>
</mx:Script>
</mx:Canvas>

Flex tutorial: Enabling track pad or mouse wheel scrolling on Mac OS X

A couple of months back when Steve Jobs announced the new unibody MacBook Pro, I couldn’t resist and decided to switched to Mac. As I was settling in to the new OS, I was surprised when I learned that Flex applications do not support track pad (or mouse wheel) scrolling on the Mac OS X. This issue has been filed in the Adobe bug system, but they have yet to resolved it.

Good news is, Gabriel Bucknall has came out with an elegant solution. It’s built upon SWFObject, basically a small Javascript file used to embed Flash content (read my post on using SWFObject to embed Flash content here).

Here’s what you need to get it working using Flex Builder:

  • Embed your Flash content using the SWFObject method. (see previous post)
  • Include “swfmacmousewheel2.js” file into the “html-template” folder
  • Replace the codes within “index.template.html” file with the codes below
  • Lastly, in your application add the line “MacMouseWheel.setup( this.stage );” within the application’s addedToStage event listener

Note: If are trying this out on your local machine, you may get a security sandbox violation error #2060. You need to deploy it on a local/remote web server to get it working. I can’t find a way to get around this. Tried including crossdomain policy file, changing the params value when embedding, and tweaking the compiler options but to no luck. Let me know if anyone found a solution to this.

Demo:
Trackpad/Mousewheel Scrolling on Mac (view source enabled)

Source Codes: index.template.html


<!-- saved from url=(0014)about:internet -->
<html lang="en">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="history/history.css" />
<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>
<script src="history/history.js" language="javascript"></script>

<style>
body { margin: 0px; overflow:hidden }
</style>

</head>

<body scroll="no">
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="swfmacmousewheel2.js"></script>
<script type="text/javascript">

	var flashVars = {};

	var params = { play: "true",
				   loop: "false",
				   quality: "high",
				   wmode: "window",
				   allowscriptaccess: "sameDomain" };

	var attributes = { id: "${application}" };

	swfobject.embedSWF( "${swf}.swf",
						"divContent",
						"100%", "100%",
						"9.0.0",
						"expressInstall.swf",
						flashVars,
						params,
						attributes );

	swfmacmousewheel.registerObject( attributes.id );

</script>

<div id="divContent">
	<h1>Alternative content</h1>
	<p><a href="http://www.adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p>
</div>
</body>
</html>

Source Codes: main application


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	backgroundColor="#F8F8F8"
	addedToStage="onAddedToStage()">

<mx:Script>
<![CDATA[
	import com.pixelbreaker.ui.osx.MacMouseWheel;

	private function onAddedToStage() : void
    {
        if ( this.stage != null )
        {
        	MacMouseWheel.setup( this.stage );
        }
    }
]]>
</mx:Script>

	<mx:Canvas x="28" y="26" width="239" height="332" backgroundColor="#C6DFF6">
		<mx:Text
			x="10" y="10"
			width="201"
			text="The quick brown fox jumps over the lazy dog quick brown fox jumps over the lazy dog..... and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog....and then, the quick brown fox jumps over the lazy dog"
			fontSize="18"/>
	</mx:Canvas>
	<mx:Label x="28" y="366" text="Place your cursor within the canvas and scroll using the mouse wheel or trackpad." fontSize="12"/>
</mx:Application>

Flex tutorial: Embedding Flash content with SWFObject 2

If you are building your Flash content with Flex Builder 3 or Flash CS3, you will see that both came with a default HTML template that provides a way to embed your compiled SWF file. Although there’s nothing wrong with that way of doing it, SWFObject seems to be a better way (the author’s explanation is here). In fact in the CS4 release, Adobe has made this the standard way of embedding Flash content.

To manually work with SWFObject in Flex Builder, replace the codes in “html-template/index.template.html” with the codes below. Then place the following files into the “html-template” folder.

  • swfobject.js
  • expressInstall.swf

The files are available here, or you can download the my source files to get those files.

[update] If you are using Flex SDK 3.1 and below, deep linking (more specifically, the BrowserManager class) may not work with SWFObject. If that happens, simply replace the codes in the “history.js” file with this

Demo:
SWFObject 2 (view source enabled)

Source Codes:


<!-- saved from url=(0014)about:internet -->
<html lang="en">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="history/history.css" />
<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>
<script src="history/history.js" language="javascript"></script>

<style>
body { margin: 0px; overflow:hidden }
</style>

</head>

<body scroll="no">
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">

	var flashVars = {};

	var params = { play: "true",
				   loop: "false",
				   quality: "high",
				   wmode: "window",
				   allowscriptaccess: "sameDomain" };

	var attributes = { id: "${application}" };

	swfobject.embedSWF( "${swf}.swf",
						"divContent",
						"100%", "100%",
						"9.0.0",
						"expressInstall.swf",
						flashVars,
						params,
						attributes );
</script>

<div id="divContent">
	<h1>Alternative content</h1>
	<p><a href="http://www.adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p>
</div>
</body>
</html>

Flex tutorial: URL-based navigation using Deep Linking

One of the best new features in Flex 3 is Deep Linking. By default, a Flex application is accessible via one URL; that poses several limitations on the users. Firstly, the browser back/forward buttons no longer works the usual way. Secondly, consider an ecommerce site, if a user wants to show his/her friends a particular product information, he/she can no longer simply give out the url, as the the url will always show the default state/page of the application.

The following shows you how to solve these issues by using the BrowserManager class.

Demo:
Deep Linking (view source enabled)

Source Codes:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	backgroundColor="#F8F8F8"
	creationComplete="onCreationComplete()">

<mx:Script>
<![CDATA[
	import mx.events.ItemClickEvent;
	import mx.containers.Canvas;
	import mx.events.BrowserChangeEvent;
	import mx.managers.BrowserManager;
	import mx.managers.IBrowserManager;

	private var _browserManager : IBrowserManager = null;

	private function onCreationComplete() : void
	{
		// 1. add browserManager event listeners here
		_browserManager = BrowserManager.getInstance();
        _browserManager.addEventListener( BrowserChangeEvent.BROWSER_URL_CHANGE, onURLChange ); 		//dispatch when user typed into addr bar
		_browserManager.addEventListener( BrowserChangeEvent.APPLICATION_URL_CHANGE, onURLChange ); 	//necessary to update the url in address bar when gotoURL called has a same base url, orignially used to dispatch when setFragment is called although not use for that purpose. now setFragent is used again.
        _browserManager.init( "" );  

		// 2. explicitly call process url if fragment is empty when loaded
        if ( _browserManager.fragment == "" )
        {
        	onURLChange();
        }
	}

	 private function onURLChange( event:BrowserChangeEvent = null ) : void
  	{
  		switch ( _browserManager.fragment.toLowerCase() )
  		{
  			case "about":
  			{
  				_browserManager.setTitle( "About us | Alekkus.com" );
  				vsMain.selectedIndex = 1;
  				break;
  			}
  			case "contact":
  			{
  				_browserManager.setTitle( "Contact us | Alekkus.com" );
  				vsMain.selectedIndex = 2;
  				break;
  			}
  			default:
  			{
  				_browserManager.setTitle( "Home | Alekkus.com" );
  				vsMain.selectedIndex = 0;
  			}
  		}
  	}

  	private function onChildIndexChange( event : ItemClickEvent ) : void
  	{
  		var canvasLabel : String = Canvas( vsMain.getChildAt( event.index ) ).label;

  		_browserManager.setFragment( canvasLabel.toLowerCase() );
  	}
]]>
</mx:Script>

	<mx:LinkBar x="10" y="10" dataProvider="{ vsMain }" itemClick="onChildIndexChange( event )"/>

	<mx:ViewStack
		id="vsMain"
		x="0" y="36"
		width="252" height="177">

		<!-- Home -->
		<mx:Canvas
			label="Home"
			width="100%" height="100%">

			<mx:Label text="Home page" x="10" y="10" fontSize="28"/>
		</mx:Canvas>

		<!-- About us -->
		<mx:Canvas
			label="About"
			width="100%" height="100%">

			<mx:Label text="About us" x="10" y="10" fontSize="28"/>
		</mx:Canvas>

		<!-- Contact us -->
		<mx:Canvas
			label="Contact"
			width="100%" height="100%">

			<mx:Label text="Contact us" x="10" y="10" fontSize="28"/>
		</mx:Canvas>
	</mx:ViewStack>

	<!-- Instructions -->
	<mx:Label x="10" y="224" text="*Notice that the url changes when you navigate thru different pages."/>
	<mx:Label x="10" y="250" text="*You can also use the browser back/forward button to navigate."/>
	<mx:Label x="10" y="276" text="*Manually typing in the url also works. e.g. .http://alekkus.com/...#contact"/>

</mx:Application>

Fiat’s Eco:Drive AIR Application at Adobe Max 2008/09

During the Adobe Max 2008/09 in Milan, team members from AKQA demonstrated a very interesting AIR application, the Fiat’s Eco:Drive.

The concept of Eco:Drive is explained here:

Serge Jespers and Andrew Shorten had an interview with the team after that. You can watch the interview here.

Flex tutorial: Resizable window

Often, a movable/draggable window is also resizable. The following will show you how to make your customized window resizable.

Demo:
Resizable Window (view source enabled)

Source Codes:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	backgroundColor="#F8F8F8">

<mx:Script>
<![CDATA[
	import mx.events.FlexEvent;
	import mx.core.UIComponent;

	private var _window : UIComponent;
	private var _originalWidth : Number;
	private var _originalHeight : Number;
	private var _mouseDownPosition : Point;

	private function onResizeMouseDown( event : MouseEvent ) : void
	{
		// 1. set _window
		_window = UIComponent( UIComponent( event.currentTarget ).parent );

		// 2. add mouse move and mouse up event listeners
		this.systemManager.addEventListener( MouseEvent.MOUSE_MOVE, onResizeMouseMove, true );
		this.systemManager.addEventListener( MouseEvent.MOUSE_UP, onResizeMouseUp, true );									

		// 3. save original width, height, rotation
		_originalWidth = _window.width;
		_originalHeight = _window.height;	

		// 4. save mouse down position
		_mouseDownPosition = new Point( event.stageX, event.stageY );
	}

	private function onResizeMouseMove( event : MouseEvent ) : void
	{
		// 1. prevent any other mouse up events to happen
		event.stopImmediatePropagation();

		// 2. calculate new width, height
		var newWidth:Number = _originalWidth + ( event.stageX - _mouseDownPosition.x );
		var newHeight:Number = _originalHeight + ( event.stageY - _mouseDownPosition.y );			

		// 3. resize window
		_window.setActualSize( newWidth, newHeight );
	}

	private function onResizeMouseUp( event : MouseEvent ) : void
	{
		// 1. prevent any other mouse up events to happen
		event.stopImmediatePropagation();	

		// 2. remove event listeners
		this.systemManager.removeEventListener( MouseEvent.MOUSE_MOVE, onResizeMouseMove, true );
		this.systemManager.removeEventListener( MouseEvent.MOUSE_UP, onResizeMouseUp , true );
	}

	private function doDrawTriangle( event : FlexEvent ) : void
	{
		var uiComp : UIComponent = UIComponent( event.currentTarget );

		uiComp.graphics.clear();
		uiComp.graphics.beginFill( 0xB1DAFA );
		uiComp.graphics.moveTo( uiComp.width, 0 );
		uiComp.graphics.lineTo( uiComp.width, uiComp.height );
		uiComp.graphics.lineTo( 0, uiComp.height );
	}
]]>
</mx:Script>

	<mx:Canvas
		id="cvsMain"
		x="37" y="31" width="260" height="160"
		borderColor="#999999" backgroundColor="#FFFFFF" borderStyle="solid" dropShadowEnabled="true" borderThickness="2"
		horizontalScrollPolicy="off" verticalScrollPolicy="off">

		<!-- Resize triangle -->
		<mx:UIComponent
			x="{ cvsMain.width - 24 }" y="{ cvsMain.height - 24 }"
			width="20" height="20"
			creationComplete="doDrawTriangle( event )"
			mouseDown="onResizeMouseDown( event )" />

		<!-- Instruction -->
		<mx:Label x="16" y="59" text="Drag the blue triangle to resize" fontSize="14"/>
	</mx:Canvas>
</mx:Application>

  This blog is powered by WordPress with GimpStyle Theme design by Horacio Bella.