by Adobe
Adobe logo


4 May 2011

Creating an interactive chart



This sample project shows you how to use charts in a Flex application. To look at the code, right-click on the SWF in the browser and select View Source or download the sample files and follow the instructions to import the Flash Builder FXP. Multiple application versions are provided: an XML version that does not require a server as well as versions using Flash Remoting with PHP, Java, and ColdFusion servers.
Flex charting components
The Flex framework includes a set of charting components charts that you can use to enhance the data visualization in an application. The mx.charts.* package includes classes for creating pie, bar, column, line, plot, area, bubble, candlestick, and highLowOpenClose charts. Additional charting components are available from IBM in its ILOG Elixr product that includes 3D charts, gauges and dials, calendars, organization charts, maps, and more.
Pie chart
To create a pie chart, you use the PieChart class. You set the dataProvider property to the collection of data you want to chart and the series property to an instance of the PieSeries class.
<mx:PieChart x="35" y="80" id="deptPieCht" width="282" height="282" dataProvider="{departments}" ...> <mx:series> <mx:PieSeries field="budget" labelField="name" labelPosition="inside" nameField="name" /> </mx:series> </mx:PieChart>
For the PieSeries object, the field is the property of the objects in the dataProvider used to set the data for each pie wedge; it determines the wedge size. labelField is the property of the dataProvider used to display labels for each wedge. Labels are only displayed if the labelPosition style is set to outside, inside, callout, or insideWithCallout to specify where the labels should be displayed relative to each wedge; the default value is none in which case no labels are shown. nameField is the property of the dataProvider used to set the name of a wedge (in data tips or the legend which are discussed in following sections).
Data tips
For every chart, you can specify whether you want data tips to be displayed for individual chart items by setting its showDataTips property to true or false. Data tips are different from data labels, although they can show the same information. Data labels are always visible regardless of the location of the user’s mouse pointer. A data tip is only displayed when the user mouses over a chart item.
By default, a pie chart data tip displays the percentage value for the wedge and the actual data value in parentheses. If the nameField property is set for the PieSeries, the dataProvider property it references is also displayed in the data tip. To customize the text displayed in the data tip further, you can specify a dataTipFunction for the chart.
<mx:PieChart id="deptPieCht" dataProvider="{departments}" showDataTips="true" dataTipFunction="formatDeptPieTips" ...>
The dataTipFunction you specify is called once before every data tip is displayed. The function must have one argument of type HitData (which will contain the information about the data item for which the data tip is to be displayed) and return a String.
protected function formatDeptPieTips(hitData:HitData):String{ return "<b>""</b><br/>"+"Budget: " +moneyFormatter.format(hitData.item.budget); }
You use the HitData object's item property to access properties of the particular data item. item is an object whose properties correspond to those of the objects contained in the chart's dataProvider; it’s the "selected" chart item. In the code above, and hitData.item.budget are displayed where name and budget are properties of the objects in the departments ArrayCollection.
In this example, the value of hitData.item.budget is formatted using an instance of the CurrencyFormatter class that is defined inside the Declarations tag.
<s:CurrencyFormatter id="moneyFormatter" useCurrencySymbol="true" currencySymbol="$" fractionalDigits="0"/>
The Flex framework contains a package of predefined formatters located in the mx.formatters package. To use the formatters, you create an instance of the formatting class and set its properties to values that determine how the string should be formatted and then you call the format() method of the formatter and pass to it the string to format.
In addition to raw text, the return string can also contain a handful of basic HTML tags that the text controls can interpret including <br>,<p>,<a>,<font>,<b>,<i>,<u>, and <li>.
return "<b>""</b><br/>"+"Budget: " +moneyFormatter.format(hitData.item.budget);
To customize the data tip further, for example to use other Flex components inside it, you create and specify a dataTipRenderer class.
Chart events
Chart components have all the normal events inherited from the base Flex component class, UIComponent—such as click, mouseOver, and so on—but they also have specific chart events and chart data events. Chart events (chartClick and chartDoubleClick) are broadcast when the user clicks on a chart but not on an item in the chart and chart data events (itemClick, itemRollOver, and more) are broadcast when the user performs the corresponding action over a chart item, a data point. How close the user needs to be to the actual chart item is set with a mouseSensitivity property.
In the code, deptPieCht_itemClickHandler() is called when the user clicks on a pie wedge.
<mx:PieChart id="deptPieCht" itemClick="deptPieCht_itemClickHandler(event)" ... >
The event handler changes the view state to DepartmentDetails which also includes a column chart (which will be discussed next), sets the column charts's dataProvider to data for the department clicked in the pie chart, and does some additional formatting.
protected function deptPieCht_itemClickHandler(event:ChartItemEvent):void{ currentState="DepartmentDetails"; deptColCht.dataProvider=createDataProvider(event.hitData.item); (...) }
The ChartItemEvent object that is passed to the event handler is used to get information about the item, the department, that was clicked in the pie chart. In addition to the standard properties that all Event objects have, the ChartItemEvent object also has a hitData property that is an instance of the HitData class discussed earlier. Recall the HitData item property contains information about the data point clicked. In the code, the event.hitData.item object is passed to a function called createDataProvider().
This function is just creating an array of four objects, each with a field, actual, and est property for the selected data item, getting the data in a format that can be charted in the column chart.
private function createDataProvider(item:Object):Array{ var dp:Array= [{field:'salaries',actual:item.actualsalary,est:item.estsalary}, {field:'travel',actual:item.actualtravel,est:item.esttravel}, {field:'supplies',actual:item.actualtravel,est:item.esttravel}, {field:'contractors',actual:item.actualcontractors,est:item.estcontractors}]; return dp; }
Column chart
When a wedge in the pie chart is clicked, the application switches to its DepartmentDetails state (if it is not in it already) that includes a ColumnChart instance. Just as for the pie chart, you set a column chart's series property to an instance of a series class. If you want to plot multiple series, you simply set the series property to an array of series objects.
<mx:ColumnChart id="deptColCht" showDataTips="true" includeIn="DepartmentDetails" ...> <mx:series> <mx:ColumnSeries displayName="Estimated" yField="est" .../> <mx:ColumnSeries displayName="Actual" yField="actual" /> </mx:series> </mx:ColumnChart>
You set the dataProvider for the chart (or for individual series) to the collection(s) of data you want to chart using MXML or ActionScript. In this application, the dataProvider is set dynamically in the itemClick handler for the pie chart.
protected function deptPieCht_itemClickHandler(event:ChartItemEvent):void{ deptColCht.dataProvider=createDataProvider(event.hitData.item); (...) }
For a column series, you have to set the yField property equal to the property of the objects in the dataProvider whose values you want displayed in the columns. For a bar chart, you have to set the xField property. This column chart has two series, one charting the est property of the objects in the dataProvider and one charting the actual property.
If you ran this code as shown above, you would see one column for each of the items in the dataProvider. The labels for the y axis would reflect the values for the est and actual properties, but the x axis would just display the position of that item in the dataProvider, for example 1, 2, 3, and so on.
To specify what should be displayed in the axis labels, you set the horizontalAxis and/or verticalAxis properties of a Cartesian chart equal to an instance of an Axis class and set properties for that Axis class instance. There are four predefined axis classes: LinearAxis, LogAxis, DateTimeAxis, and CategoryAxis.
To show the values for the field property of the dataProvider objects along the x axis, you set the ColumnChart horizontalAxis property equal to an instance of the CategoryAxis class and set its categoryfield property to the name of the dataProvider object property to display, field.
<mx:ColumnChart id="deptColCht" showDataTips="true" ...> <mx:horizontalAxis> <mx:CategoryAxis categoryField="field"/> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries displayName="Estimated" yField="est" .../> <mx:ColumnSeries displayName="Actual" yField="actual" .../> </mx:series> </mx:ColumnChart>
You use the title property to display an axis title beneath the axis.
<mx:CategoryAxis id="expenseAxis" categoryField="field" title="Expenses"/>
The axis is also given an id so its title can be set dynamically inside the pie chart's itemClick handler." Expenses";
The x axis title includes the name of the department selected in the pie chart.
Similarly, to set a title on the y axis, you have to set the verticalAxis property of the chart equal to an instance of an Axis class and set its title property. For this column chart, the axis is an instance of LinearAxis. Further control over the axis labels can be obtained by setting additional properties of the Axis object, which for this LinearAxis includes setting the minimum and maximum properties.
<mx:verticalAxis> <mx:LinearAxis id="amountAxis" title="Amount" minimum="0" maximum="500000" labelFunction="axisMoneyFormatter"/> </mx:verticalAxis>
The text that appears in the labels can be formatted by setting the axis labelFunction property to a function to be called before the label is displayed. The function must have three required arguments (the current value of the label, the value of the label before it on the axis, and an instance of the axis object whose labels are being formatted) and return a String. In many cases, only the first argument holding the current value of the label is used.
protected function axisMoneyFormatter(labelValue:Object, previousValue:Object, axis:IAxis):String{ return moneyFormatter.format(labelValue); }
This function is using the same formatter used to format the data tips in the pie chart.
Axis renderers
To format the axis lines or the axis tick lines, you set the chart's horizontalAxisRenderers or verticalAxisRenderers properties equal to an array of instances of the AxisRenderer class, set styles for each AxisRenderer instance, and then associate each AxisRenderer with a particular axis. This may seem more complicated than it needs to be, but charts can have multiple x and y axes so is necessary.
To associate an AxisRenderer with a particular axis, you must assign id properties to the axis objects so they can be referenced.
<mx:horizontalAxis> <mx:CategoryAxis id="expenseAxis" title="Expenses" categoryField="field"/> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis id="amountAxis" title="Amount" .../> </mx:verticalAxis>
Then for each AxisRenderer object, you set its axis property equal to a reference to an axis instance, using {} to specify an object instead of the name of the object as a String.
<mx:verticalAxisRenderers> <mx:AxisRenderer verticalAxisTitleAlignment="vertical" axis="{amountAxis}" .../> </mx:verticalAxisRenderers>
In this code, the verticalAxisTitleAlignment property is used to rotate the title for the vertical LinearAxis 180 degrees so it faces the chart instead of facing away from the chart. Other AxisRenderer styles include showLine, tickPlacement, tickLength, and more.
If you want to change the color, thickness, or alpha of the axis lines or axis tick lines, you set the AxisRenderer axisStroke or tickStroke styles to an instance of a Stroke class (SolidColorStroke or GradientStroke) and set its color, weight, and alpha properties. You could define the complex Stroke objects using nested child tags in the AxisRenderer tag, but often you want to use the same stroke in more than component so it makes sense to instead define a reusable Stroke instance (in ActionScript or in the Declarations tag in MXML).
<s:SolidColorStroke id="brownStrokeThick" color="#7F7364" weight="5"/> <s:SolidColorStroke id="brownStrokeThin" color="#7F7364" weight="1"/>
The weight is the thickness of the line in pixels.
You then set the AxisRenderer axisStroke or tickStroke styles to one of these SolidColorStroke objects.
<mx:verticalAxisRenderers> <mx:AxisRenderer verticalAxisTitleAlignment="vertical" axis="{amountAxis}" axisStroke="{brownStrokeThick}" tickStroke="{brownStrokeThin}"/> </mx:verticalAxisRenderers> <mx:horizontalAxisRenderers> <mx:AxisRenderer axis="{expenseAxis}" axisStroke="{brownStrokeThick}" tickStroke="{brownStrokeThin}"/> </mx:horizontalAxisRenderers>
To customize the text displayed in the labels and titles (changing the color, size, and so on), you set additional styles on the chart or series objects either inline, in a style sheet, or at runtime using ActionScript. In this application, a type selector in the TestDrive.css stylesheet is used to style all column chart titles.
mx|ColumnChart { axis-title-style-name:brownTitles; } .brownTitles{ font-weight:bold; color:#403029; }
To change the colors of the columns, you set the fill style for a ColumnSeries object to an instance of a SolidColor object (which has a color and alpha property) or in a style sheet, you can just set it equal to the hex code for a color. In this application, a class selector is defined in the style sheet that sets the fill style:
.brownFill { fill:#403029; }
... and the style is assigned to the Actual column series using the styleName property.
<mx:ColumnSeries displayName="Actual" yField="actual" showDataEffect="{interpolate}" styleName="brownFill"/>
The color of the Estimated column series is set dynamically in the pie chart's itemClick event handler. Because fill is a style and not a property, the setStyle() method must be used to change it at runtime.
estSeries.setStyle("fill",(event.hitData.chartItem as PieSeriesItem).fill);
To change the colors of the wedges in a pie chart, you set the fills style for a PieSeries object to an array of SolidColor objects or in a style sheet, you can just set it equal to a list of colors. In this application, a type selector is defined that sets the fills style for all PieSeries.
mx|PieSeries { fills:#7F7364,#BFB59F,#E5DFC3,#586F99,#6782B2,#ADCAFF,#F8F8F4; }
A Legend control matches the fill patterns in a chart to labels that describe the data items (for a pie chart) or the data series (for all other charts) shown with those fill patterns. Each entry in a Legend control is known as a legend item and it contains two basic parts: the marker and the label. The simplest way to create a Legend control is to set its dataProvider to an instance of a chart. In this case, all the legend items are created automatically.
The commented code for a legend for the pie chart would display a legend item for each of the pie wedges.
<!--<mx:Legend includeIn="DepartmentChart" dataProvider="{deptPieCht}" x="323" y="80"/>-->
The label for each legend item is set to the value of the data item property specified by the PieSeries nameField property.
<mx:PieSeries field="budget" labelField="name" labelPosition="inside" nameField="name" />
The pie chart legend is redundant in this code example because labels are already displayed for each wedge so it is not displayed.
A legend for the column chart displays one legend item for each of the data series in the chart.
<mx:Legend includeIn="DepartmentDetails" dataProvider="{deptColCht}" x="596" y="80"/>
In this case, the label for each legend item is set to the value of the data item property specified by the ColumnsSeries displayName property.
<mx:ColumnSeries id="estSeries" displayName="Estimated" yField="est" showDataEffect="{interpolate}"/>
A legend is a separate control from the chart components, not part of them, so where the legend appears in the interface is set by its position properties in the container it is added to just like for every other component.
Lastly, let's look at how to animate data changes in a chart. Chart controls support all the standard Flex effects like Zoom and Fade, but they also have effect classes that apply only to the data in the chart. These include SeriesInterpolate, SeriesSlide, and SeriesZoom (located in the mx.charts.effects.effects package). These effects zoom or slide the chart items inside the chart. SeriesInterpolate moves the graphics that represent the existing data in the series to the new points. Instead of clearing the chart and then repopulating it as with SeriesZoom and SeriesSlide, this effect keeps the data on the screen at all times.
Inside the Declarations tag, you'll see a definition for an instance of the SeriesInterpolate class with a duration of 1 second (1000 milliseconds).
<mx:SeriesInterpolate id="interpolate" duration="1000"/>
To apply this effect to a data series in a chart, you set the series' showDataEffect to this effect instance.
<mx:ColumnSeries id="estSeries" displayName="Estimated" yField="est" showDataEffect="{interpolate}"/> <mx:ColumnSeries displayName="Actual" yField="actual" showDataEffect="{interpolate}" styleName="brownFill"/>
Chart series have both hideDataEffect and showDataEffect effects, but for the SeriesInterpolate effect, the hideDataEffect is never triggered so it must be used with the showDataEffect trigger. You can offset the data changes by setting the SeriesInterpolate elementOffset property to a time in milliseconds to stagger the changes.