Wednesday, November 28, 2012

Empty String != null

For some of us out there, we might be assigning an empty string to various types of variables thinking that nothing might go wrong. However, that isn't the case. For different types of objects / components and for different types of variables or properties, by assigning an empty string might give you some unnecessary troubles. For example...

Time for some source codes: ImageSourceIssue.mxml


 
 
  
 
 
 
  
 
 
  
   
  
  
  
  
   
   
   
   
   
   
   
   
   
   
  
  
   
   
  
  
  
 


If you are using firebug or Charles or any other types of Web Developer Tools, you can easily identify the differences in the results for the 3 buttons. :)

* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Thursday, November 22, 2012

Which 1 is better 4 / 7 / 10 ?

Approximately a week ago, Google has released it's fourth Nexus-branded Android smartphone. As I was looking at the specifications of Nexus 4, I was drooling. Too bad I don't have a lot of spare money to go around purchasing it. (I probably will end up holding on to my Nexus 3 till the release of Nexus 5. :P)


Logo taken from the 'Google Nexus' website.

* Click here for the website of 'Google Nexus'.

Saturday, November 17, 2012

Creating a Favi Icon for your web site

If you are a web developer or for some reason you need to grab a favion from a website, you might encounter some cross browser issues. (Trust me, this can be quite annoying sometimes. Some Favi Icon might appear in some browsers, but on some other browsers it does not. You will be pretty amazed with the number of web sites that have this issue. =="")


Image taken from the website of 'favion.ico generator'.
Therefore, I will grab the favicon that I'm getting from website
and do a import and re-export the favicon to generate a new
favicon that can work for most of the browser.

Alternatively, you can create a new favicon for your website
through this website too.

* Click here for the website of 'favion.ico generator'.

Friday, November 9, 2012

Flex: Playing with multiple column chart

Well, I was trying to figure out how to render multiple column chart some time back. After spending a few days playing around it, I finally found a way to work around it. :)

