Friday, April 30, 2010

Flex 3: RTE Bullet and Align button issue

While working with Rich Text Editor component of Flex 3, I cam across with strange issue.

Try out following flow. On fresh launch change Font / Font Size / Font Color / Bold / Italic / Underline and then if you click on either alignment buttons or Bullet button. Ideally all formatting setting should retain and whatever you type should have these formatting. But it is failing. The formatting will revert back to the default values.

I tried to find out the actual issue, In the RichTextEditor.mxml, within the setTextStyles function. New text format instance is been created in Bullet and align button click condition. This new TextFormat object overwrites the previously set formatting.

else if (type == "align" || type == "bullet")
{
if (beginIndex == endIndex)
{
tf = new TextFormat();
}

To overcome this issue I have written a fix in the mxml where RTE instance is been created. To fix this issue, I just had assigned the formatted values to the newly created TextFormat object, Doing this will retain the previously set formatting.
Following is the code snippet for the fix.

public function checkForFormating():void
{
var textField:IUITextField = textArea.getTextField();
var beginIndex:int = textField.selectionBeginIndex;
var endIndex:int = textField.selectionEndIndex;
if (beginIndex == endIndex)
{
var tf:TextFormat;
tf = textField.defaultTextFormat;

tf['font'] = fontFamilyCombo.text;

var fontSize:uint = uint(fontSizeCombo.text);
if (fontSize > 0)
tf['size'] = fontSize;

tf['color'] = uint(colorPicker.selectedColor);

tf['bold'] = boldButton.selected;
tf['italic'] = italicButton.selected;
tf['underline'] = undoButton.selected;

if (alignButtons.selectedIndex == 0)
tf.align = "left"
else if (alignButtons.selectedIndex == 1)
tf.align = "center"
else if (alignButtons.selectedIndex == 2)
tf.align = "right"
else if (alignButtons.selectedIndex == 3)
tf.align = "justify"

tf['bullet'] = bulletButton.selected;

if (lineSpaceButton.selectedIndex == 0)
tf.leading = "2"
else if (lineSpaceButton.selectedIndex == 1)
tf.leading = "4"
else if (lineSpaceButton.selectedIndex == 2)
tf.leading = "8"

textField.defaultTextFormat = tf;
}
}
In this function, basically i have reassign all the formatting based on the default formatting property. All you have to do is call this function on bullet / align button click. Add a Mouse Click listener and call this function on handler.

This will resolve the issue. I have tested this and it works fine, Let me know if you find any issue in this.

Read more...

Wednesday, April 28, 2010

Flex 3: Cross Domain XML Loading

Flash Player has security feature, This security is basically domain based. It will allow a swf from specific domain to load assets, data or it will allow communication between two swf files from that domain. When a particular swf file is loaded in flash player, Security sandbox is created for that particular domain. This mean swf file in that domain will have access to all assets, data of that sandbox.

If a swf file from any particular domain wants a access to data or assets of any other domain, we need to have cross-domain policy file available on remote server. This crossdomain.xml needs to be structure in predefined format, Which will be read by the swf player and depending upon the tags, it will allow access to that server.

Following is the sample code for crossdomain.xml.

<?xml version="1.0"?>
<cross-domain-policy>
<!-- below tag will allow access from any domain. -->
<allow-access-from domain="*"/>
<!-- below tag will allow access to www.shaileshmak.000fees.net domain. -->
<allow-access-from domain="www.shaileshmak.000fees.net"/>
<!-- below tag will allow access to any sub domain of 000fees.net domain. -->
<allow-access-from domain="*.000fees.net"/>
<!-- below tag will allow access to 105.216.0.40 ip. -->
<allow-access-from domain="105.216.0.40"/>
</cross-domain-policy>
If a swf tries to access any data from other domain, swf player by default search for the crossdomain.xml file at root directory of the remote server. If the crossdomain.xml is placed other than the root directory, We can access that file using Security.loadPolicyFile(); function.

e.g.
Security.loadPolicyFile(http://www.shaileshmak.000fees.net/MyWork/crossdomain.xml);
Make sure you are loading this crossdomain.xml file, before loading the assets from the remote server.

I have created a Flex example for loading xml into the datagrid, In this example, the data xml file is located at remote server and the swf file from different server is accessing this xml and loading it into the datagrid.

Following is the sample code of the application.

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

<mx:HTTPService id="service"
showBusyCursor="true"
url="http://shailesh.ihemant.com/employee.xml"
resultFormat="object"
result="serviceResultHandler(event)"
fault="serviceFaultHandler(event)"/>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;

[Bindable]
private var employeeCollection:ArrayCollection;
private function init():void
{
employeeCollection = new ArrayCollection();
}

private function serviceResultHandler(event:ResultEvent):void
{
employeeCollection = event.result.Employee_Info.Employee as ArrayCollection;
}

private function serviceFaultHandler(event:FaultEvent):void
{
Alert.show(event.toString());
}

private function getEmployeeHandler():void
{
service.send();
}
]]>
</mx:Script>

<mx:Button id="getEmployee"
label="Get Employee"
click="getEmployeeHandler();"/>

<mx:DataGrid id="grid"
width="80%"
dataProvider="{employeeCollection}">
<mx:columns>
<mx:DataGridColumn dataField="Name" headerText="Name"/>
<mx:DataGridColumn dataField="Designation" headerText="Designation"/>
<mx:DataGridColumn dataField="Email" headerText="Email"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
Look at the demo application.

Read more...

Sunday, April 25, 2010

Flex 4: New components and containers

With the introduction to new Flash Builder 4 (Flex 4 - code base Gumbao), There are changes in the component architecture. Flex 4 SDK introduce number of new components and container with new architecture. This will make developers life much easier, as the skinning, effects and other customization now will be much straight forward. In Flex 4 new component they have introduced Spark Components.

Following table list out the Flex 3 component and their Flex 4 Spark counter part.

