Flex Custom Column Chart ItemRenderer
I’ve spend a lot of time lately trying to figure out how to draw on chart components and how to use Degrafa (graphics framework for Flex). I thought it’d be cool to have a column chart change colors programmatically based on its value.
This example demonstrates how to:
- Createa custom ItemRenderer and apply it to a series
- Use Degrafa to convert numbers to a color in the spectrum
- Convert pixel to chart coordinates to smoothly change column colors
See the example below, more code and comments after the break (right click to view source):
Creating a programmatic ItemRenderer
package util { import flash.display.GradientType; import flash.display.Graphics; import flash.geom.Point; import flash.geom.Rectangle; import mx.charts.ChartItem; import mx.charts.ColumnChart; import mx.charts.chartClasses.LegendData; import mx.core.Application; import mx.core.IDataRenderer; import mx.core.UIComponent; public class ThermalColumnChartRenderer extends UIComponent implements IDataRenderer { public function ThermalColumnChartRenderer():void { super(); } private var chartItem:ChartItem; public function set data(value:Object):void { if (chartItem == value) return; if (value is LegendData) return; chartItem = ChartItem(value); } public function get data():Object { return chartItem; } override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); // Convert the pixel location into the chart location var curValue:Number = convertDataToLocal(chartItem.itemRenderer.y); var rc:Rectangle = new Rectangle(0, 0, width , height ); var columnColor:uint; var g:Graphics = graphics; g.clear(); g.moveTo(rc.left,rc.top); g.lineStyle(2); // Use thermal class to convert our 0-100 value to a color g.beginFill(getThermalColor(curValue)); g.lineTo(rc.right,rc.top); g.lineTo(rc.right,rc.bottom); g.lineTo(rc.left,rc.bottom); g.lineTo(rc.left,rc.top); g.endFill(); } private function getThermalColor(num:Number):Number { return Application.application.thermalColor.getColor(num); } private function convertDataToLocal(yNum:Number):Number { var chart:ColumnChart = ColumnChart(parentApplication.columnChart); var oldPoint:Point = new Point(0,yNum); var newPoint:Array = chart.localToData(oldPoint); // Not sure why but the data value is always slightly larger than the // actual value, so cap at 100 if(newPoint[1] > 100) return 100; return (newPoint[1]); } } }
Converting a number to a color with help from Degrafa
package util { import com.degrafa.paint.palette.PaletteUtils; public class ThermalColor { private var hi:int = 0; private var lo:int = 0; private var colorMap:Array; // Number of different colors in range private var size:int = 150; public function ThermalColor() { colorMap = getColorMap(); } public function setHi(hi:int):void { this.hi = hi; } public function setLo(lo:int):void { this.lo = lo; } public function setSize(newSize:int):void { size = newSize; colorMap = getColorMap(); } // Generates a thermal color map with [size] many colors public function getColorMap():Array { var colorMap:Array = new Array(); var h:Number; for (var i:int=0; i
References:
http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=2&postId=2021
http://blog.sunild.com/2009/01/simple-degrafa-color-picker.html
http://livedocs.adobe.com/flex/3/html/help.html?content=charts_formatting_12.html
Ok dude… THAT IS PIMP!!!! Excellent post! Very cool!
Yeah, that is very cool. Mind if I add a link to this blog entry from the docs?
matt horn
flex docs