Tim for some source files - 'SimpleMultipleColumn.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"
      backgroundColor="#CDCDCD"
      creationComplete="creationCompleteEvent(event)"> 
 <fx:Declarations>
  <!-- 
  We need to specify the types of animations over here
  -->
  <s:Parallel id="parallelEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
   <mx:SeriesSlide duration="1000" direction="up"/>
  </s:Parallel>
  <s:Parallel id="parallelCarEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
  </s:Parallel>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import flashx.textLayout.conversion.TextConverter;
   
   import mx.charts.HitData;
   import mx.charts.chartClasses.IChartElement2;
   import mx.charts.chartClasses.Series;
   import mx.charts.series.ColumnSeries;
   import mx.charts.series.LineSeries;
   import mx.collections.ArrayCollection;
   import mx.collections.Sort;
   import mx.collections.SortField;
   import mx.events.FlexEvent;
   import mx.formatters.DateFormatter;
   import mx.graphics.Stroke;
   
   import spark.events.IndexChangeEvent;
   
   //Records used in the chart
   [Bindable]
   private var myData:XML = 
    <records> 
     <record>
      <date>01/09/2013</date>
      <people>63</people>
      <car>23</car>
     </record>
     <record>
      <date>02/09/2013</date>
      <people>61</people>
      <car>81</car>
     </record>
     <record>
      <date>03/09/2013</date>
      <people>67</people>
      <car>47</car>
     </record>
     <record>
      <date>04/09/2013</date>
      <people>75</people>
      <car>95</car>
     </record>
     <record>
      <date>05/09/2013</date>
      <people>65</people>
      <car>45</car>
     </record>
     <record>
      <date>06/09/2013</date>
      <people>32</people>
      <car>52</car>
     </record>
     <record>
      <date>07/09/2013</date>
      <people>66</people>
      <car>46</car>
     </record>
     <record>
      <date>08/09/2013</date>
      <people>85</people>
      <car>105</car>
     </record>
     <record>
      <date>09/09/2013</date>
      <people>37</people>
      <car>57</car>
     </record>
     <record>
      <date>10/09/2013</date>
      <people>80</people>
      <car>100</car>
     </record>
    </records>;
   
   private var localSeries:ColumnSeries = new ColumnSeries();
   private var localCarSeries:ColumnSeries = new ColumnSeries();
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    //Create the SortField object for the "time" field in 
    //the ArrayCollection object, and make sure we do a 
    //numeric sort.
    var dataSortField:SortField = new SortField();
    dataSortField.name = "time";
    dataSortField.numeric = true;
    
    //Create the Sort object and add the SortField object 
    //created earlier to the array of fields to sort on.
    var numericDataSort:Sort = new Sort();
    numericDataSort.fields = [dataSortField];
    
    // Parsing the xml data into ArrayCollection
    var objArray:ArrayCollection = new ArrayCollection();
    var tempObj:Object;
    var dateArray:Array;
    var tempDate:Date;
    for(var i:int = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     tempObj.people = myData.record[i].people;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    }
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localSeries.dataProvider = objArray;
    localSeries.yField = "people";
    localSeries.xField = "date";
    //Create alternate colors for the columns
    localSeries.setStyle("fill", 0xCDFFCD);
    //Create the strokes for the columns
    localSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localSeries.displayName = "col_people";
    //Set the width(%) of the column 
    localSeries.columnWidthRatio = 0.3;
    //Set the offset
    localSeries.offset = -0.15;
    
    objArray = new ArrayCollection();
    for(i = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     tempObj.car = myData.record[i].car;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    } 
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localCarSeries.dataProvider = objArray;
    localCarSeries.yField = "car";
    localCarSeries.xField = "date";
    //Create alternate colors for the columns
    localCarSeries.setStyle("fill", 0xCDCDFF);
    //Create the strokes for the columns
    localCarSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localCarSeries.displayName = "line_car";
    //Set the width(%) of the column 
    localCarSeries.columnWidthRatio = 0.3;
    //Set the offset
    localCarSeries.offset = 0.15;
    
    //We will remove all the series attach to the chart
    //first
    chart.series = null;
    
    //End all the effects first, else some glich will
    //appear.
    parallelEffect.end();
    parallelCarEffect.end();
    
    //Base on the type of animation selected, attach 
    //the effect to the column
    localSeries.setStyle("creationCompleteEffect", 
     parallelEffect);
    localCarSeries.setStyle("creationCompleteEffect", 
     parallelCarEffect);
    
    // Back up the current series on the chart.
    var currentSeries:Array = chart.series;
    // Add the new series to the current Array of series.
    currentSeries.push(localCarSeries);
    currentSeries.push(localSeries);
    // Add the new Array of series to the chart.
    chart.series = currentSeries;
   }
   
   //This function will return a string based on the
   //Date format DD/MM/YYYY.
   private function dateFormatter(tempDate:Date):String
   {
    var fmt:DateFormatter = new DateFormatter();
    fmt.formatString = "DD/MM/YYYY";
    return fmt.format(tempDate);
   }
   
   //We are customizing the datatip / tool tip of the
   //chart data.
   public function myDataTipFunction(e:HitData):String {
    var s:String = "";
    var tempDate:Date = e.item.date as Date;
    s += "Date: " + dateFormatter(tempDate) + "<br>";
    if(Series(e.element).displayName == "col_people")
    {
     s += "No. of People: " + e.item.people;
    }else{
     s += "No. of Cars: " + e.item.car;
    }
    return s;
   }
   
   //This function will be used to change the date labels of
   //the chart to match the data.
   public function createDate(s:Date):Date {    
    var newDate:Date = new Date();
    newDate.time = s.time;
    //We need to increase a day to the labels.
    newDate.date += 1;
    return newDate;
   }  
   
   //This function will toggle the visibility of the chart
   //Data based on the values of the respective check boxes.
   protected function chkChartChangeEvent(event:Event):void
   {
    var showCarData:Boolean = chkCar.selected;
    var showPeopleData:Boolean = chkPeople.selected;
    for(var i:int = 0; i < chart.series.length; i ++)
    {
     if(chart.series[i].displayName == "line_car")
     {
      chart.series[i].visible = showCarData;
     }
     if(chart.series[i].displayName == "col_people")
     {
      chart.series[i].visible = showPeopleData;
     }
    }
   }
   
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:BorderContainer width="100%"
         backgroundAlpha="0"
         borderVisible="false">
   <s:HGroup verticalAlign="middle" horizontalAlign="center"
       width="100%"
       height="100%">
    <!-- Need to set the gutterLeft and 
    gutterTop of the chart -->
    <mx:CartesianChart id="chart"
           gutterTop="0"
           gutterLeft="50"
           showDataTips="true" 
           width="80%"
           height="80%"
           dataTipFunction="myDataTipFunction">
     <mx:horizontalAxis>
      <mx:DateTimeAxis dataUnits="days" id="dateAxis" 
           alignLabelsToUnits="false" 
           parseFunction="createDate"/> 
     </mx:horizontalAxis>
    </mx:CartesianChart>
   </s:HGroup>
  </s:BorderContainer>
  <s:HGroup width="100%" horizontalAlign="center" 
      verticalAlign="middle">
   <s:CheckBox id="chkCar"
      change="chkChartChangeEvent(event)" 
      selected="true"
      label="Show Car Data"/>
   <s:CheckBox id="chkPeople"
      change="chkChartChangeEvent(event)" 
      selected="true"
      label="Show People Data"/>
  </s:HGroup>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Saturday, November 3, 2012