Flex 3 MX Component Flex 4 spark Component
mx.controls.Button spark.components.Button
mx.controls.ButtonBar spark.components.ButtonBar
mx.controls.CheckBox spark.components.CheckBox
mx.controls.ComboBox spark.components.DropDownList (w/o editability)
mx.controls.HorizontalList spark.components.List (with a HorizontalLayout)
mx.controls.HRule spark.primitives.Line
mx.controls.HScrollBar spark.components.HScrollBar
mx.controls.HSlider spark.components.HSlider
mx.controls.Image spark.primitives.BitmapImage (w/o support for external images)
mx.controls.LinkBar spark.components.ButtonBar (with a custom skin)
mx.controls.LinkButton spark.components.Button (with a custom skin)
mx.controls.List spark.components.List
mx.controls.NumericStepper spark.components.NumericStepper
mx.controls.RadioButton spark.components.RadioButton
mx.controls.RadioButtonGroup spark.components.RadioButtonGroup
mx.controls.TextArea spark.components.TextArea
mx.controls.TabBar spark.components.TabBar
mx.controls.TextInput spark.components.TextInput
mx.controls.TileList spark.components.List (with a TileLayout)
mx.controls.ToggleButtonBar spark.components.ButtonBar
mx.controls.VideoDisplay spark.components.VideoPlayer
mx.controls.VRule spark.primitives.Line
mx.controls.VScrollBar spark.components.VScrollBar
mx.controls.VSlider spark.components.VSlider
mx.core.Application spark.components.Application
mx.core.Window spark.components.Window
mx.core.WindowedApplication spark.components.WindowedApplication
mx.containers.ApplicationControlBar spark.components.Application (with the controlBarContent)
mx.containers.Canvas spark.components.Group
mx.containers.ControlBar spark.components.Panel (with the controlBarContent property)
mx.containers.HBox spark.components.HGroup
mx.containers.Panel spark.components.Panel
mx.containers.Tile spark.components.Group (with a TileLayout)
mx.containers.VBox spark.components.VGroup

These components/containers are developed based on the UIComponent. There are few components/containers who is not having Spark counterpart. Following table demonstrate the list of components/container without Spark counterpart.

Flex 3 classes with no direct Flex 4 counterpart

mx.controls.Alert
mx.controls.ColorPicker
mx.controls.DataGrid
mx.controls.DateChooser
mx.controls.DateField
mx.controls.Menu
mx.controls.MenuBar
mx.controls.PopUpButton
mx.controls.PopUpMenuButton
mx.controls.ProgressBar
mx.controls.RichTextEditor
mx.controls.Tree
mx.containers.Accordion
mx.containers.DividedBox
mx.containers.Form
mx.containers.Grid
mx.containers.TabNavigator
mx.containers.TitleWindow
mx.containers.ViewStack

I am very excited about new architecture in Flex 4. I know you all too.

I will come up with some tutorial very soon in Flex 4.

Read more...

Saturday, April 24, 2010

Flex 3: Dispatch custom event

In this tutorial, I will walk through the Custom Even handling in Flex 3. Like Flex 3 inbuilt events, you can dispatch your custom event from the custom component. To do this we need to create an Custom Event class inherited from Flex based Event class. After this you can dispatch this custom event from your component or class using dispatch event function. Even you can add this event inline to your custom component tag in mxml file. To get the inline event property we need to set Metadata for the custom Event in component mxml.

In this tutorial, we will create an application which will have login form. And on login we will dispatch the custom LOGIN Event. To complete this application it will need to create following files.

  • Login.mxml

  • LoginEvent.as

  • Main.mxml


To start with, we will create an flex application in Flex Builder. While creating the project give your main mxml application file name as Main.mxml

Next, we will create the Login component, which will have the simple login form. This form will have two elements as, User Id: and Password:. To create this mxml component first we will set the folder structure to allocate the respective files. We will keep Component within src.view.components folder, and custom events within src.event folder.

First create these folders in src folder as show in the below image.



Now we are ready with packages, Next we will create the MXML Component named Login.mxml within the src.view.components folder. This Login.mxml will be based on Panel with no default width and height.

Replace following code to complete the Login Form.
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" title="Login" width="302" height="152">
<mx:Form width="100%">
<mx:FormItem label="User ID">
<mx:TextInput id="userid" />
</mx:FormItem>
<mx:FormItem label="Password">
<mx:TextInput id="password" displayAsPassword="true" />
</mx:FormItem>
<mx:FormItem>
<mx:Button id="btnLogin" label="Login" click="loginHandler()"/>
</mx:FormItem>
</mx:Form>
</mx:Panel>
In above code snippet, we have created the simple login Form containing two input field, User Id and Password respectively and one Login button.

We need to dispatch custom Login Event on Login Button click, For this first we have to create LoginEvent class.
Create LoginEvent class within src.events package. Make sure you extend this class to flex inbuilt Event class. There are few things we need to follow to create custom event.

You are require to override the Event.clone() method. This method will return the clone reference of your custom event i.e. LoginEvent.
You can create your custom properties that are required by the custom event. In our example LoginEvent will need to have userId and passWord.

In LoginEvent class add following code snippet to complete the CustomEvent class.
package events
{
import flash.events.Event;

public class LoginEvent extends Event
{
public static const LOGIN:String = 'login';

public var userId:String = '';
public var password:String = '';

public function LoginEvent(type:String, userId:String, password:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);

this.userId = userId;
this.password = password;
}

override public function clone():Event {
return new LoginEvent(type, userId, password);
}
}
}
In the above code snippet, We have created the static const for event type, this we will use when we will dispatch or add event. Also we have created the two public properties userId and password, which we will send along with event when we dispatch this event.

Now we are ready with LoginEvent class, next we have to dispatch this event when user clicks on the Login button from the Login.mxml. Open Login.mxml file and add click handler function for Login button. In this function we will dispatch the LoginEvent along with userId and password property. Add this function in your Script tag within Login.mxml as shown below.
 <mx:Script>
<![CDATA[
import events.LoginEvent;
private function loginHandler():void
{
this.dispatchEvent(new LoginEvent(LoginEvent.LOGIN),userid.text, password.text)
}
]]>
</mx:Script>

If you noticed in above code, we have dispatch the LoginEvent on loginHandler function. We are ready with custom login component which will dispatch the Login event. But to add this custom login Event inline to the Login tag we need to se the metadata in Login.mxml. To do this add following code just above the Script tag.
<mx:Metadata>
[Event(name="login", type="events.LoginEvent")]
</mx:Metadata>
Remember you the name what we have mention in the name property above will be used in the Login tag as inline event property.

Now your complete Login.mxml will look like as below.
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" title="Login" width="302" height="152">
<mx:Metadata>
[Event(name="login", type="events.LoginEvent")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import events.LoginEvent;
private function loginHandler():void
{
this.dispatchEvent(new LoginEvent(LoginEvent.LOGIN),userid.text, password.text)
}
]]>
</mx:Script>
<mx:Form width="100%">
<mx:FormItem label="User ID">
<mx:TextInput id="userid" />
</mx:FormItem>
<mx:FormItem label="Password">
<mx:TextInput id="password" displayAsPassword="true" />
</mx:FormItem>
<mx:FormItem>
<mx:Button id="btnLogin" label="Login" click="loginHandler()"/>
</mx:FormItem>
</mx:Form>
</mx:Panel>
Now we will add this custom component in the Main.mxml file and we will check whether we are getting the LOGIN event from Login.mxml component. To do so add following code in your Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="vertical"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:components="view.components.*">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import events.LoginEvent;

