Back and Flexing
Apologies to regular readers may be wondering where I have been. I took a week off after OAUG to sit on a San Diego beach to get toasted to a crisp and to avoid any sharks. We were on that same beach the day before it happened! Needless to say my wife was constantly telling me to watch the kids in the surf, checking for any big gray fins in the water and if seen to run or swim like hell!
While I was away, Noelle has been working on some Flex template goodies. We got a requirement a while back to produce a report similar to this:

Its nothing to 'write home about' standard table stuff but the interesting feature is the 'percentage bar' embedded in the table. Two issues to solve here:
1. Building the 'bar' component - its not an out of the box feature.
2. Getting the bar to render inside the table
Noelle, being very cunning, solved both!

Its not exactly the same look and feel but we were after the functionality - the look can be tweaked quite easily.
Tackling the 'bar' component first, Noelle first needed to build the 'percentage bar'. To do this, Noelle used an ActionScript class to create and render the bar. It basically takes a label object and extends it to render the text value and a rectangle shape, calculates the percentage fill to be used based on the data.
Here's the script
// ActionScript file
package
{// Need these packages for rendering and drawing
import flash.display.*;
import flash.geom.*;
import flash.text.TextField;
import mx.controls.Label;
// We are going to extend the label object
public class PercentageBar extends Label {
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
// Create rectangle shape and width
var rndedRect:Shape = new Shape();
var rectWidth:Number=100;
var rectHeight:Number=15;
// Fill for the rectangle is derived from value in the main.mxml ie the parent application
var rectFill:Number=this.parentApplication.percentCalculated;
//Set the fill type, colors, alphas and ratios
var fillType:String = GradientType.LINEAR;
var colors:Array = [0xFF0000,0xFFFFFF];
var alphas:Array = [1, 1];
var ratios:Array = [0, 255];
// matrix - not required but allows you to specify the fill
var matr:Matrix = new Matrix();
matr.createGradientBox(rectFill, rectHeight, 0, 0, 0);
var spreadMethod:String = SpreadMethod.PAD;
//Start rendering the rectangle
rndedRect.graphics.beginGradientFill(fillType,colors,alphas,ratios,matr,spreadMethod);
rndedRect.graphics.lineStyle(1,0x000000,1,false);
rndedRect.graphics.drawRoundRect(2, 0, rectWidth, rectHeight, 10, 20);
rndedRect.graphics.endFill();
// Add the rectangle to the label object
this.addChild(rndedRect);
//Create the label for the rectangle
// Value drawn from the percentCalculated value in the main.mxml
var label:TextField = new TextField;
label.width = 26;
label.text = (this.parentApplication.percentCalculated+ "%");
label.x = 105;
label.y = 0;
//Add the text field to the label
this.addChild(label);
}
}
}
Those familiar with java should not be too scared of the code - if you spend some time with it its not that tough to understand. Its code yes! but it adds a huge layer of flexibility to the flex reports.
Thats the 'bar' component, so how to bring it into the main table layout. Thats pretty easy too ...
Remember that the bar component needed the 'percentCalculated' value from the parent application ie the main flex template? Well, we need a function to calculate that:
[
Bindable] public var percentCalculated:Number;// determine the percent of the target number - round before passing back
private function calcPercent(row:Object, column:DataGridColumn ):void
{
var a:Number;
var t:Number;
a = row.actual;
t = row.target;
percentCalculated = Math.round((a/t) * 100);
}
Notice we need to declare the 'percentCalculated' variable as public and bindable so the action script class can access it. Its a simple calculation to get the percentage based on the rendered table data.
To get the 'bar' to render we just need to set the last column to use its own renderer ie the PercentageBar AS class that was created.
<mx:DataGrid id="myDatagrid" width="500" height="300" dataProvider="{dataXML.product}" editable="false" enabled="false">
<mx:columns>
<mx:Array>
<mx:DataGridColumn dataField="name" headerText="Product Category"/>
<mx:DataGridColumn dataField="actual" headerText="Units Sold Actual" id="actual"/>
<mx:DataGridColumn dataField="target" headerText="Units Sold Planned" id="target"/>
<mx:DataGridColumn itemRenderer="PercentageBar" width="135" headerText="% of Target" labelFunction="calcPercent"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
You can get the complete source to the flex project here. Thanks again to Noelle for the research and code.
So, a little effort but hopefully you get an idea of how you can take existing Flex objects and extend them to create your own visualizations of the data. You can now tell your users that the 'world is their oyster' when it comes to reporting ... or may be not!