Android: Simple XML Parsing

Probably due to the fact that I have been playing or working with XML (e4x) for a very long period of time, therefore it makes things pretty hard when I'm jumping backwards to the old way of parsing xml. After spending a bit of time looking through numerous tutorials and my previous codes, here's a simple xml parsing project that I have created.

'Screen grab of my XML Parsing Project'
Basically, upon running the app, it will copy an XML into your android
device. Upon a successful copying of the file, I will read the contents
of the XML file and display them in a TextView.
(Because I'm combining some of my previous tutorial with this, therefore
it's difficult for me to show all the source files in this post. I would
highly suggest that you download the source files and look through the
source codes and the comments that I have added.)

* Click here for the source files of the project.
^ Click here for the 'Android XML Parsing Tutorial' that I have referenced.

Thursday, October 25, 2012

Flex 4: Simple walkthrough in adding GA to your flex site

As an individual started creating a new website, he/she will be interested in finding out how did the website perform. He/she will be interested in tracking down the actions of the user and which is the most popular page throughout the whole website. Therefore I'm creating a simple demo on integrating the Google Analytics services into your flex website.

Time for some coding.
The main application file source code - SimpleGATracking.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      creationComplete="creationCompleteEvent(event)"
      addedToStage="addedToStageEvent(event)"
      xmlns:local="*">
 <fx:Script>
  <![CDATA[
   import com.util.GATracker.GATrackerObj;
   
   import mx.events.FlexEvent;
   
   private var _isCreationComplete:Boolean = false;
   private var _isAddedToStage:Boolean = false;
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    _isCreationComplete = true;
    createContent();    
   }
   
   protected function addedToStageEvent(event:Event):void
   {
    _isAddedToStage = true;
    createContent();
   }
   
   private function createContent():void
   {
    if(_isCreationComplete && _isAddedToStage)
    {
     //let's setup the GATrackerObj
     GATrackerObj.getInstance().setup(this,"UA-35825942-1",true);
    }
   }
   
   /* 
    Upon clicking on one of the buttons,
    we will track the button click.
   */
   protected function clickEvent(event:MouseEvent):void
   {
    if(event.currentTarget == btn1)
    {
     GATrackerObj.getInstance().
      track("main/button_1_click");
    }else if(event.currentTarget == btn2){
     GATrackerObj.getInstance().
      track("main/button_2_click");
    }
   }
   
  ]]>
 </fx:Script>
 <s:VGroup width="100%"
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:VGroup width="50%"
      height="50%">
   <s:HGroup horizontalAlign="center"
       verticalAlign="middle"
       width="100%"
       height="50%">
    <s:Button id="btn1"
        label="Button 1"
        click="clickEvent(event)"/>
    <s:Button id="btn2"
        label="Button 2"
        click="clickEvent(event)"/>
   </s:HGroup>
   <local:SimpleCanvasView width="100%"
      height="50%"
       backgroundColor="#DEDEDE"/>
  </s:VGroup>
 </s:VGroup>
</s:Application>

The view file source code - SimpleCanvasView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx">
 <s:layout>
  <s:HorizontalLayout horizontalAlign="center"
        verticalAlign="middle"/>
 </s:layout>
 <fx:Script>
  <![CDATA[
   import com.util.GATracker.GATrackerObj;
   /* 
    Upon clicking on one of the buttons,
    we will track the button click.
   */
   protected function clickEvent(event:MouseEvent):void
   {
    if(event.currentTarget == btn1)
    {
     GATrackerObj.getInstance().
      track("inner_view/button_1_click");
    }else if(event.currentTarget == btn2){
     GATrackerObj.getInstance().
      track("inner_view/button_2_click");
    }
   }
  ]]>
 </fx:Script>
 
 <s:Button id="btn1"
     label="Button 1"
     click="clickEvent(event)"/>
 <s:Button id="btn2"
     label="Button 2"
     click="clickEvent(event)"/> 
