As part of interacting with charts, you can select data points (ChartItem objects), examine the underlying data, and then perform actions on those objects. A ChartItem class represents a single entry in the chart series' data provider. A series is made up of an Array of ChartItem objects.
To enable data point selection, you set the value of the selectionMode property on the chart. Possible values of this property are none, single, and multiple. Setting the selectionMode property to none prevents any data points in the chart from being selected. Setting selectionMode to single lets you select one data point at a time. Setting selectionMode to multiple lets you select one or more data points at a time. The default value is none.
You also toggle the series' selectability by setting the value of the selectable property. As a result, while you might set the selectionMode on the chart to multiple, you can make the data points in some series selectable and others not selectable within the same chart by using the series' selectable property.
You can programmatically select data points or the application user can interactively select data points in the following ways:
When understanding chart item selection, you should first understand the following terms:
The following example creates three different types of charts. You can select one or more data points in each chart using the mouse, keyboard, and region selection techniques. The example displays the data points in each series that are currently selected.
<?xml version="1.0" ?>
<!-- charts/SimpleSelection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private function handleChange(event:Event):void {
var allSeries:Array = event.currentTarget.series;
textArea1.text = "";
for (var i:int=0; i<allSeries.length; i++) {
textArea1.text += "\n" + allSeries[i].id +
" Selected Items: " + allSeries[i].selectedIndices;
}
}
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{ Expense:"Taxes", Amount:2000 },
{ Expense:"Rent", Amount:1000 },
{ Expense:"Food", Amount:200 } ]);
[Bindable]
private var medalsAC:ArrayCollection = new ArrayCollection( [
{ Country: "A", Gold: 35, Silver:39, Bronze: 29 },
{ Country: "B", Gold: 32, Silver:17, Bronze: 14 },
{ Country: "C", Gold: 27, Silver:27, Bronze: 38 },
{ Country: "D", Gold: 15, Silver:15, Bronze: 10 },
{ Country: "E", Gold: 15, Silver:10, Bronze: 10 } ]);
[Bindable]
private var profitsAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);
]]>
</mx:Script>
<mx:HBox>
<mx:Panel title="Bar Chart">
<mx:BarChart id="myBarChart"
height="225"
showDataTips="true"
dataProvider="{medalsAC}"
selectionMode="multiple"
change="handleChange(event)"
>
<mx:verticalAxis>
<mx:CategoryAxis categoryField="Country"/>
</mx:verticalAxis>
<mx:series>
<mx:BarSeries id="barSeries1"
yField="Country"
xField="Gold"
displayName="Gold"
selectable="true"
/>
<mx:BarSeries id="barSeries2"
yField="Country"
xField="Silver"
displayName="Silver"
selectable="true"
/>
<mx:BarSeries id="barSeries3"
yField="Country"
xField="Bronze"
displayName="Bronze"
selectable="true"
/>
</mx:series>
</mx:BarChart>
<mx:Legend dataProvider="{myBarChart}"/>
</mx:Panel>
<mx:Panel title="Pie Chart" >
<mx:PieChart id="myPieChart"
height="225"
dataProvider="{expenses}"
showDataTips="true"
selectionMode="multiple"
change="handleChange(event)"
>
<mx:series>
<mx:PieSeries
id="pieSeries1"
field="Amount"
nameField="Expense"
labelPosition="callout"
/>
</mx:series>
</mx:PieChart>
<mx:Legend dataProvider="{myPieChart}"/>
</mx:Panel>
<mx:Panel title="Plot Chart">
<mx:PlotChart id="myPlotChart"
height="225"
showDataTips="true"
dataProvider="{profitsAC}"
selectionMode="multiple"
change="handleChange(event)"
>
<mx:series>
<mx:PlotSeries id="plotSeries1"
xField="Expenses"
yField="Profit"
displayName="Expenses/Profit"
selectable="true"
/>
<mx:PlotSeries id="plotSeries2"
xField="Amount"
yField="Expenses"
displayName="Amount/Expenses"
selectable="true"
/>
<mx:PlotSeries id="plotSeries3"
xField="Profit"
yField="Amount"
displayName="Profit/Amount"
selectable="true"
/>
</mx:series>
</mx:PlotChart>
<mx:Legend dataProvider="{myPlotChart}"/>
</mx:Panel>
</mx:HBox>
<mx:HBox width="370" height="71">
<mx:Label text="Selection Changed Event:" />
<mx:TextArea id="textArea1" height="70" width="213"/>
</mx:HBox>
</mx:Application>
The executing SWF file for the previous example is shown below:
You can specify the colors that are used to indicate if an item is selected, disabled, or being rolled over. You do this by using the itemSelectionColor, itemDisabledColor, and itemRollOverColor style properties of the chart controls. The following example specifies different colors for these states for several chart types:
BarChart, PieChart, PlotChart {
itemSelectionColor: red;
itemDisabledColor: green;
itemRollOverColor: blue;
}
Users can select all data points in an area on a chart by drawing a rectangle (the region) on the chart. Users define a rectangular region by clicking and holding the mouse button while they move the mouse, drawing a rectangle on the chart. On the MOUSE_UP event, the items inside the rectangular region are selected. The starting point for a rectangular range must be over the chart. You cannot start the rectangle outside of the chart control's bounds.
To select data points with region selection, the value of the chart's selectionMode property must be multiple. If it is single or none, then you cannot draw the selection rectangle on the chart.
For most charts, as long as any point inside the rectangle touches a data point (for example, a column in a ColumnChart control), you select that data point. For BubbleChart and PieChart controls, an item is selected only if its center is inside the selection rectangle.
To select chart items, you can use the arrow keys, space bar, and enter key on your keyboard or the mouse pointer. If you want to select more than data point, the value of the chart's selectionMode property must be multiple.
You use the left and right arrows to move up and down the data in the series.
Click the left arrow to select the previous item and the right arrow to select the next item in the series. When you reach the last item in a series, you move to the first item in the next series.
Click the up and down arrow keys to move to the next or previous series on the chart.
Click the up arrow key to select the next series in the chart's series array. Click the down arrow key to select the previous series.
The index of the item in each series remains the same. If there is only one series in the chart, then click the up arrow key to select the first data point in the series; click the down arrow key to select the last data point in the series.
You can use the shift and control keys in conjunction with the other keys to select or deselect data points and change the caret in the selection.
Hold the shift key down while clicking the right arrow key to add the next data point to the selection until you reach the end of the series. Click the left arrow key to remove the last data point from the selection.
Hold the shift key down while clicking the up arrow key to select the first item in the next series. Click the down arrow key to select the last item in the previous series.
Hold the control key down while using the arrow keys to move the caret while not deselecting the anchor item. You can then select the new caret by pressing the space bar.
Click the space bar to toggle the selection of the caret item, if the control key is depressed. A deselected caret item appears highlighted, but the highlight color is not the same as the selected item color.
Page Up/Home and Page Down/End keys
Click the Page Up/Home and Page Down/End keys to move to the first and last items in the current series, respectively. Moving to an item makes that item the caret item, but does not select it. You can press the space bar to select it.
The default behavior of the mouse pointer is to select the data point under the mouse pointer when you click the mouse button and de-select all other data points.
If you click the mouse button and drag it over a chart, you create a rectangular region that defines a selection range. All data points inside that range are selected.
If you select a data point, then hold the shift key down and click on another data point, you select the first point, the target point, and all points that appear inside the rectangular range that you just created. If you select a data point, then hold the control key down and click another data point, you select both data points, but not the data points in between. You can add more individual data points by continuing to hold the control key down while you select another data point.
If you click anywhere on the chart that does not have a data point without any keys held down, then you clear the selection. Clicking outside of the chart control's boundary does not clear the selection.
You can use the chart selection APIs to programmatically select one or more data points in a chart control. These APIs consist of methods and properties of the ChartBase, ChartItem, and chart series objects.
Selections with multiple items include a caret and an anchor. You can access these items by using the caretItem and anchorItem properties of the chart control.
The series defines which ChartItem objects are selected. You can programmatically select items by setting the values of the following properties of the series:
The index properties refer to the index of the chart item in the series. This index is the same as the index in the data provider, assuming you did not sort or limit the series items.
Programmatically setting the values of these properties does not trigger a change event.
The following example increments and decrements the series' selectedIndex property to select each item, one after the other, in the series:
<?xml version="1.0" ?>
<!-- charts/SimplerCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.series.items.ColumnSeriesItem;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Expenses: 1500, Amount: 450, Profit: 2000 },
{ Month: "Feb", Expenses: 200, Amount: 600, Profit: 1000 },
{ Month: "Mar", Expenses: 500, Amount: 300, Profit: 1500 },
{ Month: "Apr", Expenses: 1200, Amount: 900, Profit: 1800 },
{ Month: "May", Expenses: 575, Amount: 500, Profit: 2400 } ]);
private function initApp():void {
// Select the first item on start up.
series1.selectedIndex = 0;
}
private function getNext(e:Event):void {
series1.selectedIndex += 1;
}
private function getPrev(e:Event):void {
series1.selectedIndex -= 1;
}
private function getFirst(e:Event):void {
series1.selectedIndex = 0;
}
private function getLast(e:Event):void {
series1.selectedIndex = series1.items.length - 1;
}
]]>
</mx:Script>
<mx:Panel height="100%" width="100%">
<mx:ColumnChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="single"
>
<mx:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
</mx:ColumnChart>
<mx:HBox>
<mx:Label id="label0" text="Value: "/>
<mx:Label id="label1"/>
</mx:HBox>
<mx:Legend dataProvider="{myChart}" width="200"/>
<mx:HBox>
<mx:Button label="|<" click="getFirst(event);" />
<mx:Button label="<" click="getPrev(event);" />
<mx:Button label=">" click="getNext(event);" />
<mx:Button label=">|" click="getLast(event);" />
</mx:HBox>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
To cycle through ChartItem objects in a series, you can use methods such as getNextItem() and getPreviousItem(). For more information, see Methods and properties of the ChartBase class.
The selectedIndices property lets you select any number of ChartItems in a chart control. The following example uses the selectedIndices property to select all items in all series when the user presses the Ctrl+a keys on the keyboard:
<?xml version="1.0" ?>
<!-- charts/SelectAllItems.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import flash.events.KeyboardEvent;
import mx.charts.events.ChartItemEvent;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);
private function initApp():void {
application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
private function keyHandler(event:KeyboardEvent):void {
var ctrlPressed:Boolean = event.ctrlKey;
// If the user presses Ctrl + A, select all chart items.
if (ctrlPressed) {
var curKeyCode:int = event.keyCode;
if (curKeyCode == 65) { // 65 is the keycode value for 'a'
selectItems();
}
}
}
private function selectItems():void {
// Create an array of all the chart's series.
var allSeries:Array = myChart.series;
// Iterate over each series.
for (var i:int=0; i<allSeries.length; i++) {
var selectedData:Array = [];
// Iterate over the number of items in the series.
for (var j:int=0; j<expensesAC.length; j++) {
selectedData.push(j);
}
// Use the series' selectedIndices property to select all the
// chart items.
allSeries[i].selectedIndices = selectedData;
}
}
]]>
</mx:Script>
<mx:Panel height="100%" width="100%">
<mx:PlotChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
>
<mx:series>
<mx:PlotSeries id="series1"
xField="Expenses"
yField="Profit"
displayName="Expenses/Profit"
selectable="true"
/>
<mx:PlotSeries id="series2"
xField="Amount"
yField="Expenses"
displayName="Amount/Expenses"
selectable="true"
/>
<mx:PlotSeries id="series3"
xField="Profit"
yField="Amount"
displayName="Profit/Amount"
selectable="true"
/>
</mx:series>
</mx:PlotChart>
<mx:Legend dataProvider="{myChart}" width="200"/>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
The following example is similar to the previous example, except that it lets you set a threshold value in the TextInput control. The chart only selects chart items whose values are greater than that threshold.
<?xml version="1.0" ?>
<!-- charts/ConditionallySelectChartItems.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);
private function selectItems(event:Event):void {
// Create an array of all the chart's series.
var allSeries:Array = myChart.series;
// Iterate over each series.
for (var i:int=0; i<allSeries.length; i++) {
var selectedData:Array = [];
// Iterate over each item in the series.
for (var j:int=0; j<expensesAC.length; j++) {
if (expensesAC.getItemAt(j).Profit >=
Number(threshold.text)) {
selectedData.push(j);
}
}
// Use the series' selectedIndices property to select all the
// chart items that met the criteria.
allSeries[i].selectedIndices = selectedData;
}
}
]]>
</mx:Script>
<mx:Panel height="100%" width="100%">
<mx:PlotChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
>
<mx:series>
<mx:PlotSeries id="series1"
xField="Expenses"
yField="Profit"
displayName="Expenses/Profit"
selectable="true"
/>
<mx:PlotSeries id="series2"
xField="Amount"
yField="Expenses"
displayName="Amount/Expenses"
selectable="true"
/>
<mx:PlotSeries id="series3"
xField="Profit"
yField="Amount"
displayName="Profit/Amount"
selectable="true"
/>
</mx:series>
</mx:PlotChart>
<mx:Legend dataProvider="{myChart}" width="200"/>
<mx:TextInput id="threshold" text="1000"/>
<mx:Button label="Select Items" click="selectItems(event)"/>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
Methods and properties of the ChartBase class
The ChartBase class is the parent class of all chart controls. You can programmatically access ChartItem objects by using the following methods of this class:
These methods return a ChartItem object, whether it is selected or not. Which object is returned depends on which one is currently selected, and which direction constant (ChartBase.HORIZONTAL or ChartBase.VERTICAL) you pass to the method.
The following example uses these methods to cycle through the data points in a ColumnChart control. It sets the value of the series' selectedItem property to identify the new ChartItem as the currently selected item.
<?xml version="1.0" ?>
<!-- charts/SimpleCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.series.items.ColumnSeriesItem;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Expenses: 1500, Amount: 450, Profit: 2000 },
{ Month: "Feb", Expenses: 200, Amount: 600, Profit: 1000 },
{ Month: "Mar", Expenses: 500, Amount: 300, Profit: 1500 },
{ Month: "Apr", Expenses: 1200, Amount: 900, Profit: 1800 },
{ Month: "May", Expenses: 575, Amount: 500, Profit: 2400 } ]);
private function initApp():void {
// Select the first item on start up.
series1.selectedIndex = 0;
}
private function getNext(e:Event, dir:*):void {
var curItem:ChartItem = series1.selectedItem;
var newItem:ChartItem = myChart.getNextItem(dir);
applyNewItem(newItem);
}
private function getPrev(e:Event, dir:*):void {
var curItem:ChartItem = series1.selectedItem;
var newItem:ChartItem = myChart.getPreviousItem(dir);
applyNewItem(newItem);
}
private function getFirst(e:Event, dir:*):void {
var newItem:ChartItem = myChart.getFirstItem(dir);
applyNewItem(newItem);
}
private function getLast(e:Event, dir:*):void {
var newItem:ChartItem = myChart.getLastItem(dir);
applyNewItem(newItem);
}
private function applyNewItem(n:ChartItem):void {
series1.selectedItem = n;
}
]]>
</mx:Script>
<mx:Panel height="100%" width="100%">
<mx:ColumnChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="single"
>
<mx:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
</mx:ColumnChart>
<mx:HBox>
<mx:Label id="label0" text="Value: "/>
<mx:Label id="label1"/>
</mx:HBox>
<mx:Legend dataProvider="{myChart}" width="200"/>
<mx:HBox>
<mx:Button label="|<"
click="getFirst(event, ChartBase.HORIZONTAL);" />
<mx:Button label="<"
click="getPrev(event, ChartBase.HORIZONTAL);" />
<mx:Button label=">"
click="getNext(event, ChartBase.HORIZONTAL);" />
<mx:Button label=">|"
click="getLast(event, ChartBase.HORIZONTAL);" />
</mx:HBox>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
These item getter methods do not have associated setters. You cannot set the selected ChartItem objects in the same manner. Instead, you use the properties of the series, as described in Properties of the series.
Calling the getNextItem() and getPreviousItem() methods provides more control over the item selection than simply incrementing and decrementing the series' selectedIndex property as shown in Properties of the series. With these methods, you can choose the direction in which you select the next or previous item, and then decide whether to make the item appear selected.
The item getter methods also account for when you get to the end of the series, for example. If no ChartItems are currently selected, then the getNextItem() method gets the first one in the series. If you are at the beginning of the series, the getPreviousItem() gets the last item in the series.
The ChartBase class defines two additional properties, selectedChartItem and selectedChartItems, that return an item or Array of items that are selected. You cannot set the values of these properties to select chart items. These properties are read-only. They are useful if your chart has multiple series and you want to know which items across the series are selected without iterating over all the series.
You can set the value of the currentState property of a ChartItem object to make it appear selected or deselected, or make it appear in some other state. The currentState property can be set to none, rollOver, selected, disabled, focusedSelected, and focused.
Setting the state of the item does not add it to the selectedItems array. It only changes the appearance of the chart item. Setting the value of this property also does not trigger a change event.
You can use the getItemsInRegion() method to define a rectangular area and select those chart items that are within that region. The getItemsInRegion() method takes an instance of the Rectangle class as its only argument. This rectangle defines an area on the stage, in global coordinates.
Getting an array of ChartItem objects with the getItemsInRegion() method does not trigger a change event. The state of the items does not change.
The following example lets you specify the x, y, height, and width properties of a rectangular range. It then calls the getItemsInRegion() method and passes those values to define the range. All chart items that fall within this invisible rectangle are selected and their values are displayed in the TextArea control.
<?xml version="1.0" ?>
<!-- charts/GetItemsInRangeExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.series.items.ColumnSeriesItem;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Expenses: 1500, Amount: 450, Profit: 2000 },
{ Month: "Feb", Expenses: 200, Amount: 600, Profit: 1000 },
{ Month: "Mar", Expenses: 500, Amount: 300, Profit: 1500 },
{ Month: "Apr", Expenses: 1200, Amount: 900, Profit: 1800 },
{ Month: "May", Expenses: 575, Amount: 500, Profit: 2400 } ]);
private function getItems(e:Event):void {
var x:Number = Number(ti1.text);
var y:Number = Number(ti2.text);
var h:Number = Number(ti3.text);
var w:Number = Number(ti4.text);
var r:Rectangle = new Rectangle(x, y, h, w);
// Get an Array of ChartItems in the defined area.
var a:Array = myChart.getItemsInRegion(r);
for (var i:int = 0; i<a.length; i++) {
var myChartItem:ColumnSeriesItem = ColumnSeriesItem(a[i]);
// Make items appear selected.
myChartItem.currentState = "selected";
// Show values of the items that appear selected.
ta1.text += myChartItem.xValue.toString() +
"=" + myChartItem.yValue.toString() + "\n";
}
}
]]>
</mx:Script>
<mx:Panel id="p1" height="100%" width="100%">
<mx:ColumnChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
>
<mx:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
<mx:ColumnSeries id="series2"
yField="Amount"
displayName="Amount"
selectable="true"
/>
<mx:ColumnSeries id="series3"
yField="Profit"
displayName="Profit"
selectable="true"
/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
</mx:ColumnChart>
<mx:Legend dataProvider="{myChart}" width="200"/>
<mx:HBox>
<mx:Form>
<mx:FormItem label="x">
<mx:TextInput id="ti1" text="0"/>
</mx:FormItem>
<mx:FormItem label="y">
<mx:TextInput id="ti2" text="0"/>
</mx:FormItem>
</mx:Form>
<mx:Form>
<mx:FormItem label="Height">
<mx:TextInput id="ti3" text="0"/>
</mx:FormItem>
<mx:FormItem label="Width">
<mx:TextInput id="ti4" text="0"/>
</mx:FormItem>
</mx:Form>
</mx:HBox>
<mx:Button label="Get Items" click="getItems(event)" />
<mx:TextArea id="ta1" height="100" width="300"/>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
To work with the data of a ChartItem, you typically cast it to its specific series type. For example, in a ColumnChart control, the ChartItem objects are of type ColumnSeriesItem. Doing this lets you access series-specific properties such as the yValue, xValue, and index of the ChartItem. You can also then access the data provider's object by using the item property. Finally, you can access the properties of the series by casting the element property to a series object.
Assuming that a[i] is a reference to a ChartItem object from an Array, use the following syntax.
Access the properties of the series item
var csi:ColumnSeriesItem = ColumnSeriesItem(a[i]); trace(csi.yValue);
var csi:ColumnSeriesItem = ColumnSeriesItem(a[i]); trace(csi.item.Profit);
var csi:ColumnSeriesItem = ColumnSeriesItem(a[i]); var cs:ColumnSeries = ColumnSeries(csi.element); trace(cs.displayName);
When a user selects a chart item using mouse, keyboard or region selection, the chart's change event is dispatched. When the following properties are updated through user interaction, a change event is dispatched:
The change event does not contain references to the HitData or HitSet of the selected chart items. To access that information, you can use the chart's selectedChartItem and selectedChartItems properties.
When you select an item programmatically, no change event is dispatched. When you change the selectedState property of a chart item, no change event is dispatched.
You can clear all selected data points by using the chart control's clearSelection() method. The following example clears all selected data points when the user presses the ESC key:
<?xml version="1.0" ?>
<!-- charts/ClearItemSelection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import flash.events.KeyboardEvent;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);
private function initApp():void {
application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
// Clears all chart items selected when the user presses the ESC key.
private function keyHandler(event:KeyboardEvent):void {
var curKeyCode:int = event.keyCode;
if (curKeyCode == 27) { // 27 is the keycode value for ESC
myChart.clearSelection();
}
}
]]>
</mx:Script>
<mx:Panel height="100%" width="100%">
<mx:PlotChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
>
<mx:series>
<mx:PlotSeries id="series1"
xField="Expenses"
yField="Profit"
displayName="Expenses/Profit"
selectable="true"
/>
<mx:PlotSeries id="series2"
xField="Amount"
yField="Expenses"
displayName="Amount/Expenses"
selectable="true"
/>
<mx:PlotSeries id="series3"
xField="Profit"
yField="Amount"
displayName="Profit/Amount"
selectable="true"
/>
</mx:series>
</mx:PlotChart>
<mx:Legend dataProvider="{myChart}" width="200"/>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
In addition to clearing item selections programmatically, users can use the mouse or keyboard to clear items. If a user clicks anywhere on the chart control's background, and not over a data point, they clear all selections. If a user uses the up and down arrow keys to select a data point, they clear the existing data points. For more information, see Keyboard and mouse selection.
You can use the selection API to get some or all of the ChartItem objects of one chart, and then create a new chart with them. To do this, you create a new data provider for the new chart. To do this, you can call the ArrayCollection's getItemAt() method on the original chart's data provider and pass to it the original series' selected indices. This method then returns an object whose values you then add to an object in the new data provider.
The selectedIndex and selectedIndices properties of a chart's series represent the position of the chart item in the series. This position is also equivalent to the position of the chart item's underlying data object in the data provider.
The following example creates a PieChart control from the selected columns in the ColumnChart control. The PieChart control also allows selection; you can explode a piece by selecting it.
<?xml version="1.0" ?>
<!-- charts/MakeChartFromSelection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.series.items.ColumnSeriesItem;
import mx.charts.PieChart;
import mx.charts.series.PieSeries;
import mx.charts.events.ChartItemEvent;
import mx.charts.Legend;
[Bindable]
public var newDataProviderAC:ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection([
{ Month: "Jan", Expenses: 1500 },
{ Month: "Feb", Expenses: 200 },
{ Month: "Mar", Expenses: 500 },
{ Month: "Apr", Expenses: 1200 },
{ Month: "May", Expenses: 575 } ]);
private function initApp():void {
myColumnChart.addEventListener(ChartItemEvent.CHANGE, createNewChart);
setupPieChart();
}
private function getNewDataProvider():ArrayCollection {
newDataProviderAC = new ArrayCollection();
for (var i:int=0; i<series1.selectedItems.length; i++) {
var o:Object = new Object();
o.Month = expensesAC.getItemAt(series1.selectedIndices[i]).Month;
o.Expenses = expensesAC.getItemAt(series1.selectedIndices[i]).Expenses;
newDataProviderAC.addItem(o);
}
return newDataProviderAC;
}
private var newChart:PieChart;
private var newSeries:PieSeries;
[Bindable]
private var explodedPiece:Array;
private function explodePiece(e:Event):void {
explodedPiece = new Array();
explodedPiece[newSeries.selectedIndex] = .2;
newSeries.perWedgeExplodeRadius = explodedPiece;
}
private function setupPieChart():void {
newChart = new PieChart();
newChart.showDataTips = true;
newChart.selectionMode = "single";
newSeries = new PieSeries();
newSeries.field = "Expenses";
newSeries.nameField = "Month";
newSeries.setStyle("labelPosition", "callout");
newSeries.setStyle("showDataEffect", "interpol");
var newSeriesArray:Array = new Array();
newSeriesArray.push(newSeries);
newChart.series = newSeriesArray;
newChart.addEventListener(ChartItemEvent.CHANGE, explodePiece);
// Create a legend for the new chart.
var newLegend:Legend = new Legend();
newLegend.dataProvider = newChart;
p1.addChild(newChart);
p1.addChild(newLegend);
}
private function createNewChart(e:Event):void {
newChart.dataProvider = getNewDataProvider();
}
]]>
</mx:Script>
<mx:SeriesInterpolate id="interpol"
duration="1000"
elementOffset="0"
minimumElementDuration="200"
/>
<mx:Panel id="p1">
<mx:ColumnChart id="myColumnChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
>
<mx:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
</mx:ColumnChart>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
As an extension of the selection API, you can drag and drop chart items from one chart to another (or from a chart to some other object altogether).
To use drag and drop operations in your chart controls:
The following example lets you drag chart items from the ColumnChart control to the PieChart control. When the application starts, there is no PieChart control, but it becomes visible when the first chart item is dragged onto it. This example also examines the dragged chart items to ensure that they are not added more than once to the target chart. It does this by using the target data provider's contains() method.
<?xml version="1.0" ?>
<!-- charts/MakeChartFromDragDrop.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.PieChart;
import mx.charts.series.PieSeries;
import mx.charts.events.ChartItemEvent;
import mx.events.DragEvent;
import mx.controls.List;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.charts.Legend;
[Bindable]
public var newDataProviderAC:ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection([
{ Month: "Jan", Expenses: 1500 },
{ Month: "Feb", Expenses: 200 },
{ Month: "Mar", Expenses: 500 },
{ Month: "Apr", Expenses: 1200 },
{ Month: "May", Expenses: 575 } ]);
private function initApp():void {
setupPieChart();
}
private var newChart:PieChart;
private var newSeries:PieSeries;
[Bindable]
private var explodedPiece:Array;
private function explodePiece(e:Event):void {
explodedPiece = new Array();
explodedPiece[newSeries.selectedIndex] = .2;
newSeries.perWedgeExplodeRadius = explodedPiece;
}
private function setupPieChart():void {
newChart = new PieChart();
newChart.showDataTips = true;
newChart.selectionMode = "multiple";
newChart.dropEnabled= true;
newChart.dragEnabled= false;
newChart.height = 350;
newChart.width = 350;
newChart.addEventListener("dragEnter", doDragEnter);
newChart.addEventListener("dragDrop", doDragDrop);
newChart.dataProvider = newDataProviderAC;
newSeries = new PieSeries();
newSeries.field = "Expenses";
newSeries.nameField = "Month";
newSeries.setStyle("labelPosition", "callout");
newSeries.setStyle("showDataEffect", "interpol");
var newSeriesArray:Array = new Array();
newSeriesArray.push(newSeries);
newChart.series = newSeriesArray;
newChart.addEventListener(ChartItemEvent.CHANGE, explodePiece);
// Create a legend for the new chart.
var newLegend:Legend = new Legend();
newLegend.dataProvider = newChart;
p2.addChild(newChart);
p2.addChild(newLegend);
}
private function doDragEnter(event:DragEvent):void {
// Get a reference to the target chart.
var dragTarget:ChartBase = ChartBase(event.currentTarget);
// Register the target chart with the DragManager.
DragManager.acceptDragDrop(dragTarget);
}
private function doDragDrop(event:DragEvent):void {
// Get a reference to the target chart.
var dropTarget:ChartBase=ChartBase(event.currentTarget);
// Get the dragged items from the drag initiator. When getting
// items from chart controls, you must use the 'chartitems'
// format.
var items:Array = event.dragSource.dataForFormat("chartitems")
as Array;
// Trace status messages.
trace("length: " + String(items.length));
trace("format: " + String(event.dragSource.formats[0]));
// Add each item to the drop target's data provider.
for(var i:uint=0; i < items.length; i++) {
// If the target data provider already contains the
// item, then do nothing.
if (dropTarget.dataProvider.contains(items[i].item)) {
// If the target data provider does NOT already
// contain the item, then add it.
} else {
dropTarget.dataProvider.addItem(items[i].item);
}
}
}
]]>
</mx:Script>
<mx:SeriesInterpolate id="interpol"
duration="1000"
elementOffset="0"
minimumElementDuration="200"
/>
<mx:Panel id="p1" title="Source Chart" height="250" width="400">
<mx:ColumnChart id="myColumnChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
dragEnabled="true"
dropEnabled="false"
>
<mx:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
</mx:ColumnChart>
</mx:Panel>
<!-- This will be the parent of the soon-to-be created chart. -->
<mx:Panel id="p2" title="Target Chart" height="400" width="400">
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
Chart controls also support the standard drag and drop methods of List-based controls such as hideDropFeedback() and showDropFeedback(). These methods display indicators under the mouse pointer to indicate whether drag and drop operations are allowed and where the items will be dropped.
For more information about drag and drop operations, see Using Drag and Drop.
Dropping ChartItem objects onto components
The target of a drag and drop operation from a chart control does not need to be another chart control. Instead, you can drag an object onto any Flex component using simple drag and drop rules. The following example lets you drag a column from the chart onto the TextArea. The TextArea then extracts data from the dropped item and displays that information in text.
<?xml version="1.0" ?>
<!-- charts/DragDropToComponent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.DragEvent;
import mx.controls.List;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.events.ChartItemEvent;
import mx.charts.series.items.ColumnSeriesItem;
[Bindable]
private var clothing_sales:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Pants: 35, Shirts:39, Fedoras: 29 },
{ Month: "Feb", Pants: 32, Shirts:17, Fedoras: 14 },
{ Month: "Mar", Pants: 27, Shirts:27, Fedoras: 38 } ]);
private function doDragEnter(event:DragEvent):void {
var dragTarget:TextArea = TextArea(event.currentTarget);
DragManager.acceptDragDrop(dragTarget);
}
private function doDragDrop(event:DragEvent):void {
var dropTarget:TextArea = TextArea(event.currentTarget);
var curItem:ColumnSeriesItem =
ColumnSeriesItem(event.dragSource.dataForFormat("chartitems")[0]);
var curSeries:ColumnSeries = ColumnSeries(curItem.element);
var clothingType:String = curSeries.displayName;
var numSold:String = curItem.yValue.toString();
var monthSold:String = curItem.item.Month;
ta1.text = "You sold " + numSold + " " +
clothingType + " in " + monthSold + ".";
}
]]>
</mx:Script>
<mx:Panel title="Rearrange Items in ColumnChart">
<mx:ColumnChart id="myChart"
height="225"
showDataTips="true"
dataProvider="{clothing_sales}"
selectionMode="single"
dragEnabled="true"
>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSeries id="columnSeries1"
xField="Month"
yField="Pants"
displayName="Pants"
selectable="true"
/>
<mx:ColumnSeries id="columnSeries2"
xField="Month"
yField="Shirts"
displayName="Shirts"
selectable="true"
/>
<mx:ColumnSeries id="columnSeries3"
xField="Month"
yField="Fedoras"
displayName="Fedoras"
selectable="true"
/>
</mx:series>
</mx:ColumnChart>
<mx:HBox>
<mx:Legend dataProvider="{myChart}"/>
<mx:TextArea id="ta1"
height="75"
width="200"
dragEnter="doDragEnter(event)"
dragDrop="doDragDrop(event)"
/>
</mx:HBox>
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below:
When you drag a chart item off of a source chart, an outline of the underlyig chart item appears as the drag image. For example, if you drag a column from a ColumnChart control, a column appears under the mouse pointer to represent the item that is being dragged.
You can customize the image that is displayed during a drag operation by overriding the default defintion of the dragImage property in a custom chart class. You do this by embedding your new image (or defining it in ActionScript), overriding the dragImage() getter method, and returning the new image.
The default location, in coordinates, of the drag image is 0,0 unless you override the DragManager's doDrag() method. You can also set the starting location of the drag proxy image by using the x and y coordinates of the image proxy in the dragImage() getter.
The following example custom chart class embeds an image and returns it in the dragImage() getter method. This example also positions the drag image proxy so that the mouse pointer is near its lower right corner.
// charts/MyColumnChart.as
package {
import mx.charts.ColumnChart;
import mx.core.IUIComponent;
import mx.controls.Image;
public class MyColumnChart extends ColumnChart {
[Embed(source="../../images/charting/dollarSign.png")]
public var dollarSign:Class;
public function MyColumnChart() {
super();
}
override protected function get dragImage():IUIComponent {
var imageProxy:Image = new Image();
imageProxy.source = dollarSign;
var imageHeight:Number = 50;
var imageWidth:Number = 32;
imageProxy.height = imageHeight;
imageProxy.width = imageWidth;
// Position the image proxy above and to the left of
// the mouse pointer.
imageProxy.x = this.mouseX - imageWidth;
imageProxy.y = this.mouseY - imageHeight;
return imageProxy;
}
}
}
The following example uses the MyColumnChart custom chart class to define its custom drag image:
<?xml version="1.0" ?>
<!-- charts/DragDropCustomDragImage.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()" xmlns:local="*">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.chartClasses.ChartBase;
import mx.charts.ChartItem;
import mx.charts.PieChart;
import mx.charts.series.PieSeries;
import mx.charts.events.ChartItemEvent;
import mx.events.DragEvent;
import mx.controls.List;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.controls.Image;
import flash.events.MouseEvent;
import mx.charts.Legend;
[Bindable]
public var newDataProviderAC:ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection([
{ Month: "Jan", Expenses: 1500 },
{ Month: "Feb", Expenses: 200 },
{ Month: "Mar", Expenses: 500 },
{ Month: "Apr", Expenses: 1200 },
{ Month: "May", Expenses: 575 } ]);
private function initApp():void {
setupPieChart();
}
private var newChart:PieChart;
private var newSeries:PieSeries;
[Bindable]
private var explodedPiece:Array;
private function explodePiece(e:Event):void {
explodedPiece = new Array();
explodedPiece[newSeries.selectedIndex] = .2;
newSeries.perWedgeExplodeRadius = explodedPiece;
}
private function setupPieChart():void {
newChart = new PieChart();
newChart.showDataTips = true;
newChart.selectionMode = "multiple";
newChart.dropEnabled= true;
newChart.dragEnabled= false;
newChart.height = 350;
newChart.width = 350;
newChart.addEventListener("dragEnter", doDragEnter);
newChart.addEventListener("dragDrop", doDragDrop);
newChart.dataProvider = newDataProviderAC;
newSeries = new PieSeries();
newSeries.field = "Expenses";
newSeries.nameField = "Month";
newSeries.setStyle("labelPosition", "callout");
newSeries.setStyle("showDataEffect", "interpol");
var newSeriesArray:Array = new Array();
newSeriesArray.push(newSeries);
newChart.series = newSeriesArray;
newChart.addEventListener(ChartItemEvent.CHANGE, explodePiece);
// Create a legend for the new chart.
var newLegend:Legend = new Legend();
newLegend.dataProvider = newChart;
p2.addChild(newChart);
p2.addChild(newLegend);
}
private function doDragEnter(event:DragEvent):void {
var dragTarget:ChartBase = ChartBase(event.currentTarget);
DragManager.acceptDragDrop(dragTarget);
}
private function doDragDrop(event:DragEvent):void {
var dropTarget:ChartBase=ChartBase(event.currentTarget);
var items:Array = event.dragSource.dataForFormat("chartitems") as Array;
for(var i:uint=0; i < items.length; i++) {
if (dropTarget.dataProvider.contains(items[i].item)) {
} else {
dropTarget.dataProvider.addItem(items[i].item);
}
}
}
]]>
</mx:Script>
<mx:SeriesInterpolate id="interpol"
duration="1000"
elementOffset="0"
minimumElementDuration="200"
/>
<mx:Panel id="p1" title="Source Chart" height="250" width="400">
<local:MyColumnChart id="myChart"
height="207"
width="350"
showDataTips="true"
dataProvider="{expensesAC}"
selectionMode="multiple"
dragEnabled="true"
dropEnabled="false"
>
<local:series>
<mx:ColumnSeries id="series1"
yField="Expenses"
displayName="Expenses"
selectable="true"
/>
</local:series>
<local:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</local:horizontalAxis>
</local:MyColumnChart>
</mx:Panel>
<mx:Panel id="p2" title="Target Chart" height="400" width="400">
</mx:Panel>
</mx:Application>
The executing SWF file for the previous example is shown below: