One common use of charts is to allow the user to drill
down into the data. This usually occurs when the user performs some
sort of event on the chart such as clicking on a wedge in a PieChart
control or clicking on a column in a ColumnChart control. Clicking
on a data item reveals a new chart that describes the make-up of
that data item.
For example, you might have a ColumnChart control that shows
the month-by-month production of widgets. To initially populate
this chart, you might make a database call (through a service or
some other adapter). If the user then clicks on the January column,
the application could display the number of widgets of each color
that were produced that month. To get the individual month’s widget
data, you typically make another database call and pass a parameter
to the listening service that describes the specific data you want.
You can then use the resulting data provider to render the new view.
Typically, when you drill down into chart data, you create new
charts in your application with ActionScript. When creating new
charts in ActionScript, you must be sure to create a series, add
it to the new chart’s series Array, and then call the addElement() method
(on Spark containers) or addChild() method (on
MX containers) to add the new chart to the display list. For more
information, see Creating charts in ActionScript.
One way to provide drill-down functionality is to make calls
that are external to the application to get the drill-down data.
You typically do this by using the chart’s itemClick event
listener, which gives you access to the HitData object. The HitData object
lets you examine what data was underneath the mouse when the event
was triggered. This capability lets you perform actions on specific
chart data. For more information, see Using the HitData object.
You can also use a simple Event object to get a reference to
the series that was clicked. The following example shows the net
worth of a fictional person. When you click on a column in the initial
view, the example drills down into a second view that shows the
change in value of a particular asset class over time.
The following example uses the Event object to get a reference
to the clicked ColumnSeries. It then drills down into the single
ColumnSeries by replacing the chart’s series Array with the single
ColumnSeries in the chart. When you click a column again, the chart
returns to its original configuration with all ColumnSeries.
<?xml version="1.0"?>
<!-- charts/SimpleDrillDown.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="initApp();srv.send();"
height="600">
<fx:Declarations>
<!-- View source of the following page to see the structure of the data that Flex uses in this example. -->
<mx:HTTPService id="srv" url="http://aspexamples.adobe.com/chart_examples/networth-xml.aspx"/>
<!-- To see data in an HTML table, go to http://aspexamples.adobe.com/chart_examples/networth.aspx -->
</fx:Declarations>
<fx:Script><![CDATA[
public var initSeriesArray:Array = new Array();
public var level:Number = 1;
public var newSeries:Array;
private function initApp():void {
// Get initial series Array -- to be reloaded when it returns
// from a drill down.
initSeriesArray = chart.series;
}
private function zoomIntoSeries(e:Event):void {
newSeries = new Array();
if (level == 1) {
newSeries.push(e.currentTarget);
level = 2;
} else {
newSeries = initSeriesArray;
p1.title = "Net Worth";
level = 1;
}
chart.series = newSeries;
}
]]></fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel id="p1" title="Net Worth">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:ColumnChart id="chart"
dataProvider="{srv.lastResult.data.result}"
type="stacked"
showDataTips="true">
<mx:series>
<mx:ColumnSeries id="s1"
displayName="Cash"
yField="cash"
xField="date"
click="zoomIntoSeries(event)"/>
<mx:ColumnSeries id="s2"
displayName="Stocks"
yField="stocks"
xField="date"
click="zoomIntoSeries(event)"/>
<mx:ColumnSeries id="s3"
displayName="Retirement"
yField="retirement"
xField="date"
click="zoomIntoSeries(event)"/>
<mx:ColumnSeries id="s4"
displayName="Home"
yField="home"
xField="date"
click="zoomIntoSeries(event)"/>
<mx:ColumnSeries id="s5"
displayName="Other"
yField="other"
xField="date"
click="zoomIntoSeries(event)"/>
</mx:series>
<mx:horizontalAxis >
<mx:DateTimeAxis title="Date" dataUnits="months"/>
</mx:horizontalAxis>
</mx:ColumnChart>
<mx:Legend dataProvider="{chart}"/>
</s:Panel>
</s:Application>
The executing SWF file for the previous example is shown below:
Another approach to drilling down into chart data is to use unused
data within the existing data provider. You can do this by changing
the properties of the series and axes when the chart is clicked.
The following example is similar to the previous example in that
it drills down into the assets of a fictional person’s net worth.
In this case, though, it shows the value of the asset classes for
the clicked-on month in the drill-down view rather than the change
over time of a particular asset class.
This example uses the HitData object’s item property
to access the values of the current data provider. By building an
Array of objects with the newly-discovered data, the chart is able
to drill down into the series without making calls to any external
services.
Drilling down into data is an ideal time to use effects such
as SeriesSlide. This example also defines seriesIn and seriesOut effects
to slide the columns in and out when the drilling down (and the
return from drilling down) occurs.
<?xml version="1.0"?>
<!-- charts/DrillDownWithEffects.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="srv.send();"
height="600">
<fx:Declarations>
<!-- View source of the following page to see the structure of the data that Flex uses in this example. -->
<mx:HTTPService id="srv" url="http://aspexamples.adobe.com/chart_examples/networth-xml.aspx" result="resultHandler()"/>
<!-- To see data in an HTML table, go to http://aspexamples.adobe.com/chart_examples/networth.aspx -->
<mx:SeriesSlide id="slideIn" duration="1000" direction="down"/>
<mx:SeriesSlide id="slideOut" duration="1000" direction="up"/>
</fx:Declarations>
<fx:Script><![CDATA[
import mx.collections.ArrayCollection;
import mx.charts.HitData;
import mx.charts.events.ChartItemEvent;
[Bindable]
public var drillDownDataSet:ArrayCollection;
[Bindable]
public var dp:ArrayCollection;
// level is a temporary variable used to determine when to drill down.
private var level:int = 1;
private function resultHandler():void {
dp = ArrayCollection(srv.lastResult.data.result);
}
private function zoomIntoSeries(e:ChartItemEvent):void {
if (level == 1) {
drillDownDataSet = new ArrayCollection(genData(e));
cs1.displayName = "Assets";
cs1.yField = "amount";
cs1.xField = "type";
ca1.categoryField = "type";
p1.title = "Asset breakdown for " + e.hitData.item.date;
dp = drillDownDataSet;
// Remove the Legend. It is not needed in this view because
// each asset class is its own column in the drill down.
p1.removeElement(myLegend);
level = 2;
} else {
cs1.displayName = "All Assets";
cs1.yField = "assets";
cs1.xField = "date";
ca1.categoryField = "date";
p1.title = "Net Worth";
// Add the Legend back to the Panel.
p1.addElement(myLegend);
// Reset chart to original data provider.
resultHandler();
level = 1;
}
}
// Build an ArrayCollection of objects to make up the new data set.
private function genData(e:ChartItemEvent):Array {
var result:Array = [];
trace("Cash: " + e.hitData.item.cash);
trace("Stocks: " + e.hitData.item.stocks);
trace("Retirement: " + e.hitData.item.retirement);
trace("Home: " + e.hitData.item.home);
trace("Other: " + e.hitData.item.other);
var o1:Object = {
type:"cash",
amount:e.hitData.item.cash
};
var o2:Object = {
type:"stocks",
amount:e.hitData.item.stocks
};
var o3:Object = {
type:"retirement",
amount:e.hitData.item.retirement
};
var o4:Object = {
type:"home",
amount:e.hitData.item.home
};
var o5:Object = {
type:"other",
amount:e.hitData.item.other
};
trace(o1.type + ":" + o1.amount);
result.push(o1);
result.push(o2);
result.push(o3);
result.push(o4);
result.push(o5);
return result;
}
]]></fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel id="p1" title="Net Worth">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:ColumnChart id="chart"
showDataTips="true"
itemClick="zoomIntoSeries(event)"
dataProvider="{dp}">
<mx:series>
<mx:ColumnSeries id="cs1"
displayName="All Assets"
yField="assets"
xField="date"
hideDataEffect="slideOut"
showDataEffect="slideIn"/>
</mx:series>
<mx:horizontalAxis>
<mx:CategoryAxis id="ca1" categoryField="date"/>
</mx:horizontalAxis>
</mx:ColumnChart>
<mx:Legend id="myLegend" dataProvider="{chart}"/>
</s:Panel>
</s:Application>
The executing SWF file for the previous example is shown below:
Another way to drill down into chart data is to use the selection
API. You can select a subset of data points on a chart to create
a new data provider. For more information, see Selecting chart items.