Render a bar graph within a Flex (Advanced)DataGrid
A nice visual representation of a variable such as a “percentage growth” is a bar graph that shows the value around a central zero point, with different colour bars for negative and positive growth. To render this in an AdvancedDataGrid, we need to create a custom itemRenderer class that overloads the updateDisplayList method and draws a bar using the UIComponent.graphics object. This will give you a grid which looks something like this:

Full source code for the item renderer class below.
package com.symmetri.utils.skins { import flash.display.Graphics; import mx.controls.advancedDataGridClasses.*; import mx.controls.listClasses.*; import mx.core.IDataRenderer; import mx.core.UIComponent; import mx.events.FlexEvent; import mx.utils.GraphicsUtil; [Event(name=“dataChange“, type=“mx.events.FlexEvent“)] public class ReportBarItemRenderer extends UIComponent implements IDataRenderer, IDropInListItemRenderer, IListItemRenderer { private var _data : Object = null; private var _listData : BaseListData = null; public var BAR_MAX_WIDTH:Number = 17; public var BAR_HEIGHT:Number = 13; public var BAR_X:Number = 20; public var BAR_Y:Number = 1; public var DATA_MAX_VALUE:Number = 50; public var COLOR_POSITIVE:Number = 0x0D84A4; public var COLOR_NEGATIVE:Number = 0xD00A3D; public function ReportBarItemRenderer() { super(); } public function get data():Object { return _data; } public function set data(value:Object):void { this._data = value; this.invalidateProperties(); dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); } public function get listData():BaseListData { return _listData; } public function set listData(value:BaseListData):void { this._listData = value; this.invalidateProperties(); dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); } override protected function updateDisplayList(w:Number, h:Number):void { super.updateDisplayList(w, h); if (_data != null) { // draw a horizontal bar to represent value of data // scaled between -1.0 and +1.0 var _fieldName:String = AdvancedDataGridListData(listData).dataField; var _value:String = String(data[AdvancedDataGridListData(listData).dataField]); if (isNaN(Number(_value))) { // do nothing, data value not numeric } else { // draw the bar var _scaledValue:Number = Number(_value)/DATA_MAX_VALUE; var _width:Number = _scaledValue*BAR_MAX_WIDTH; // keep a minimum width of 1 pixel if ((_width > -1) && (_width < 0)) _width = -1; if ((_width < 1) && (_width > 0)) _width = 1; graphics.clear(); graphics.lineStyle(1, 0xFFFFFF, 0); // no border if (_scaledValue < 0) { // draw a negative bar graphics.beginFill(COLOR_NEGATIVE, 1); GraphicsUtil.drawRoundRectComplex(graphics, BAR_X+_width, BAR_Y, -_width, BAR_HEIGHT, 0, 0, 0, 0); } else { // draw a negative bar graphics.beginFill(COLOR_POSITIVE, 1); GraphicsUtil.drawRoundRectComplex(graphics, BAR_X, BAR_Y, _width, BAR_HEIGHT, 0, 0, 0, 0); } graphics.endFill(); // draw a tooltip with the data value this.toolTip = _value.toString(); } } super.validateNow(); } } }

Superb!, I was facing a problem that all my cells were getting rendered with the last value for color, I have to implement one more renderer to get columnIndex and rowIndex.
Comment by Tannu — August 13, 2009 @ 6:38 pm