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.

0 comments:

Post a Comment