private function loginHandler(event:LoginEvent):void
{
Alert.show('Loign Event Handled Successfully for user id '+event.userId);
}
]]>
</mx:Script>
<components:Login login="loginHandler(event)"/>
</mx:Application>
If you notice in above code, we have added custom Loign component. And if you see the namespace for Login tag is components. We have added metadata for login event in Login.mxml and that we have used inline to the <components:Login> tag.

This is how we can use the Custom component in Flex.

I hope this will help.

View Demo here.

Read more...

Monday, April 19, 2010

Flex 3: Calling ActionScript Function from javaScript

In my earlier tutorial, we have seen how we can call JavaScript function from Flex application.

Today I will explain reverse functionality of calling Action Script function from JavaScript. Using ExternalInterface class of Flex library we can invoke Action Script function from JavaScript. To do this first we have to map the function in Action Script using addCallback method. This is static method of class ExternalInterface.

For this tutorial we will create an input Field and button in the html. To do this, first create a Flex project in Flex builder. Open your index.template.html form {project}/html-template/ folder. In this html page add following code just before the </body> tag.


<div>First Name: <input type="text" id="firstName"></div>
<div>Last Name: <input type="text" id="lastName"></div>
<div>Country: <input type="text" id="country"></div>
<div><input type="button" value="Send to Flex" onclick="sendDataToFlex()"></div>
We have created three input fields for first name, last name and country, We have also added button. Clicking on this button, it will call the Action Script function.

To make the html page proper. replace all ${width} by 600 and ${height} with 400. So that we can have flex swf size fix to 600x400.

If you have notice, in above code snippet we are calling sendDataToFlex function on Send to Flex button click. For that we have to write a function. To do this add following code before <noscript>

<script language="JavaScript" type="text/JavaScript">

function sendDataToFlex()
{
}

</script>
Now in the blank function body, we will add code for calling Flex function. To do this first we need to have reference of flash object in html page. We can retrieve the flex swf object using following function. Add following code above function sendDataToFlex()

function getFlexApp()
{
if(navigator.appName.indexOf("microsoft")!=-1)
{
return window['${application}'];
}
else
{
returndocument['${application}'];
}
}
This function will return the flex swf object reference. Now using this function we will call the function in Flex application.

Now we need to write a function which will call the flex method. Add following code after getFlexApp function.

function sendDataToFlex()
{
getFlexApp().addPerson(document.getElementById('firstName').value, document.getElementById('lastName').value, document.getElementById('country').value);
}
In the above method we have taken Flex application reference using getFlexApp and we are calling addPerson method of flex application. For this method we require three parameters, Here we will pass the values of each text field we have created.

Now we are done with creating Html file. Once you build your project, This template will create the html page in your output folder of project, by default it is bin-debug with all modification we made in the template.

Next we have to move to MXML. Open your application mxml file. In this file we will create a data grid component in which all data comes from java script will populate. Following code will create the data grid in your application.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
creationComplete="init();">

<mx:DataGrid width="500"
height="250"
dataProvider="{persons}">
<mx:columns>
<mx:DataGridColumn headerText="First Name"
dataField="firstName"/>
<mx:DataGridColumn headerText="Last Name"
dataField="lastName"/>
<mx:DataGridColumn headerText="Country"
dataField="country"/>
</mx:columns>
</mx:DataGrid>

</mx:Application>
We are ready with display component, Next we have to map JavaScript function using ExternalInterface.addCallback method. In this method we have to set two parameters, First will be the name what we will use in the JavaScript and next will be the function reference. Also we will create the function which will be called from JavaScript. In this function we will receive three parameters, add these values in persons array collection. This variable is binded with the data Grid. Updating this variable will add the values in Data greed. Add following code in the script tag of MXML file.

import mx.collections.ArrayCollection;

[Bindable]
private var persons:ArrayCollection = new ArrayCollection();

public function addPerson(firstName:String, lastName:String, country:String):void
{
persons.addItem({'firstName': firstName, 'lastName': lastName, 'country': country});
}

private function init():void
{
ExternalInterface.addCallback('addPerson', addPerson);
}
Once it is set, we are all set to go. Build your project and check.

Check out the demo here


Read more...

Saturday, April 17, 2010

Flex 3: Calling JavaScript from Flex

It is possible to communicate with the javascript functions reside in the html page from Flex. Flex library has an ExternalInterface class which allow us to communicate with Flex and javaScript and vice versa.

In this tutorial I will explain how you can communicate. You can call javaScript function which has no parameter, which has parameters and function which is returning values. I will cover function which will receive parameter in string format and returns the plain string.

To start with, First create a flex project in the Builder. First we will create a javaScript function in the html page and then we will call that from the Flex application. Open your index.template.html form {project}/html-template/ folder. In this html page add following code just before the <noscript> tag.

<script language="JavaScript" type="text/javascript">

function flexTojavaScript(fromFlex)
{
alert(value);
return 'Returning from JavaScript to Flex';
}

</script>
In the above code I have created the Script tag and within that I have created a function named 'flexTojavaScript' which will receive a parameter named 'fromFlex'. This function will return plain text.

That's it, we are done with the changes in html page.

Now we will move to the flex application mxml. In this mxml, I have created a button which will call the clickHandler on clicking on it. From the click handler I have called the javascript function using ExternalInterface class. The value returned from the javascript is stored in the returnFromJavaScript variable.

private function clickHandler():void
{
returnFromJavaScript='';
returnFromJavaScript = ExternalInterface.call("flexTojavaScript", "This is called from Flex");
}
ExternalInterface class has static method named 'call'. using this function we can call the javaScript function. In this function you will find two parameter, first parameter is the name of the javaScript function as a string. You can also send the parameters. In the above code we are sending plain string to javaScript. As mention above the function is javaScript is returning string. Which we are storing in the application local variable. In this application I have crated the text which will show up the return value of javaScript function.

That's it We are done with the changes. Just build your project and click on the button. You will find that javaScript alert will appear. Which will have the parameter text what we have sent from the Flex. On Clicking OK button of the alert prompt. You will find that the value which is returned from the javaScript will populate below the button.

This is very simple method using which we can call the javaScript function from the Flex.

I hope this will help you.

In my next tutorial I will explain the revers of this, i.e. Calling Flex function from javaScript.

Read more...

Flex 3: setting data using FlashVars