</s:BorderContainer>

The file that I have created to communicate with Google Analytics - GATrackerObj.as
package com.util.GATracker
{
 import com.google.analytics.AnalyticsTracker;
 import com.google.analytics.GATracker;
 
 import mx.core.UIComponent;
 
 public class GATrackerObj extends UIComponent
 {
  private static var _instance:GATrackerObj=null;
  public var tracker:AnalyticsTracker;
  
  //You need the following functions to create a 
  //singleton Object. SingletonObject(e:SingletonEnforcer)
  //and getInstance():SingletonObject
  //Rather than using new SingletonObject to create a new
  //object of the class, you need to use
  //SingletonObject.getInstance() to point to the Singleton
  //class.
  public function GATrackerObj(e:SingletonEnforcer)
  {
   trace("new singleton object created");
  }
  
  public static function getInstance():GATrackerObj{
   if(_instance==null){
    _instance=new GATrackerObj(new SingletonEnforcer);
   }
   return _instance;
  }
  
  /**
   * In order to track(value) your pages, 
   * you need to run setup first
   * 
   * @param view - the view that you are executing the setup()
   * @param id - the GA Account ID
   * @param debug - do you want to show the visual debug console 
   */
  public function setup(view:*,
         id:String, 
         debug:Boolean = false):void
  {
   view.addElement(GATrackerObj.getInstance());
   tracker = new GATracker(this, id, "AS3", debug);
  }
  
  /**
   * In order to track(value) your pages, 
   * you need to run setup first
   * 
   * @param value - the page you want to track 
   */
  public function track(value:String):void
  {
   tracker.trackPageview("/web/" + value);
  }
 }
}

//This class is needed in creating a singleton class.
class SingletonEnforcer{
 
}

* Click here for the demo shown in this post.
^ Click here for the source files for the demo.
~ Click here for the in-depth contents of Google Analytics.
** Click here for the Google Analytics Component for Flash/Flex.

Sunday, October 21, 2012

AS3: Creating a Clone

In the AS3 world, there might be numerous situations that requires you to create a clone of a very complex component of object. However it will be kinda crazy if you are going to run a loop and copy all the variables one by one. Therefore here's a class that will help you to reduce the amount of work needed.

