CHAPTER 16
Charting
The Flex Charting Framework is a powerful series of data-rich controls that let you
create deep and interactive displays of many types of data. Flex defines a few of the
most commonly used charts—bar charts, pie charts, and column charts—and gives
you a great deal of control over their appearance. A Chart contains a ChartSeries that
creates the item renderers based on the dataProvider passed to the Chart. The ChartS
eries object can use an itemRenderer, have distinct dataFields from the dataProvider
used to display data in that ChartSeries, use display effects, and have distinct properties
set to handle user interaction. The Flex Charting Framework is an immense topic, and
as such the recipes in this chapter can cover only a small set of the possibilities. It should
also be noted that the Flex Charting components are a part of the Flex data visualization
package, which is included in the Flex professional edition and not in the standard
edition nor with the free Flex 3 SDK.
16.1 Create a Chart
Problem
You want to add a chart to your application.
Solution
Create a chart of the desired type and add the appropriate ChartSeries object for that
ChartType, and then add a dataProvider to the ChartSeries.
Discussion
Charts come in a variety of types, and it’s important to know what you have in your
toolbox before starting to work.
For every chart type, there is a corresponding ChartSeries. To add a series of data
visualized as a particular type, you add the corresponding series type and bind it to a
dataProvider. The ChartSeries defines what data is shown on the x- and y-axis and
457
what the series name is. Series can also have filters applied to give drop shadows, blur,
or glow.
Depending on the form of your data, you may need to define a horizontal or vertical
axis. If your data is grouped into categories, such as dates, countries, or people, you’ll
need a CategoryAxis. If you are using numeric data, use a LinearAxis.
The dataProvider of a chart can be an array or collection of objects; it can also be an
XMLList object. If you set a dataProvider in your chart tag, your series objects will inherit
that dataProvider, or you can specify a dataProvider for each series object. Different
series objects can use different dataProviders. A chart does not have to use all the data
in the dataProvider; it can use only a specified range.
To create bar and pie charts, you would use code similar to this:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
// a basic data set
[Bindable] public var chartDP:Array = [
{day:'Monday',rainfall:10,elevation:100,temperature:78},
{day:'Tuesday',rainfall:7,elevation:220,temperature:66},
{day:'Wednesday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Friday',rainfall:11,elevation:390,temperature:52},
{day:'Saturday',rainfall:12,elevation:790,temperature:45},
{day:'Sunday',rainfall:14,elevation:1220,temperature:24}
];
]]>
</mx:Script>
<mx:ToggleButtonBar dataProvider=\"{simpleCharts}\" direction=\"vertical\" />
<mx:ViewStack id=\"simpleCharts\" >
<mx:Canvas label=\"Bar\">
<mx:BarChart dataProvider=\"{chartDP}\" >
<mx:verticalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP}\"
categoryField=\"day\" />
</mx:verticalAxis>
<mx:series>
<!-- bar chart uses a BarSeries -->
<mx:BarSeries
yField=\"day\" xField=\"rainfall\"
displayName=\"day\" />
</mx:series>
</mx:BarChart>
458 | Chapter 16: Charting
</mx:Canvas>
<mx:Canvas label=\"Pie\">
<mx:PieChart dataProvider=\"{chartDP}\" >
<!-- no axes need to be defined in a pie chart -->
<mx:series>
<!-- pie chart uses a pie series -->
<mx:PieSeries
field=\"rainfall\"
nameField=\"day\"
labelPosition=\"callout\"
displayName=\"rainfall\" />
</mx:series>
</mx:PieChart>
</mx:Canvas>
</mx:ViewStack>
</mx:Application>
The Candlestick and the HighLowOpenClose chart types need a slightly different kind
of data set:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
// the field names don't need to be 'high','open','low', and 'close', but
you need four different fields to get this kind of chart to work
[Bindable] public var highLowChartDP:Array = [
{date:\"1-Aug-05\",open:42.57,high:43.08,low:42.08,close:42.75},
{date:\"2-Aug-05\",open:42.89,high:43.5,low:42.61,close:43.19},
{date:\"3-Aug-05\",open:43.19,high:43.31,low:42.77,close:43.22},
{date:\"4-Aug-05\",open:42.89,high:43,low:42.29,close:42.71},
{date:\"5-Aug-05\",open:42.49,high:43.36,low:42.02,close:42.99},
{date:\"8-Aug-05\",open:43,high:43.25,low:42.61,close:42.65},
{date:\"9-Aug-05\",open:42.93,high:43.89,low:42.91,close:43.82},
{date:\"10-Aug-05\",open:44,high:44.39,low:43.31,close:43.38},
{date:\"11-Aug-05\",open:43.39,high:44.12,low:43.25,close:44},
{date:\"12-Aug-05\",open:43.46,high:46.22,low:43.36,close:46.1}
];
]]>
</mx:Script>
<mx:CandlestickChart
dataProvider=\"{highLowChartDP}\"
showDataTips=\"true\">
<mx:verticalAxis>
<mx:LinearAxis minimum=\"40\" maximum=\"50\" />
</mx:verticalAxis>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField=\"date\" />
</mx:horizontalAxis>
<mx:series>
<mx:CandlestickSeries
16.1 Create a Chart | 459
dataProvider=\"{highLowChartDP}\"
openField=\"open\"
highField=\"high\"
lowField=\"low\"
closeField=\"close\"
displayName=\"Rainfall\"/>
</mx:series>
</mx:CandlestickChart>
</mx:Application>
16.2 Add Effects to Charts
Problem
You want to use effects for a chart.
Solution
Add an effect of the desired type to the chart’s axis or data series objects by using
<mx:rollOverEffect> or <mx:rollOutEffect> within the definition of the Axis.
Discussion
Any Effect from the mx.effects package can be added to the Series or Axis of a
Chart. A simple rollover effect can enhance the look and feel of your chart. Here’s a
basic example of how to add a fade-in and fade-out effect on rollover and rollout of
chart elements:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
[Bindable] public var chartDP:Array = [
{day:'Monday',rainfall:10,elevation:100,temperature:78},
{day:'Tuesday',rainfall:7,elevation:220,temperature:66},
{day:'Wednesday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Friday',rainfall:11,elevation:390,temperature:52},
{day:'Saturday',rainfall:12,elevation:790,temperature:45},
{day:'Sunday',rainfall:14,elevation:1220,temperature:24}
];
]]>
</mx:Script
<mx:AreaChart dataProvider=\"{chartDP}\" >
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP}\"
categoryField=\"day\" />
</mx:horizontalAxis>
<mx:series>
<mx:AreaSeries alpha=\".5\"
460 | Chapter 16: Charting
yField=\"rainfall\"
displayName=\"rainfall\">
Here a Fade effect is set for the rollover and rollout of the AreaSeries; these effects will
affect only this particular series, not the chart as a whole:
<mx:rollOverEffect>
<mx:Fade alphaFrom=\".5\" alphaTo=\"1\" duration=\"500\" />
</mx:rollOverEffect>
<mx:rollOutEffect>
<mx:Fade alphaFrom=\"1\" alphaTo=\".5\" duration=\"500\" />
</mx:rollOutEffect>
</mx:AreaSeries>
</mx:series>
</mx:AreaChart>
</mx:Application>
To add a little more action to your chart, you can use SeriesInterpolate, SeriesZoom,
and SeriesSlide to animate changing data. SeriesInterpolate animates the data points
from their old positions to their new positions. SeriesZoom shrinks the old data to
nothing and grows the new data from nothing. SeriesSlide slides out the old data and
slides in the new data. These events are typically assigned to the showDataEffect and
hideDataEffect of a series object. SeriesInterpolate can be assigned to only the show
DataEffect and has no affect when assigned to the hideDataEffect.
This example shows a slide effect that can be used when switching a chart between two
data sets. To see SeriesZoom, comment out the other effects and comment in the
SeriesZoom effect. To see SeriesInterpolate, comment out the other effects, comment
in the SeriesInterpolate effect, and remove the hideDataEffect property from the
ColumnSeries tag.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
[Bindable] public var chartDP1:Array = [
{day:'Monday',rainfall:10,elevation:100,temperature:78},
{day:'Tuesday',rainfall:7,elevation:220,temperature:66},
{day:'Wednesday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Friday',rainfall:11,elevation:390,temperature:52},
{day:'Saturday',rainfall:12,elevation:790,temperature:45},
{day:'Sunday',rainfall:14,elevation:1220,temperature:24}
];
[Bindable] public var chartDP2:Array = [
{day:'Sunday',rainfall:10,elevation:100,temperature:78},
{day:'Saturday',rainfall:7,elevation:220,temperature:66},
{day:'Friday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Wednesday',rainfall:11,elevation:390,temperature:52},
{day:'Tuesday',rainfall:12,elevation:790,temperature:45},
{day:'Monday',rainfall:14,elevation:1220,temperature:24}
];
16.2 Add Effects to Charts | 461
]]>
</mx:Script>
<mx:SeriesSlide id=\"dataIn\" duration=\"500\" direction=\"up\"/>
<mx:SeriesSlide id=\"dataOut\" duration=\"500\" direction=\"up\"/>
<mx:SeriesZoom id=\"dataOut\" duration=\"500\"/>
<mx:SeriesInterpolate id=\"dataIn\" duration=\"1000\"/> -->
<mx:BarChart id=\"rainfallChart\" dataProvider=\"{chartDP1}\" >
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP1}\"
categoryField=\"day\" />
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSeries
yField=\"rainfall\" xField=\"day\"
displayName=\"rainfall\"
showDataEffect=\"{dataIn}\" hideDataEffect=\"{dataOut}\" />
</mx:series>
</mx:BarChart>
<mx:HBox>
<mx:RadioButton groupName=\"dataProvider\" label=\"Data Provider 1\"
selected=\"true\" click=\"rainfallChart.dataProvider=chartDP1;\"/>
<mx:RadioButton groupName=\"dataProvider\" label=\"Data Provider 2\"
click=\"rainfallChart.dataProvider=chartDP2;\"/>
</mx:HBox>
</mx:Application>
16.3 Select Regions of a Chart
Problem
You need to select regions or items on your chart.
Solution
Use the selectionMode attribute of your chart to set the selection type you want; then
use mouse, keyboard, or programmatic means to select items on your chart.
Discussion
Just as with the different list components, chart elements are selectable. This might be
used for showing more detail on a data point with data grids or a secondary chart. To
make a chart selectable, you set the selectionMode attribute to single or multiple (the
default value of this attribute is none). A none value does not allow any selection, a
single value allows only one item to be selected at a time, and a multiple value allows
multiple items to be selected.
462 | Chapter 16: Charting
Chart selection can happen via the mouse, via the keyboard, by dragging a rectangular
region to select multiple points, or programmatically in ActionScript. When selecting
multiple items, the first item selected is known as the anchor and the last, the caret.
Mouse selection is very straightforward. Simply clicking a chart item puts it in a selected
state. For multiple selections, hold down the Shift key to select all the items between
your first and last selection, or hold down the Ctrl key (or on a Mac, the Command
key) for noncontiguous multiple selections. Using the left and right arrow keys lets you
cycle through the items in a chart. Chart items cycle per series. When the selection
Mode attribute is set to multiple, drawing a rectangle in a chart selects all chart items
that overlap with that rectangle.
Programmatic selection is a little more complex. A charting selection API lets you access
which items are selected and manipulate selection. You can use these attributes of a
ChartSeries object to get and set selection state:
• selectedItem
• selectedItems
• selectedIndex
• selectedIndices
Alternatively, you can use methods defined in the ChartBase class:
• getNextItem()
• getPreviousItem()
• getFirstItem()
• getLastItem()
Using the Change event of the chart enables you to be notified when the selection changes
based on mouse or keyboard interaction (but not programmatic changes).
The following example shows the selected data for all of the chart’s selected items in a
DataGrid. There are also Next and Previous buttons for navigating the selection pro-
grammatically.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"vertical\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
[Bindable] public var chartDP:Array = [
{day:'Monday',rainfall:10,elevation:100,temperature:78},
{day:'Tuesday',rainfall:7,elevation:220,temperature:66},
{day:'Wednesday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Friday',rainfall:11,elevation:390,temperature:52},
{day:'Saturday',rainfall:12,elevation:790,temperature:45},
{day:'Sunday',rainfall:14,elevation:1220,temperature:24}
];
private function changeSelectedIndex(offset:int):void
16.3 Select Regions of a Chart | 463
{
barSeries.selectedIndex+=offset;
onSelectionChange();
}
private function onSelectionChange():void
{
// programmatic changes to chart selection don't fire a Change event,
so we need to manually reset
// the dataProvider of our detail grid when we programatically change
the selection
detailGrid.dataProvider = barChart.selectedChartItems;
}
]]>
</mx:Script>
<!-- use the change event to set the dataProvider of our detail grid to our
chart's selected items -->
<mx:BarChart id=\"barChart\" dataProvider=\"{chartDP}\" selectionMode=\"multiple\"
change=\"onSelectionChange()\">
<mx:verticalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP}\"
categoryField=\"day\" />
</mx:verticalAxis>
<mx:series>
<mx:BarSeries id=\"barSeries\" selectedIndex=\"0\"
yField=\"day\" xField=\"rainfall\"
displayName=\"day\" />
</mx:series>
</mx:BarChart>
<mx:HBox>
<mx:Button click=\"changeSelectedIndex(1)\" label=\"Previous\" />
<mx:Button click=\"changeSelectedIndex(−1)\" label=\"Next\" />
</mx:HBox>
<mx:DataGrid id=\"detailGrid\" >
<mx:columns>
<mx:DataGridColumn dataField=\"xValue\" headerText=\"rainfall\" />
<mx:DataGridColumn dataField=\"yValue\" headerText=\"day\" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
16.4 Format Tick Marks for a Chart
Problem
You want to use a custom look for the chart tick marks.
Solution
Use styles on an AxisRenderer to set the desired look for your chart.
464 | Chapter 16: Charting
Discussion
Using styles, Flex gives you quite a bit of control over where and how tick marks are
displayed. There are two types of tick marks in Flex charts: major and minor. Major
tick marks correspond to axis labels, and minor tick marks appear in-between the major
tick marks.
Styles that control tick mark appearance are defined in the AxisRenderer for a chart
axis. Major tick marks can be customized with tickPlacement, tickAlignment, and
tickLength. Minor tick marks can be customized with minorTickPlacement, minorTick
Alignment, and minorTickLength.
The tickMarkPlacement and minorTickPlacement styles define where the tick mark is in
relation to the axis line. Possible values are listed in Table 16-1.
Table 16-1. Tick Mark Values and Their Placement
Value Placement
cross Across the axis
inside Inside the axis
outside Outside the axis
none No tick mark
This example places the major tick marks inside the chart axis and the minor ones
outside. The major tick marks are 5 pixels long, and the minor tick marks are 10.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\">
<mx:Script>
<![CDATA[
[Bindable] public var chartDP:Array = [
{day:'Monday',rainfall:10,elevation:100,temperature:78},
{day:'Tuesday',rainfall:7,elevation:220,temperature:66},
{day:'Wednesday',rainfall:5,elevation:540,temperature:55},
{day:'Thursday',rainfall:8,elevation:60,temperature:84},
{day:'Friday',rainfall:11,elevation:390,temperature:52},
{day:'Saturday',rainfall:12,elevation:790,temperature:45},
{day:'Sunday',rainfall:14,elevation:1220,temperature:24}
];
]]>
</mx:Script>
<mx:Style>
.customTicks {
tickPlacement:inside;
minorTickPlacement:outside;
tickLength:5;
minorTickLength:10;
}
</mx:Style>
16.4 Format Tick Marks for a Chart | 465
<mx:Canvas label=\"Area\">
<mx:AreaChart dataProvider=\"{chartDP}\" >
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP}\"
categoryField=\"day\" />
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id=\"vertAxis\" />
</mx:verticalAxis>
<mx:verticalAxisRenderers>
<mx:AxisRenderer axis=\"{vertAxis}\" styleName=\"customTicks\" />
</mx:verticalAxisRenderers>
<mx:series>
<mx:AreaSeries
yField=\"rainfall\"
displayName=\"rainfall\" />
</mx:series>
</mx:AreaChart>
</mx:Canvas>
</mx:Application>
16.5 Create a Custom Label for a Chart
Problem
You want to customize the chart labels.
Solution
Use styles and label functions.
Discussion
Charts use two kinds of labels: axis labels and data labels. Axis labels are used to show
the values at points along an axis. These can be customized with a label function. Data
labels show the data values at the location of data points and chart elements.
Using axis labels, you can gain greater control over how your axis labels are formatted.
If you need specific date formatting or currency formatting, for example, you can use
a label function. Label functions also work for data labels.
Label functions for numeric axes, category axes, and series are a bit different, as shown
next.
The numeric axis label function has the following signature:
function_name(labelValue:Object, previousLabelValue:Object, axis:IAxis):String
The parameters are as follows:
466 | Chapter 16: Charting
labelValue
The value of the current label.
previousLabelValue
The value of the label preceding this label. If this is the first label, the value of
previousLabelValue is null.
axis
The axis object, such as CategoryAxis or NumericAxis.
The category axis label function has the following signature:
function_name(labelValue:Object, previousLabelValue:Object, axis:axis_type,
labelItem:Object):String
categoryValue
The value of the category to be represented.
previousCategoryValue
The value of the previous category on the axis.
axis
The CategoryAxis being rendered.
categoryItem
The item from the data provider that is being represented.
This example uses a CurrencyFormatter for formatting the vertical axis labels and the
data labels:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"horizontal\"
backgroundColor=\"0xFFFFFF\" initialize=\"onInit()\">
<mx:Script>
<![CDATA[
import mx.charts.chartClasses.Series;
import mx.charts.ChartItem;
import mx.charts.chartClasses.IAxis;
import mx.formatters.CurrencyFormatter;
[Bindable] public var chartDP:Array = [
{month:'Jan',costs:10000,sales:100000},
{month:'Feb',costs:7000,sales:220000},
{month:'Mar',costs:5000,sales:540000},
{month:'April',costs:8000,sales:60000},
{month:'May',costs:11000,sales:390000},
{month:'June',costs:12000,sales:790000},
{month:'July',costs:14000,sales:1220000}
];
private var formatter:CurrencyFormatter;
private function onInit():void
{
formatter = new CurrencyFormatter();
formatter.currencySymbol = '$';
formatter.precision = 0;
16.5 Create a Custom Label for a Chart | 467
formatter.useThousandsSeparator = true;
}
private function currencyAxisLabel(value:Object, previousValue:Object,
axis:IAxis):String
{
return formatter.format(value);
}
]]>
</mx:Script>
<mx:LineChart dataProvider=\"{chartDP}\" >
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider=\"{chartDP}\"
categoryField=\"month\"
/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis labelFunction=\"{currencyAxisLabel}\" />
</mx:verticalAxis>
<mx:series>
<mx:LineSeries
yField=\"costs\" xField=\"month\"
displayName=\"Costs\" />
</mx:series>
</mx:LineChart>
</mx:Application>
16.6 Create a Drill-Down Effect for a Columnar Chart
Problem
You want to display an effect when drilling down into chart data to display.
Solution
Create a new array to populate with data from the chosen item and set the
dataProvider of the ColumnChart to that array. Use a SeriesZoom to transition from the
overview data set to the specific data set.
Discussion
The idea of drilling down into a chart is a UI concept that refers to allowing a user to
select a particular data item from a larger set for closer inspection. A chart’s drill-down
effect enables you to select items in the chart and then display more-specific data about
that item. This is achieved simply by setting the dataProvider of the ChartSeries. An
effect can be played when the dataProvider is changed by setting the showDataEffect
and hideDataEffect properties. There are three effects defined in the
468 | Chapter 16: Charting
mx.charts.effects package: SeriesInterpolate, SeriesSlide, and SeriesZoom. This ex-
ample uses the SeriesZoom effect. The SeriesZoom class zooms in and out of the data
displayed in the chart by using a focal point set via the horizontalFocus and vertical
Focus attributes.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\">
<mx:Script><![CDATA[
import mx.charts.series.items.ColumnSeriesItem;
import mx.graphics.SolidColor;
import mx.charts.ChartItem;
import mx.graphics.IFill;
import mx.collections.ArrayCollection;
import mx.charts.HitData;
import mx.charts.events.ChartItemEvent;
This deep data set allows the display of all the items together, as well as allowing each
item to be shown individually:
[Bindable]
public var overview:ArrayCollection = new ArrayCollection ([
{ date:\"01/02/2006\", total:3000, food:1300, drinks:1700, other:0,
expenses:2700, profit:300},
{ date:\"01/08/2006\", total:3500, food:1800, drinks:1500, other:200,
expenses:2900, profit:600},
{ date:\"01/15/2006\", total:2600, food:1000, drinks:1600, other:0,
expenses:2700, profit:−100},
{ date:\"01/22/2006\", total:3200, food:1300, drinks:1900, other:0,
expenses:2900, profit:200 },
{ date:\"02/1/2006\", total:2200, food:1200, drinks:1000, other:0,
expenses:2100, profit:100 },
{ date:\"02/8/2006\", total:2600, food:1300, drinks:1600, other:100,
expenses:2700, profit:400 },
{ date:\"02/16/2006\", total:4100, food:2300, drinks:1700, other:100,
expenses:2700, profit:200 },
{ date:\"02/22/2006\", total:4300, food:2300, drinks:1700, other:300,
expenses:3300, profit:1000 }]);
[Bindable]
public var drillDownDataSet:ArrayCollection;
[Bindable]
public var mainDataProvider:ArrayCollection = overview;
private function zoomIntoSeries(e:ChartItemEvent):void {
if (mainDataProvider == overview) {
drillDownDataSet = new ArrayCollection(createDataForDate(e));
columnSeries.displayName = \"Daily Breakdown\";
columnSeries.yField = \"amount\";
columnSeries.xField = \"type\";
ca1.categoryField = \"type\";
mainPanel.title = \"Profits for \" + e.hitData.item.date;
mainDataProvider = drillDownDataSet;
16.6 Create a Drill-Down Effect for a Columnar Chart | 469
} else {
mainDataProvider = overview;
columnSeries.displayName = \"Profit by date\";
columnSeries.yField = \"profit\";
columnSeries.xField = \"date\";
ca1.categoryField = \"date\";
mainPanel.title = \"Profit Overview\";
}
}
private function profitFunction(element:ChartItem, index:Number):IFill {
// black for profit
var dateColor:SolidColor = new SolidColor(0x000000);
var item:ColumnSeriesItem = ColumnSeriesItem(element);
var profit:Number = Number(item.yValue);
if (profit < 0) {
// red for not profitable
dateColor.color = 0xFF0000;
}
return dateColor;
}
Here the hitData property of the ChartItemEvent is used to generate the data for the
specific column in the ColumnChart that has been clicked. This will be the data set for
the drilled-down view:
private function createDataForDate(e:ChartItemEvent):Array {
var result:Array = [];
var food:Object = { type:\"food\", amount:e.hitData.item.food };
var drinks:Object = { type:\"drinks\", amount:e.hitData.item.drinks };
var other:Object = { type:\"other\", amount:e.hitData.item.other };
var expenses:Object = { type:\"expenses\", amount:e.hitData.item.expenses };
result.push(food);
result.push(drinks);
result.push(other);
result.push(expenses);
return result;
}
]]></mx:Script>
<mx:SeriesZoom id=\"slideZoomIn\" duration=\"1000\" verticalFocus=\"bottom\"/>
<mx:SeriesZoom id=\"slideZoomOut\" duration=\"1000\" verticalFocus=\"bottom\"/>
<mx:Panel id=\"mainPanel\" title=\"Profitability\">
<mx:ColumnChart id=\"chart\" showDataTips=\"true\" itemClick=\"zoomIntoSeries
470 | Chapter 16: Charting
(event)\" dataProvider=\"{mainDataProvider}\">
<mx:series>
The showDataEffect and hideDataEffect properties indicate which effect will be played
when the dataProvider for a ChartSeries is changed:
<mx:ColumnSeries id=\"columnSeries\" displayName=\"Total profit\"
fillFunction=\"profitFunction\"
yField=\"profit\" xField=\"date\" hideDataEffect=\"slideZoomOut\"
showDataEffect=\"slideZoomIn\"/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis id=\"ca1\" categoryField=\"date\"/>
</mx:horizontalAxis>
</mx:ColumnChart>
</mx:Panel>
</mx:Application>
16.7 Skin Chart Items
Problem
You need to skin (change the appearance of) the chart items displayed in a chart.
Solution
Create a skin class that extends the ProgrammaticSkin class and implements the
IDataRenderer interface. Set that skin class to be the itemRenderer for the ChartSeries
of the chart.
Discussion
The mx.charts.ChartItem is the representation of a data point in the series, so there is
one ChartItem for each item in the series’ dataProvider. The ChartItem defines the fol-
lowing properties:
currentState : String
Defines the appearance of the ChartItem.
element : IChartElement
The series or element that owns the ChartItem.
index : int
The index of the data from the series’ dataProvider that the ChartItem represents.
item : Object
The item from the series’ dataProvider that the ChartItem represents.
itemRenderer : IFlexDisplayObject
The instance of the chart’s item renderer that represents this ChartItem.
16.7 Skin Chart Items | 471
The ChartItem is owned by a ChartSeries, which uses the items to display the data
points. A ChartSeries is owned by a Chart, which may have one or more ChartSeries
items with distinct data properties. Each series has a default renderer that Flex uses to
draw that series’ ChartItem objects, as listed in Table 16-2. You can specify a new
renderer to use with the series’ itemRenderer style property. This property points to
a class that defines the appearance of the ChartItem object.
Table 16-2. Available itemRenderers for Charts
Chart Type Renderer Classes
AreaChart AreaRenderer
BarChart BoxItemRenderer
BubbleChart CircleItemRenderer
ColumnChart CrossItemRenderer
PlotChart DiamondItemRenderer
ShadowBoxRenderer
TriangleItemRenderer
CandlestickChart CandlesitckItemRenderer
HLOCChart HLOCItemRenderer
LineChart LineRenderer
ShadowLineRenderer
PieChart WedgeItemRenderer
To set an image as the itemRenderer for a series in a chart, simply set an embedded
image as the itemRenderer property:
<mx:PlotSeries xField=\"goals\" yField=\"games\" displayName=\"Goals per game\" itemRenderer=
\"@Embed(source='../assets/soccerball.png\")\" radius=\"20\" legendMarkerRenderer=\"
@Embed(source='../assets/soccerball.png')\"/>
To create a skin for a chart item, create a ProgrammaticSkin and override the
updateDisplayList method:
package oreilly.cookbook
{
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.IBitmapDrawable;
import mx.charts.series.items.ColumnSeriesItem;
import mx.core.IDataRenderer;
import mx.skins.ProgrammaticSkin;
public class CustomRenderer extends ProgrammaticSkin implements IDataRenderer {
private var _chartItem:ColumnSeriesItem;
472 | Chapter 16: Charting
[Embed(source=\"../../assets/Shakey.png\")]
private var img:Class;
public function get data():Object {
return _chartItem;
}
public function set data(value:Object):void {
_chartItem = value as ColumnSeriesItem;
invalidateDisplayList();
}
override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight
:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
var img_inst = new img();
var bmd:BitmapData = new BitmapData((img_inst as DisplayObject).height,
(foo_inst as DisplayObject).width, true);
bmd.draw(img_inst as IBitmapDrawable);
graphics.clear();
graphics.beginBitmapFill(bmd);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.endFill();
}
}
}
Now the ProgrammaticSkin class can be set as the itemRenderer of a ColumnSeries:
<mx:ColumnChart id=\"column\" dataProvider=\"{expenses}\">
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider=\"{expenses}\"
categoryField=\"Month\"
/>
</mx:horizontalAxis>
<mx:series>
<mx:Array>
<mx:ColumnSeries
xField=\"Month\"
yField=\"Expenses\"
displayName=\"Expenses\"
itemRenderer=\"oreilly.cookbook.CustomRenderer\"
/>
</mx:Array>
</mx:series>
</mx:ColumnChart>
16.7 Skin Chart Items | 473
16.8 Use ActionScript to Dynamically Add and Remove Columns
for a Chart
Problem
You need to add or remove columns of data in a column chart at runtime.
Solution
Using series sets in ActionScript, you can dynamically add and remove data series any
time.
Discussion
Series can be grouped on a chart in a Set object. There are different Set types for each
chart type, as listed in Table 16-3. For example, a ColumnChart uses a ColumnSet to group
ColumnSeries. Sets use a type attribute for determining how the series items are grouped.
Table 16-3. Types of Groupings for Series Items
Attribute Description
Clustered Series items are grouped side by side in each category. This is the default for BarCharts and ColumnCharts.
Stacked Series items are stacked on top of each other. Each item represents the cumulative value of the items beneath it.
Overlaid Series items are overlaid on top of each other, with the last series on top.
100 percent Series items are stacked on top of each other, adding up to 100 percent. Each item represents the percentage
value of the whole set.
Chart sets have a series attribute that accepts an array of series objects. By using sets,
you can group your data in many ways. For example, your chart could have two sets
of stacked sets, and each stacked set could have a set of clustered series.
By setting up your series and sets in ActionScript, you can add and remove them any
time you like.
The following example uses a data set that tracks millimeters of rainwater throughout
the day for a week. Each time of day is a series and is initialized in ActionScript. For
each series, there is a check box; when the check boxes are changed, ColumnSet is re-
initialized and adds a series for each selected check box. Finally, the ColumnSet is added
to a new array and set to the series attribute of the column chart.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"vertical\"
backgroundColor=\"0xFFFFFF\" creationComplete=\"onComplete()\">
<mx:Script>
<![CDATA[
import mx.charts.series.ColumnSet;
import mx.charts.series.ColumnSeries;
474 | Chapter 16: Charting
[Bindable] private var chartDP:Array = [{day:'Monday',dawnRainfall:10,
morningRainfall:12,midDayRainfall:6,afternoonRainfall:4,duskRainfall:5},
{day:'Tuesday',dawnRainfall:7,morningRainfall:10,midDayRainfall:5,afternoonRainfall:5,
duskRainfall:6},
{day:'Wednesday',dawnRainfall:5,morningRainfall:9,midDayRainfall:3,afternoonRainfall:2
,duskRainfall:3},
{day:'Thursday',dawnRainfall:8,morningRainfall:9,midDayRainfall:6,afternoonRainfall:6,
duskRainfall:6},
{day:'Friday',dawnRainfall:11,morningRainfall:13,midDayRainfall:4,afternoonRainfall:5,
duskRainfall:7},
{day:'Saturday',dawnRainfall:12,morningRainfall:13,midDayRainfall:9,
afternoonRainfall:3,duskRainfall:4},
{day:'Sunday',dawnRainfall:14,morningRainfall:12,midDayRainfall:5,afternoonRainfall:1,
duskRainfall:3}
];
private var dawnSeries:ColumnSeries;
private var morningSeries:ColumnSeries;
private var midDaySeries:ColumnSeries;
private var afternoonSeries:ColumnSeries;
private var duskSeries:ColumnSeries;
private var columnSet:ColumnSet;
private function onComplete():void
{
//initialize our clustered ColumnSet
columnSet = new ColumnSet();
columnSet.type = \"clustered\";
//initialize all of our series
dawnSeries = new ColumnSeries();
dawnSeries.yField = \"dawnRainfall\";
dawnSeries.xField = \"day\";
dawnSeries.displayName = \"Dawn Rainfall\";
morningSeries = new ColumnSeries();
morningSeries.yField = \"morningRainfall\";
morningSeries.xField = \"day\";
morningSeries.displayName = \"Morning Rainfall\";
midDaySeries = new ColumnSeries();
midDaySeries.yField = \"midDayRainfall\";
midDaySeries.xField = \"day\";
midDaySeries.displayName = \"Mid-day Rainfall\";
afternoonSeries = new ColumnSeries();
afternoonSeries.yField = \"afternoonRainfall\";
afternoonSeries.xField = \"day\";
afternoonSeries.displayName = \"Afternoon Rainfall\";
duskSeries = new ColumnSeries();
duskSeries.yField = \"duskRainfall\";
duskSeries.xField = \"day\";
duskSeries.displayName = \"Dusk Rainfall\";
16.8 Use ActionScript to Dynamically Add and Remove Columns for a Chart | 475
updateSeries();
}
Here the series is pushed into the column set, updating the chart:
private function updateSeries():void
{
//reinit columnSet
columnSet.series = new Array();
//for each check box, add the corresponding series if it's checked
if(showDawnCheckBox.selected) {
columnSet.series.push(dawnSeries);
}
if(showMorningCheckBox.selected) {
columnSet.series.push(morningSeries);
}
if(showMidDayCheckBox.selected) {
columnSet.series.push(midDaySeries);
}
if(showAfternoonCheckBox.selected) {
columnSet.series.push(afternoonSeries);
}
if(showDuskCheckBox.selected) {
columnSet.series.push(duskSeries);
}
// put columnSet in an array and set to
// the chart's \"series\" attribute
rainfallChart.series = [columnSet];
}
]]>
</mx:Script>
<mx:ColumnChart id=\"rainfallChart\" dataProvider=\"{chartDP}\" >
<mx:horizontalAxis>
<mx:CategoryAxis categoryField=\"day\" />
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis minimum=\"0\" maximum=\"14\" />
</mx:verticalAxis>
<!-- notice there is no series attribute defined, we do that in AS above -->
</mx:ColumnChart>
<mx:HBox>
<mx:CheckBox id=\"showDawnCheckBox\"
label=\"Dawn Rainfall\" selected=\"true\" change=\"updateSeries()\" />
<mx:CheckBox id=\"showMorningCheckBox\"
label=\"Morning Rainfall\" change=\"updateSeries()\" />
<mx:CheckBox id=\"showMidDayCheckBox\"
label=\"Mid-day Rainfall\" change=\"updateSeries()\" />
<mx:CheckBox id=\"showAfternoonCheckBox\"
label=\"Afternoon Rainfall\" change=\"updateSeries()\" />
<mx:CheckBox id=\"showDuskCheckBox\"
label=\"Dusk Rainfall\" change=\"updateSeries()\" />
</mx:HBox>
</mx:Application>
476 | Chapter 16: Charting
16.9 Overlap Multiple ChartSeries
Problem
You want to be able to use different chart types to represent overlapping data sets.
Solution
Use a ColumnChart to hold the multiple charts, and then use an <mx:Series> tag to define
the multiple charts and their properties.
Discussion
Any chart can contain multiple ChartSeries within its series array, each of which can
represent different fields within a data provider or different data providers. In the fol-
lowing example, multiple ChartSeries items are passed to the ColumnChart:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" creationComplete=\"genData()\">
<mx:Script>
<![CDATA[
private var DJIA:Number = Math.random()*50 - 20;
private var NASDAC:Number = DJIA - Math.random() * 20;
private var SP500:Number = Math.random()*40;
public function genData():void
{
// assigning the data that the chart is bound to
// is best done via a local variable that is then
// set to the chart data, rather than adding values to the
// dataprovider of the chart
var newArr:Array = [];
for(var i:int = 0; i<10; i++)
{
DJIA = DJIA + Math.random()*10 - 5;
NASDAC = NASDAC - Math.random() * 5;
SP500 = Math.random()*40;
newArr.push({\"DJIA\": DJIA, \"NASDAC\": NASDAC, \"SP500\": SP500 });
}
chartData = newArr;
}
[Bindable] public var chartData:Array = [];
]]>
</mx:Script>
<mx:SeriesInterpolate id=\"eff\" elementOffset=\"1\" minimumElementDuration=\"40\"
duration=\"2000\"/>
<mx:Button click=\"genData()\" label=\"Generate data\"/>
<mx:ColumnChart y=\"100\" width=\"100%\" height=\"100%\" dataProvider=\"{chartData}\">
<mx:series>
<mx:ColumnSeries showDataEffect=\"{eff}\" yField=\"DJIA\"/>
<mx:ColumnSeries showDataEffect=\"{eff}\" yField=\"NASDAC\"/>
16.9 Overlap Multiple ChartSeries | 477
<mx:ColumnSeries showDataEffect=\"{eff}\" yField=\"SP500\"/>
</mx:series>
</mx:ColumnChart>
</mx:Application>
The multiple ColumnSeries objects will be rendered one atop the other in the
ColumnChart.
16.10 Drag and Drop Items in a Chart
Problem
You need to drag items from a data source into a chart.
Solution
Override the dragEnterHandler and dragDropHandler methods of a chart component to
create a chart with dragging and dropping enabled.
Discussion
The drag-and-drop feature of a chart works much the same as the drag-and-drop feature
of any other component in the Flex Framework: The parent component defines a han-
dler for the mouseMove event of the chart and a handler for the dragDrop event of the
chart that will receive the dropped data. In the following example, two pie charts have
their dragEnabled and dropEnabled properties set to true and have two separate Array
Collections used as their dataProviders. When data is dropped from one component,
it is removed from the dragged component and added to the dataProvider of the other.
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\" xmlns:cookbook=
\"oreilly.cookbook.*\">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.charts.PieChart;
import mx.core.IUIComponent;
import mx.core.DragSource;
import mx.containers.Panel;
import mx.managers.DragManager;
import mx.collections.ArrayCollection;
[Bindable]
private var masterArrColl:ArrayCollection = new ArrayCollection([{ \"name\":
\"C Ronaldo\", \"sog\":128, \"goals\":20, \"games\":33 },
{ \"name\":\"A Adebayor\", \"sog\":128, \"goals\":20, \"games\":35 },
{ \"name\":\"F Torres\", \"sog\":98, \"goals\":18, \"games\":32 },
{ \"name\":\"W Rooney\", \"sog\":89, \"goals\":17, \"games\":34 },
{ \"name\":\"D Drogba\", \"sog\":114, \"goals\":16, \"games\":31 }]);
[Bindable]
private var subColl:ArrayCollection = new ArrayCollection([{ \"name\":
478 | Chapter 16: Charting
\"C Ronaldo\", \"sog\":128, \"goals\":20, \"games\":33 },
{ \"name\":\"A Adebayor\", \"sog\":128, \"goals\":20, \"games\":35 }]);
// Initializes the drag-and-drop operation.
private function mouseMoveHandler(event:MouseEvent):void {
event.preventDefault();
// Get the drag initiator component from the event object.
var dragInitiator:PieChart = PieChart(event.currentTarget);
// Create a DragSource object.
var ds:DragSource = new DragSource();
//make sure that the chart has a selected item
if(dragInitiator.selectedChartItem == null) return;
// Call the DragManager doDrag() method to start the drag.
DragManager.doDrag(dragInitiator, ds, event);
}
The mouseMoveHandler method passes the dragInitiator, the component that has dis-
patched the dragging event to the DragManager.doDrag manager, along with the
DataSource object (which is not used in this example), and the mouse event that initiated
the action.
// Called if the target accepts the dragged object and the user
// releases the mouse button while over the Canvas container.
private function dragDropHandler(event:DragEvent):void {
// Get the selected data from the chart
var index:Number = (event.dragInitiator as PieChart).selectedChartItem
.index;
(event.currentTarget as PieChart).dataProvider.addItem((event.
dragInitiator as PieChart).dataProvider.getItemAt(index));
(event.dragInitiator as PieChart).dataProvider.removeItemAt(index);
}
The object is first added to the dataProvider of the currentTarget of the dragEvent, that
is, the PieChart where the component is being dropped. The data (and corresponding
object) is then removed from the DragEvent.dragInitiator, and the PieChart that has
had data dragged from it.
]]>
</mx:Script>
<mx:PieChart dataProvider=\"{subColl}\" selectionMode=\"single\" dragEnabled=\"true\"
dropEnabled=\"true\" mouseMove=\"mouseMoveHandler(event)\" dragDrop=
\"dragDropHandler(event)\">
<mx:series>
<mx:PieSeries field=\"goals\" nameField=\"name\" labelField=\"name\"
labelPosition=\"callout\" selectable=\"true\"/>
</mx:series>
</mx:PieChart>
<mx:PieChart dataProvider=\"{masterArrColl}\" dragEnabled=\"true\" dropEnabled=\"true\"
selectionMode=\"single\" mouseMove=\"mouseMoveHandler(event)\" dragDrop=\"
dragDropHandler(event)\">
<mx:series>
16.10 Drag and Drop Items in a Chart | 479
<mx:PieSeries field=\"goals\" nameField=\"name\" labelField=\"name\"
labelPosition=\"callout\" selectable=\"true\"/>
</mx:series>
</mx:PieChart>
</mx:Application>
The selectable property of both PieSeries components must be set to true, as must the
dragEnabled and dropEnabled properties of both PieCharts. When a ChartItem is drag-
ged from the Chart, the dragProxy is rendered as a bitmap copy of the ChartItem being
dragged.
16.11 Create an Editable Line Chart
Problem
You need to update the values of one property in the data provider of one chart based
on changes to the other properties.
Solution
Create a Chart with multiple ChartSeries objects and set each changeable
ChartSeries to have the selectable property set to true. Then create drag-and-drop
event handlers that will perform any calculations that need to be made when a value is
changed.
Discussion
In the following example, a series of charts are set up to represent the profit relationship
between expenses and sales for a given date. The LineSeries objects that represent the
expenses and sales both have their selectable property set to true:
<mx:Application xmlns:mx=\"http://www.adobe.com/2006/mxml\">
<mx:Script>
<![CDATA[
import mx.charts.chartClasses.AxisLabelSet;
import mx.core.DragSource;
import mx.charts.series.LineSeries;
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.collections.ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: \"Jan\", Profit: 2000, Expenses: 1500, Sales: 3550},
{ Month: \"Feb\", Profit: 1000, Expenses: 200, Sales: 1200},
{ Month: \"Mar\", Profit: 1500, Expenses: 500, Sales: 2000},
{ Month: \"Apr\", Profit: 1800, Expenses: 1200, Sales: 3000},
{ Month: \"May\", Profit: 2400, Expenses: 575, Sales: 2975}]);
480 | Chapter 16: Charting
// Initializes the drag-and-drop operation.
private function mouseMoveHandler(event:MouseEvent):void {
event.preventDefault();
// Get the drag initiator component from the event object.
var dragInitiator:LineSeries = LineSeries(event.currentTarget);
// if a selectedItem isn't set, ignore the mouse event
if(dragInitiator.selectedItem == null) return;
// Create a DragSource object.
var ds:DragSource = new DragSource();
// Call the DragManager doDrag() method to start the drag.
DragManager.doDrag(dragInitiator, ds, event);
}
The mouseMoveHandler processes mouse movements for each of the selection-enabled
LineSeries objects. The dragging calls the DragManager.doDrag method, which has the
dragInitiator, in this case a LineSeries object, passed to the doDrag method.
private function setDragDropData(event:DragEvent):void {
var index:Number = (event.dragInitiator as LineChart).
selectedChartItem.index;
var newYVal:Number = (event.dragInitiator as LineChart).mouseY;
var selectedSeries:LineSeries = (event.dragInitiator as LineChart).
selectedChartItem.element as LineSeries;
var editedObj:Object = (event.dragInitiator as LineChart).dataProvider.
getItemAt(index);
var als:AxisLabelSet = linechart.verticalAxis.getLabelEstimate();
var maxValue:Number = als.labels[als.labels.length - 1].value;
The getLabelEstimate of the IAxis interface, which both the horizontal and vertical
axes of a chart implement, returns an AxisLabelSet object. The AxisLabelSet object
defines a label property of type array that contains all the labels that are used in the
particular axis. In this case, the last value is used to determine the maximum value of
the chart. Because this can change each time the user alters the values, it is important
to read this value each time a value is dropped to ensure that the correct maximum for
the chart is used to calculate the value that the user intended.
if(selectedSeries.yField == \"Expenses\")
{
var yPos:Number = ((linechart.height - newYVal) / linechart.height);
var newVal:Number = maxValue * yPos;
editedObj.Expenses = newVal;
}
else
{
var yPos:Number = ((linechart.height - newYVal) / linechart.height);
var newVal:Number = maxValue * yPos;
editedObj.Sales = newVal;
}
16.11 Create an Editable Line Chart | 481
editedObj.Profit = editedObj.Sales - editedObj.Expenses;
(event.dragInitiator as LineChart).clearSelection();
It is important to call the clearSelection method for the parent chart to ensure that
the chart selection does not interfere with the processing of mouse events in the chart.
The dataProvider for the LineChart is refreshed, forcing the component to redraw.
// force the chart to redraw - note if we weren't using a simple array collection
// the data object in the array could dispatch an event, forcing the
binding to update
(event.dragInitiator as LineChart).dataProvider = expensesAC;
}
]]>
</mx:Script>
<mx:Panel title=\"LineChart and AreaChart Controls Example\"
height=\"100%\" width=\"100%\" layout=\"horizontal\">
<mx:LineChart id=\"linechart\" height=\"100%\" width=\"100%\"
paddingLeft=\"5\" paddingRight=\"5\" dragDrop=\"setDragDropData(event)\"
showDataTips=\"true\" dataProvider=\"{expensesAC}\" selectionMode=\"single\"
dragEnabled=\"true\" dropEnabled=\"true\">
<mx:horizontalAxis>
<mx:CategoryAxis categoryField=\"Month\"/>
</mx:horizontalAxis>
The CircleItemRenderer used for each LineSeries is draggable if the selected property
is set to true. Because the LineSeries representing the Profit property should be cal-
culated by the component when the expenses or sales are altered, its selectable
property is set to false.
<mx:series>
<mx:LineSeries selectable=\"false\" id=\"profitSeries\" yField=\"Profit\"
form=\"curve\" displayName=\"Profit\" itemRenderer = \"mx.charts.renderers.CircleItem
Renderer\"/>
<mx:LineSeries mouseMove=\"mouseMoveHandler(event)\" yField=\"Expenses\"
form=\"curve\" displayName=\"Expenses\" selectable=\"true\" itemRenderer = \"mx.charts.
renderers.CircleItemRenderer\"/>
<mx:LineSeries mouseMove=\"mouseMoveHandler(event)\" yField=\"Sales\"
form=\"curve\" displayName=\"Sales\" selectable=\"true\" itemRenderer = \"mx.charts.
renderers.CircleItemRenderer\"/>
</mx:series>
</mx:LineChart>
<mx:Legend dataProvider=\"{linechart}\"/>
</mx:Panel>
</mx:Application>
482 | Chapter 16: Charting
0 comments
Post a comment