If you want to set any variables from html page to your Flex application. You can do it by setting FlashVars in the html page. This data can be read in Flex at runtime by accessing Application.application.parameter property.

Following example will demonstrate the steps to access the data in flex using FlashVars.

First create an Flex project in the flex builder. Now you have to set the required data in your html file in which the Flex application is reside. To do this you have to add the FlashVars property in your html.

Open your index.template.html form {project}/html-template/ folder. Why this file? Modifying this file will compile your actual html page with the latest changes you have made to this template file. Doing this you will have all your modification in the final compiled html file.

Next you have to set the FlashVars property. This you have to do it at two places. First within the <object> tag you will find <embed> tag.In this tag there are few properties set for the application swf file like.src, quality, bgcolor etc. you need to add one more property here i.e.FlashVars. Now identify the data which you want to pass to Flex application. And add that in above tag property(<object><embed>) as follow.

FlashVars="Name=Shailesh Makwana&Age=32&Qualification=B'Com&Experience=10 years"

Now your final code will look like this.

<noscript>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="${application}" width="${width}" height="${height}"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash`.cab">
<param name="movie" value="${swf}.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="${bgcolor}" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="${swf}.swf" quality="high" bgcolor="${bgcolor}"
width="${width}" height="${height}" name="${application}" align="middle"
play="true"
loop="false"
quality="high"
allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer"
FlashVars="Name=Shailesh Makwana&Age=32&Qualification=B'Com&Experience=10 years">
</embed>
</object>
</noscript>
Second place where you have to add the flash var is at javascript block. If you look above you will find javascript block with if an else if condition. in the else if condition block you will find some property is been set. Here you have to add flashVars.

Add following line of code as last parameter of AC_FL_RunContent function within else if block.
"FlashVars", "Name=Shailesh Makwana&Age=32&Qualification=B'Com&Experience=10 years"

You must have noticed that the snippet of FlashVars here is little different than the first step. Also make sure you add the comma after last parameter before adding this FlashVars. This is the common mistake everyone does.

Now your code will look like this.
AC_FL_RunContent(
"src", "${swf}",
"width", "${width}",
"height", "${height}",
"align", "middle",
"id", "${application}",
"quality", "high",
"bgcolor", "${bgcolor}",
"name", "${application}",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer",
"FlashVars", "Name=Shailesh Makwana&Age=32&Qualification=B'Com&Experience=10 years"
);
Now you are done with the html editing. When you will run the application from the builder. The output html file will have above changes.

Now, next we have to access these variables in the Flex. Open your main application MXML file. here you can access these flashVars using Application.application.parameters;. This parameter is of type object. Use these variable in your application wherever you need. I have accessed these variable in creationComplete event. And assigned the respective variable value to the text component as follow.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init();">
<mx:Script>
<![CDATA[

private function init():void
{
var flashVar:Object = Application.application.parameters;

nameT.htmlText = "<b>Name :</b>" +flashVar.Name;
ageT.htmlText = "<b>Age :</b>" +flashVar.Age;
qualificationT.htmlText = "<b>Qualification :</b>" +flashVar.Qualification;
experienceT.htmlText = "<b>Experience :</b>" +flashVar.Experience;
}
]]>
</mx:Script>
<mx:VBox width="300" height="100%">
<mx:Text id="nameT" width="100%" />
<mx:Text id="ageT" width="100%" />
<mx:Text id="qualificationT" width="100%" />
<mx:Text id="experienceT" width="100%" />
</mx:VBox>
</mx:Application>

After compiling this project, you will see that all variable what we have set in the html is now displayed in the Flex application. I hope this will help you.

Read more...

Friday, April 16, 2010

SingleTon design pattern in AS3

Singleton patter is very useful pattern when you need to have only one object of any class in application. You can enforce this by creating a singleton class.

We cannot directly restrict the user to create multiple object of any class in AS3, Since AS3 doesn't support private or protected constructor. AS3 constructor can always be public. So how we can restrict user for creating an object from outside. There is a work around to this. We can achieve this by creating an enforcer class in the same class file. And we will pass the reference of this enforcer class in the constructor of Singleton class. Since the enforce class can be access by same class only. No one can create the singleton class object outside that class.

Following example explain how we can achieve using AS3.


package
{
public class Singleton
{
private static var _instance:Singleton;

public function Singleton (enforcer:Enforcer)
{
if(!enforcer)
throw(new Error("The Class cannot be instantiated."));
}

public static function getInstance():ModelLocator
{
if(!_instance)
_instance = new ModelLocator(new Enforcer())

return _instance;
}
}
}

class Enforcer
{

}

Create a class which will receive a parameter as enforcer class. And create the enforcer class within the same class below the package block. This enforcer class can only be access by the Singleton class only.

As Singleton class object require Enforcer object reference as a paramer, it cannot be created from outside from the Singleton class. We are checking in Singleton constructor body that if enforcer is null, it will throw an error.

This class can be access only by calling getInstance Static method.

To access this class reference use following code snipped.

var singleton: Singleton = Singleton.getInstance();

I hope this will help you in your development.


Singleton patter is very useful pattern when you need to have only one object of any class in application. You can enforce this by creating a singleton class.

We cannot directly restrict the user to create multiple object of any class in AS3, Since AS3 doesn't support private or protected constructor. AS3 constructor can always be public. So how we can restrict user by creating an object from outside. There is a work around to this. We can achieve this by creating an enforcer class in the same class file. and we will pass the reference of this enforcer class in the constructor of Singleton class. Since the enforce class can be access by same class only. No one can create the singleton class object outside that class.

Read more...

AS Doc Creation from Flex Builder 3.

Flex builder has capability of generating ASDoc using an exe, which will generate the ASDoc for your codes. But how? I didn't find any documention in the help of flex builder. So I am writting this for all, who are looking for.

It is very simple. Following steps demonstrate how we can set the ASDoc compliar in Flex builder 3.

Step 1. Set up the external tool in builder by clicking Run > External Tools > Open External Tool Dialog. Or you can get it from tool bar. Click on the following icon in tool bar.


This will pop up External Tools dialog box.

Step 2. Click on the new launch configration button from the top left


Step 3. Give it name whatever you fill approricate.
In the location field click on browse button and search for the asdoc exe in the SDK folder. by default it reside at C:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\bin\asdoc.exe in windows.

Step 4. Point your project folder. In the working directory field type ${project_loc} – this will point to your current project.

Step 5 : Set up the arguments. Inn the arguments field add following arguments.
-source-path src
-doc-sources src
This assumes that you set up your projects with the default source folder called src. It’ll look into your project folder’s src for generating ASDoc.

Thats it, you have setup your ASDoc generation tool. Now just click on the Run button to Generate the Doc. This will create athe ASDoc in asdoc-output folder within your current folder structure.

I hope this will help you.

Read more...

Saturday, April 10, 2010

Flex 3: PureMVC tutorial


PureMVC is free framework which you can use to develop the MVC structured project. As name suggest pureMVC is a framework which is based on the Model, View and Controller. Where you can isolate your business logic with your view elements.

Today I got an opportunity to write a tutorial on Flex development using pureMVC framework. In this tutorial I will walk through the development process using pureMVC framework. The project which I will explain here will have simple data population on datagrid from the XML using HTTPService.

Before we get going, you’ll need the following

  • Flex SDK 3. Its free!
  • Flex Builder 3
  • PureMVC
  • framework library.

    Before I start this tutorial, I assume that you have knowledge about AS3 and Flex. Also you have knowledge of using Flex Builder 3.

    Now we are ready with all required tools. we can start with actual project development. First we will setup the project in Flex Build. Then we will set the packages and folders.

    1. Create flex project in Flex Builder 3 and name it SimplePureMVCExample
    2. add the pureMVC framework library in the lib folder ( add PureMVC_AS3_2_0_4.swc in lib folder of the project). (Refer below image).
    3. Within src folder of the project, create following packages for Model, View and Controller. (Refer below image.)

      com.sm.pureMVC.model.
      com.sm.pureMVC.view.
      com.sm.pureMVC.controller.


    folderStructure

    Now we have all folder ready. I will explain what each folder will have.

    Controller – will have all command classes. Which will use to communicate between Model(Proxy) and view(Mediator)

    Model – will have all business logic classes. Which will process business logic and send the notification.

    View – will have all mediator classes which will listen to all visual elements.

    Application developed using pureMVC framework needs to have an entry point which will startup the pureMVC framework. For this we need to create an ApplicationFacade class. Which will be a heart of the application.

    First we will create an application mxml file which will send a startup notification. which will start the pureMVC.

    Following is the code of main application class.









    If you noticed I have called the startup method on creationComplete event. In this method i have passed the reference of application. The startup method is been called by accessing single tone class ApplicationFacade.


    private function init():void
    {
    ApplicationFacade.getInstance().startup(this);
    }
    This Application mxml has the reference of two visual elements. i.e. Button and Custom component Employee Detail. Which is just an data grid, which will hold the details about the employee. This we will used later with Mediators.



    Now we will move to the next class. i.e. ApplicationFacade. This is a single tone class. This class will extend the Facade class of pureMVC frame work and implement IFacade. This is mandatory that Application Facade class should extend the Facade class of framework and implement the IFacade interface.

    Following is the code sample of Application Facade class.


    package com.sm.pureMVC {
    import com.sm.pureMVC.controller.LoadCommand;
    import com.sm.pureMVC.controller.StartupCommand;

    import org.puremvc.as3.interfaces.IFacade;
    import org.puremvc.as3.patterns.facade.Facade;
    import org.puremvc.as3.patterns.observer.Notification;

    /**
    * @author SM
    */
    public class ApplicationFacade extends Facade implements IFacade {

    public static const NAME : String = 'ApplicationFacade';
    public static const STARTUP : String = NAME + 'Startup';
    public static const LOAD : String = NAME + 'Load';
    public static const DATA_LOADED : String = NAME + 'dataLoaded';

    public static function getInstance() : ApplicationFacade {
    if(instance == null)instance = new ApplicationFacade();
    return instance as ApplicationFacade;
    }

    override protected function initializeController() : void {
    super.initializeController();
    registerCommand(STARTUP, StartupCommand);
    registerCommand(LOAD, LoadCommand);
    }

    public function startup(application : PureMVCExample) : void
    {
    sendNotification(STARTUP, application);
    }

    override public function sendNotification(notificationName : String, body : Object = null, type : String = null) : void {
    notifyObservers(new Notification(notificationName, body, type));
    }
    }
    }

    In this class you have noticed that, there are few const declared in the beginning. These are the names of the commands. Which will be access during sending notification.


    public static const NAME : String = 'ApplicationFacade';
    public static const STARTUP : String = NAME + 'Startup';
    public static const LOAD : String = NAME + 'Load';
    public static const DATA_LOADED : String = NAME + 'dataLoaded';
    The initialize Controller method will used to register all controllers(Commands).This is an overridden method of Facade class. and this will call the super method and then it will register all controllers. To register the command we will use the registerCommand method and we will pass two parameters. First is Name of the command and second is the command class.

    override protected function initializeController() : void {
    super.initializeController();
    registerCommand(STARTUP, StartupCommand);
    registerCommand(LOAD, LoadCommand);
    }
    The startup public method will be called from the main application mxml file. and this will send a notification of STARTUP command. and it will also send the reference to the main application. This notification will execute the Startup command.

    public function startup(application : PureMVCExample) : void
    {
    sendNotification(STARTUP, application);
    }

    Now we have send the STARTUP notification. We will need to create an StartupCommand class within com.sm.pureMVC.controller package. This class will extend the SImpleCommand of pureMVC framework and implements the ICommand. This is the entry command which will initiate the Proxy and Mediator. Whenever the startup notification is send it will trigger the execute method of Startup Command

    Following is the code sample of StartupCommand class.


    package com.sm.pureMVC.controller {

    import com.sm.pureMVC.model.EmployeeServiceProxy;
    import com.sm.pureMVC.view.ApplicationMediator;

    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.command.SimpleCommand;

    /**
    * @author SM
    */
    public class StartupCommand extends SimpleCommand {

    /**
    * Initialize the model and views
    */
    override public function execute(notification:INotification):void
    {
    facade.registerProxy(new EmployeeServiceProxy());
    facade.registerMediator(new ApplicationMediator(notification.getBody() as PureMVCExample));
    }
    }
    }

    The execute overridden method will have the code for initializing the EmployeeServiceProxy proxy and ApplicationMediator mediator. The application reference passed along with startUp Notification can be accessed by notification parameter of execute method. i.e by notification.getBody(); and this will be passed to the Mediator as a parameter.


    override public function execute(notification:INotification):void
    {
    facade.registerProxy(new EmployeeServiceProxy());
    facade.registerMediator(new ApplicationMediator(notification.getBody() as PureMVCExample));
    }
    Now we are ready with startup command class. Lets move to create EmployeeServiceProxy class. We will create this proxy class in com.sm.pureMVC.model package.This class will hold the logic of loading XML using http Service. In this class we will create the service which will load the employee.xml on call of onLoad method from outside. On http Service result we will send the notification of DATA_LOADED along with an array collection. This will be listen by EmployeeDetailMediator class employee datagrid component.

    Following is the code sample of EmployeeServiceProxy class.


    package com.sm.pureMVC.model
    {


    import com.sm.pureMVC.ApplicationFacade;

    import mx.collections.ArrayCollection;
    import mx.controls.Alert;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.http.mxml.HTTPService;

    import org.puremvc.as3.interfaces.IProxy;
    import org.puremvc.as3.patterns.proxy.Proxy;

    public class EmployeeServiceProxy extends Proxy implements IProxy
    {
    public static const NAME:String = 'EmployeeProxy';

    private var serv:HTTPService;

    public function EmployeeServiceProxy(data:Object = null)
    {
    super(NAME, data);
    setService()
    }

    private function setService():void
    {
    serv = new HTTPService();
    serv.url="assets/data/employee.xml"
    serv.resultFormat="object"
    serv.addEventListener(ResultEvent.RESULT,servResultHandler);
    serv.addEventListener(FaultEvent.FAULT,servFaultHandler);
    }

    private function servResultHandler(event:ResultEvent):void
    {
    sendNotification(ApplicationFacade.DATA_LOADED, event.result.Employee_Info.Employee as ArrayCollection);
    }

    private function servFaultHandler(event:FaultEvent):void
    {
    Alert.show(event.toString());
    }

    public function loadData():void
    {
    serv.send();
    }

    override public function getProxyName():String
    {
    return EmployeeServiceProxy.NAME;
    }
    }
    }

    Declare the proxy name const in the beginning. This cont can be used, when we have to access the proxy class using retriveProxy method of Facade class.

    public static const NAME:String = 'EmployeeProxy';
    The setService method will be called from the constructor and it will initialize the http service and set the required properties and listeners.

    private function setService():void
    {
    serv = new HTTPService();
    serv.url="assets/data/employee.xml"
    serv.resultFormat="object"
    serv.addEventListener(ResultEvent.RESULT,servResultHandler);
    serv.addEventListener(FaultEvent.FAULT,servFaultHandler);
    }
    The loadData method will be called from the outside. This method will send the http service request. The result/fault of the request will be handle in the respective handler methods.


    public function loadData():void
    {
    serv.send();
    }
    The servResultHandler will triggered on result of service. This function will send the notification for data loaded along with the data object. This notification will be listen by the interested mediators(in this project EmployeeDetailMediator).


    private function servResultHandler(event:ResultEvent):void
    {
    sendNotification(ApplicationFacade.DATA_LOADED, event.result.Employee_Info.Employee as ArrayCollection);
    }
    Now we have set the proxy class. we will move to create the application mediator class in the com.sm.pureMVC.view package.

    This class will extend the Proxy Class and implement the IProxy interface. This class will register the EmployeeDetailMediator and set the listener of button to load the xml.

    Following is the code sample of EmployeeServiceProxy class.

    package com.sm.pureMVC.view
    {
    import com.sm.pureMVC.ApplicationFacade;

    import flash.events.MouseEvent;

    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;

    public class ApplicationMediator extends Mediator implements IMediator
    {
    public static const NAME:String = 'ApplicationMediator';

    public function ApplicationMediator(viewComponent:Object=null)
    {
    super(ApplicationMediator.NAME, viewComponent);
    facade.registerMediator(new EmployeeDetailMediator(application.employeeList));
    application.getEmployee.addEventListener(MouseEvent.CLICK, getEmployeeClickHandler);
    }

    override public function getMediatorName():String
    {
    return ApplicationMediator.NAME;;
    }

    private function get application():PureMVCExample
    {
    return viewComponent as PureMVCExample;
    }

    private function getEmployeeClickHandler(event:MouseEvent):void
    {
    sendNotification(ApplicationFacade.LOAD);
    }

    }
    }

    Declare the Mediator name const in the beginning. This cont can be used, when we have to access the mediator class using retriveMediator method of Facade class.


    public static const NAME:String = 'ApplicationMediator';
    The application reference passed with ApplicationMediator will be stored in the viewComponent property of the class. In the constructor we will register another mediator i.e. EmployeeDetailMediator and we will pass the reference of the employee detail component to this mediator as a parameter. This will map the employee detail component with EmployeeDetailMediator.

    Also we will add the listener to the getEmployee button which is present in the application mxml.

    public function ApplicationMediator(viewComponent:Object=null)
    {
    super(ApplicationMediator.NAME, viewComponent);
    facade.registerMediator(new EmployeeDetailMediator(application.employeeList));
    application.getEmployee.addEventListener(MouseEvent.CLICK, getEmployeeClickHandler);
    }
    On getEmployee button click handler we will send the notification of Load command. This will be listen by the LoadCommand.

    private function getEmployeeClickHandler(event:MouseEvent):void
    {
    sendNotification(ApplicationFacade.LOAD);
    }
    Now we will create the LoadCommand class in com.sm.pureMVC.controller package. Like Startup command this command class will also extend the SimpleCommand and implements the ICommand. This class will execute when Load notification is sent. In this application the load notification is been sent from the getEmployee click handler.

    Following is the code sample of EmployeeServiceProxy class.

    package com.sm.pureMVC.controller
    {
    import com.sm.pureMVC.model.EmployeeServiceProxy;

    import org.puremvc.as3.interfaces.ICommand;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.command.SimpleCommand;

    public class LoadCommand extends SimpleCommand implements ICommand
    {
    public function LoadCommand()
    {
    super();
    }

    override public function execute(notification:INotification):void
    {
    var employeeProxy:EmployeeServiceProxy = facade.retrieveProxy(EmployeeServiceProxy.NAME) as EmployeeServiceProxy;
    employeeProxy.loadData();
    }

    }
    }
    The execute overridden method will have the code for calling loadData method of EmployeeServiceProxy class. If you have noticed here we hate retrieve the reference of EmployeeServiceProxy class using retrieveProxy method of facade class. To retrieve the reference we have passed the EmployeeServiceProxy name const. This will intimate facade that the request is for EmployeeServiceProxy class.

    override public function execute(notification:INotification):void
    {
    var employeeProxy:EmployeeServiceProxy = facade.retrieveProxy(EmployeeServiceProxy.NAME) as EmployeeServiceProxy;
    employeeProxy.loadData();
    }
    Now we are ready with Load command class, next we will create the EmployeeDetailMediator class. This class will extend the Mediator and implement the IMediator interface. Remember we have register this mediator in the ApplicationMediator class constructor and we have passed the reference of employee detail component to this.

    In this class we have to listen to DATA_LOADED notification, which was sent from the EmployeeServiceProxy class result handler method. and set the employee data to the data grid which was passed along with DATA_LOADED notification.

    Following is the code sample of EmployeeServiceProxy class.

    package com.sm.pureMVC.view
    {
    import com.sm.pureMVC.ApplicationFacade;
    import com.sm.pureMVC.view.components.EmployeeDetail;

    import mx.collections.ArrayCollection;

    import org.puremvc.as3.interfaces.IMediator;
    import org.puremvc.as3.interfaces.INotification;
    import org.puremvc.as3.patterns.mediator.Mediator;

    public class EmployeeDetailMediator extends Mediator implements IMediator
    {
    public static const NAME:String = 'EmployeeDetailMediator';

    public function EmployeeDetailMediator(viewComponent:Object=null)
    {
    super(EmployeeDetailMediator.NAME, viewComponent);
    }

    override public function getMediatorName():String
    {
    return EmployeeDetailMediator.NAME;
    }

    private function get employeeDetail():EmployeeDetail
    {
    return viewComponent as EmployeeDetail;
    }

    override public function listNotificationInterests():Array
    {
    return [ ApplicationFacade.DATA_LOADED];
    }

    override public function handleNotification(notification:INotification):void
    {
    switch (notification.getName()) {
    case ApplicationFacade.DATA_LOADED:
    employeeDetail.employee.dataProvider = notification.getBody() as ArrayCollection;
    break;
    }
    }

    }
    }

    To listen to the notification in mediator we have to follow few steps. First we have to add the notification which are interested by this mediator using listNotificationInterests method. In this overridden method we will return the array of notification names which will be interested by this mediator class.


    override public function listNotificationInterests():Array
    {
    return [ ApplicationFacade.DATA_LOADED];
    }
    Now, after adding the interested notification. we will create the function which will execute respective functionality for interested notification. The handleNotification overridden method will have the code for executing specific functionality for each notification. If the mediator is interested in multiple notification. that can be listen using switch case loop.

    In this function, within DATA_LOADED case we will set the employee data grid data provider. Remember we have sent the data object reference along with the DATA_LOADED notification. We will access this data object by getBody method of notification.

    override public function handleNotification(notification:INotification):void
    {
    switch (notification.getName()) {
    case ApplicationFacade.DATA_LOADED:
    employeeDetail.employee.dataProvider = notification.getBody() as ArrayCollection;
    break;
    }
    }

    That’s it. we have complete the simple flex application using pureMVC framework. I hope this tutorial will help you to understand the flow of developing the flex application using pureMVC. If you have any question, Kindly let me know I will try to answer you question.

    Summary of development.

    1. Call startup method of ApplicationFacade class from the application mxml file.

    2. Send the startup notification from the ApplicationFacade class.

    3. Initialize the ApplicationMediator and EmployeeServiceProxy in the Startup command.

    4. Add the get employee button listener in the ApplicationMediator class.

    5. Send notification of LOAD command from the ApplicationMediator class

    6. Initialize the EmployeeDetailMediator mediator in the ApplicationMediator class.

    7. Add logic of xml loading using httpService in the EmployeeServiceProxy class.

    8. Send notification of DATA_LOADED from the EmployeeServiceProxy class.

    9. Handle DATA_LOADED notification in EmployeeDetailMediator class.


    Download the complete source zip file

    Read more...

    Friday, April 9, 2010

    Flex 3: Pie Chart interactive Label

    I have started exploring Flex 3 pie chart component few days back and i realize that the labels for pie chart is not interactive. There is no inbuilt events for pie chart label.


    To make the label interactive of pie chart component i have extend the pie chart component. But It was really strange that there was no direct reference available to individual labels. Instead there is a reference to the labelContainer who hold all the labels. To achieve the label reference i have added the listener to the label container and check the current target is label field or not. and Then i have dispatched the custom label event.





    Following snippet is for the custom pie chart component which i have extend from Pie chart.


    File Name ClickableLabelPieChart.mxml






    [Event(name="labelClick", type="events.ChartLabelEvent")]
    [Event(name="labelDoubleClick", type="events.ChartLabelEvent")]
    [Event(name="labelMouseDown", type="events.ChartLabelEvent")]
    [Event(name="labelMouseUp", type="events.ChartLabelEvent")]
    [Event(name="labelRollOver", type="events.ChartLabelEvent")]
    [Event(name="labelRollOut", type="events.ChartLabelEvent")]
    [Event(name="labelMouseMove", type="events.ChartLabelEvent")]



    import mx.core.UITextField;
    import mx.charts.series.PieSeries;
    import events.ChartLabelEvent;

    [Bindable]
    private var pieSeries:PieSeries;

    private function addLabelEvents():void
    {
    pieSeries = this.series[0];
    if (pieSeries)
    {
    pieSeries.labelContainer.addEventListener(MouseEvent.CLICK, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.DOUBLE_CLICK, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.MOUSE_DOWN, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.MOUSE_MOVE, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.MOUSE_OUT, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.MOUSE_OVER, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.MOUSE_UP, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.ROLL_OUT, dispatchLabelEventHandler);
    pieSeries.labelContainer.addEventListener(MouseEvent.ROLL_OVER, dispatchLabelEventHandler);
    }
    }



    private function dispatchLabelEventHandler(event:MouseEvent):void
    {

    if(event.target is UITextField == false)
    return;

    var currentLabel:UITextField = event.target as UITextField
    var chartEventType:String = '';
    switch(event.type)
    {
    case MouseEvent.CLICK:
    chartEventType = ChartLabelEvent.LABEL_CLICK;
    break;
    case MouseEvent.DOUBLE_CLICK:
    chartEventType = ChartLabelEvent.LABEL_DOUBLE_CLICK;
    break;
    case MouseEvent.MOUSE_DOWN:
    chartEventType = ChartLabelEvent.LABEL_MOUSE_DOWN;
    break;
    case MouseEvent.MOUSE_MOVE:
    chartEventType = ChartLabelEvent.LABEL_MOUSE_MOVE;
    break;
    case MouseEvent.MOUSE_OUT:
    chartEventType = ChartLabelEvent.LABEL_MOUSE_OUT;
    break;
    case MouseEvent.MOUSE_OVER:
    chartEventType = ChartLabelEvent.LABEL_MOUSE_OVER;
    break;
    case MouseEvent.MOUSE_UP:
    chartEventType = ChartLabelEvent.LABEL_MOUSE_UP;
    break;
    case MouseEvent.ROLL_OUT:
    chartEventType = ChartLabelEvent.LABEL_ROLL_OUT;
    break;
    case MouseEvent.ROLL_OVER:
    chartEventType = ChartLabelEvent.LABEL_ROLL_OVER;
    break;
    }


    this.dispatchEvent(new ChartLabelEvent(chartEventType, currentLabel));
    }
    ]]>






    I have used the custom event for label. For that i have created an Custom Event class based on MouseEvent

    File Name ChartLabelEvent.as


    package events
    {
    import flash.display.InteractiveObject;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    import mx.core.UITextField;

    public class ChartLabelEvent extends MouseEvent
    {
    public static const LABEL_CLICK:String = "labelClick";

    public static const LABEL_DOUBLE_CLICK:String = "labelDoubleClick";

    public static const LABEL_MOUSE_DOWN:String = "labelMouseDown";

    public static const LABEL_MOUSE_MOVE:String = "labelMouseMove";

    public static const LABEL_MOUSE_OUT:String = "labelMouseOut";

    public static const LABEL_MOUSE_OVER:String = "labelMouseOver";

    public static const LABEL_ROLL_OUT:String = "labelRollOut";

    public static const LABEL_ROLL_OVER:String = "labelRollOver";

    public static const LABEL_MOUSE_UP:String = "labelMouseUp";

    private var _labelField:UITextField;

    public function ChartLabelEvent(type:String, labelField:UITextField = null, triggerEvent:MouseEvent=null)
    {
    var relPt:Point;
    if (triggerEvent && triggerEvent.target)
    {
    relPt = target.globalToLocal(triggerEvent.target.localToGlobal(
    new Point(triggerEvent.localX, triggerEvent.localY)));
    }
    else
    {
    if(target)
    relPt = new Point(target.mouseX,target.mouseY);
    else
    relPt = new Point(0,0);
    }

    var bubbles:Boolean = true;
    var cancelable:Boolean = false;
    var relatedObject:InteractiveObject = null;
    var ctrlKey:Boolean = false;
    var shiftKey:Boolean = false;
    var altKey:Boolean = false;
    var buttonDown:Boolean = false;
    var delta:int = 0;

    if(triggerEvent)
    {
    bubbles = triggerEvent.bubbles;
    cancelable = triggerEvent.cancelable;
    relatedObject = triggerEvent.relatedObject;
    ctrlKey = triggerEvent.ctrlKey;
    altKey = triggerEvent.altKey;
    shiftKey = triggerEvent.shiftKey;
    buttonDown = triggerEvent.buttonDown;
    delta = triggerEvent.delta;
    }
    super(type, bubbles, cancelable, relPt.x, relPt.y, relatedObject, ctrlKey, altKey, shiftKey, buttonDown, delta);

    this.labelField = labelField;
    }

    public override function clone():Event
    {
    return new ChartLabelEvent(type, labelField, this);
    }


    public function get labelField():UITextField
    {
    return _labelField;
    }

    public function set labelField(value:UITextField):void
    {
    _labelField = value;
    }
    }
    }


    Finally the application mxml. In this file i have added the custom Pie chart component and added all label mouse events on creation complete. On the mouse handler function, I have changed the Label color on roll over and roll out with background. On click the color of lable changes to green.

    PieChartLabelEvent.mxml




    import mx.graphics.SolidColor;
    import mx.collections.ArrayCollection;
    import events.ChartLabelEvent;
    private function init():void
    {
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_CLICK, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_DOUBLE_CLICK, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_DOWN, chartLabelMouseHandler);
    //labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_MOVE, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_OUT, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_OVER, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_OVER, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_MOUSE_UP, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_ROLL_OUT, chartLabelMouseHandler);
    labelPieChart.addEventListener(ChartLabelEvent.LABEL_ROLL_OVER, chartLabelMouseHandler);
    }
    private function chartLabelMouseHandler(event:ChartLabelEvent):void
    {
    trace(event.labelField);
    if(event.type == ChartLabelEvent.LABEL_MOUSE_OVER)
    {
    event.labelField.background = true;
    event.labelField.backgroundColor = 0xFF0000;
    event.labelField.textColor = 0xffff00;
    }else if(event.type == ChartLabelEvent.LABEL_MOUSE_OUT)
    {
    event.labelField.background = false;
    event.labelField.textColor = 0x000000;
    }else if(event.type == ChartLabelEvent.LABEL_CLICK)
    {
    var color:uint = event.labelField.textColor != 0x00ff00 ? 0x00ff00 : 0x000000;
    event.labelField.textColor = color;
    }
    }

    [Bindable]
    private var fragments:ArrayCollection = new ArrayCollection([
    { Country: "USA", Gold: 35},
    { Country: "China", Gold: 32},
    { Country: "India", Gold: 5},
    { Country: "Brazil", Gold: 15},
    { Country: "Russia", Gold: 27}
    ]);

    [Bindable]
    private var _fillList:Array = [
    new SolidColor(0xFF5B5B,0.9),
    new SolidColor(0xA9FE5C,0.9),
    new SolidColor(0xFEBD5C,0.9),
    new SolidColor(0xFF8040,0.9),
    new SolidColor(0x5BFFCA,0.9),
    ];

    private function displayGold(data:Object, field:String, index:Number, percentValue:Number):String {
    var temp:String= (" " + percentValue).substr(0,6);
    return data.Country + ": " + "Total Gold: " + Math.round(data.Gold);
    }
    ]]>

    weight = "2"
    color = "0x999999"
    alpha = ".8"
    caps = "square"/>

    weight = "1"
    color = "0xFFFFCC"
    alpha = ".5"/>


    color = "0x000000"
    weight = "2"
    alpha = ".5"/>
    dataProvider = "{fragments}"
    showDataTips = "true"
    selectionMode = "single"
    height = "100%"
    width = "100%">

    nameField = "Country"
    labelPosition = "callout"
    selectable = "true"
    labelFunction = "displayGold"
    calloutStroke = "{callouts}"
    radialStroke = "{radial}"
    stroke = "{pieborder}"
    fills = "{_fillList}"/>








    You can use these mouse event to make the label draggable. I will explain this in my next post where i will create an application which will have a functionality of changing the label by dragging from the list.

    Read more...

    Draggable Wedges in Pie chart

    Its been too long since I had wrote a blog.
    Today I got a chance and I am writing this for Flex pie chart draggable wedge.

    Flex has very good library of components. This is one of that and I have extended the pie chart component to make the wedges interactive and draggable. Flex pie chart component doesn't have this feature. So I tried to make one.

    For developing this I have created draggable points at the end of each wedge. And on dragging, it will change the value of that wedge and its related wedge.

    Comments are welcome


    Read more...