Here's our main Application Class - SimpleCopyingOfObjects.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"
      backgroundColor="#CDCDCD"
      creationComplete="creationCompleteEvent(event)">
 <fx:Script>
  <![CDATA[
   import flash.net.*;
   import flash.utils.*;
   
   import mx.collections.ArrayCollection;
   import mx.events.FlexEvent;
   import mx.utils.ObjectUtil;
   
   import view.CustomComponent;
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    //Creating 2 new CustomComponent and assign some
    //values to it.
    var tempObj:CustomComponent = new CustomComponent();
    var tempObj1:CustomComponent = new CustomComponent();
    tempObj.message = "I'm am a new View.";
    tempObj1.message = "I'm am a new View1.";
    tempObj.myContent.addItem(tempObj1);
    
    //Now let's create some clones.
    var tempClone1 = cloneObject(tempObj);
    var tempClone2 = cloneCustomObject(tempObj);
    
    txtMsg.appendText("tempObj is: " + 
     getQualifiedClassName(tempObj));
    txtMsg.appendText("\ntempClone1 is: " + 
     getQualifiedClassName(tempClone1));
    txtMsg.appendText("\ntempClone2 is: " + 
     getQualifiedClassName(tempClone2));
    
    txtMsg.appendText("\n\nValue of tempObj.message is: " + 
     tempObj.message);
    if(tempClone1.hasOwnProperty("message"))
    {
     txtMsg.appendText("\nValue of tempClone1.message is: "+ 
      tempClone1.message);
    }else{
     txtMsg.appendText("\nValue of tempClone1.message is " + 
      "unaccessible.");
    }
    if(tempClone2.hasOwnProperty("message"))
    {
     txtMsg.appendText("\nValue of tempClone2.message is: "+ 
      tempClone2.message);
    }else{
     txtMsg.appendText("\nValue of tempClone2.message is " + 
      "unaccessible.");
    }
    
    tempObj.message = "I'm am a old View.";
    txtMsg.appendText("\n\nChange Value of tempObj.message "+ 
     "to 'I'm am a old View.'");
    txtMsg.appendText("\nValue of tempObj.message is: "+ 
     tempObj.message);
    if(tempClone1.hasOwnProperty("message"))
    {
     txtMsg.appendText("\nValue of tempClone1.message is: "+ 
      tempClone1.message);
    }else{
     txtMsg.appendText("\nValue of tempClone1.message is " + 
      "unaccessible.");
    }
    if(tempClone2.hasOwnProperty("message"))
    {
     txtMsg.appendText("\nValue of tempClone2.message is: "+ 
      tempClone2.message);
    }else{
     txtMsg.appendText("\nValue of tempClone2.message is " + 
      "unaccessible.");
    }
    
    tempObj1.message = "I'm am a old View1.";
    txtMsg.appendText("\n\nChange Value of tempObj1.message "+ 
     "to 'I'm am a old View1.'");
    
    var tempObject:CustomComponent = CustomComponent(
     tempObj.myContent.getItemAt(0));
    txtMsg.appendText("\nValue of tempObj.myContent." +
     "getItemAt(0).message is: " + tempObject.message);
    if(tempClone1.myContent is ArrayCollection)
    {
     if(tempClone1.myContent.getItemAt(0) is CustomComponent)
     {
      tempObject = CustomComponent(
       tempClone1.myContent.getItemAt(0));
      txtMsg.appendText("\nValue of tempClone1.myContent." +
       "getItemAt(0).message is: " + tempObject.message);
     }else{
      txtMsg.appendText("\nValue of tempClone1.myContent." +
       "getItemAt(0) is not a CustomComponent.");
     }
    }else{
     txtMsg.appendText("\nValue of tempClone1.myContent" +
      "getItemAt(0) is unaccessible.");
    }
    if(tempClone2.myContent is ArrayCollection)
    {
     if(tempClone2.myContent.getItemAt(0) is CustomComponent)
     {
      tempObject = CustomComponent(
       tempClone2.myContent.getItemAt(0));
      txtMsg.appendText("\nValue of tempClone2.myContent." +
       "getItemAt(0).message is: " + tempObject.message);
     }else{
      txtMsg.appendText("\nValue of tempClone2.myContent." +
       "getItemAt(0) is not a CustomComponent.");
     }
    }else{
     txtMsg.appendText("\nValue of tempClone2.myContent" +
      "getItemAt(0) is unaccessible.");
    }
   }
   
   //This function will copy an custom object/component
   //into an Object.
   private function cloneObject(CustomObject:*):*
   {
    var ba:ByteArray = new ByteArray();
    ba.writeObject(CustomObject);
    ba.position = 0;
    return ba.readObject();
   }
   
   //This function will clone an custom object/component.
   //based on the given type of the original object.
   private function cloneCustomObject(CustomObject:*):*
   {
    //Grab the Class Name of the object that we are copying
    var className:String = getQualifiedClassName(CustomObject);
    //Register it first before we clone it
    registerClassAlias(className, 
     getDefinitionByName(className) as Class);
    //While copying the object, the Class Type will be register
    //because of the registerClassAlias call previously
    return ObjectUtil.copy(CustomObject);
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:Label textAlign="center" 
     text="Output:"/>
  <s:TextArea width="90%" 
     height="90%"
     id="txtMsg"/>
 </s:VGroup>
</s:Application>
And here's our custom component Class - CustomComponent.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
   xmlns:s="library://ns.adobe.com/flex/spark" 
   xmlns:mx="library://ns.adobe.com/flex/mx" >
 <fx:Script>
  <![CDATA[
   import mx.collections.ArrayCollection;
   private var _message:String = "";

   public function get message():String
   {
    return _message;
   }

   public function set message(value:String):void
   {
    _message = value;
   }
   
   private var _myContent:ArrayCollection = 
    new ArrayCollection();

   public function get myContent():ArrayCollection
   {
    return _myContent;
   }

   public function set myContent(value:ArrayCollection):void
   {
    _myContent = value;
   }
   
  ]]>
 </fx:Script>
</s:Group>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.