Sometimes a DataGrid control just isn't enough. In the rich world of Macromedia Flex applications, developers quickly want to leverage the capabilities of the Macromedia Flash platform to augment those rows and rows of dry numbers with beautiful, easy-to-understand data visualizations. With the release of Flex 1.5, Macromedia gives you a new set of highly customizable charting components you can use to win friends, impress your coworkers, and build the chart of your dreams.
This article introduces you to the new charting platform in Flex 1.5. I will guide you through the process of building a highly stylized, interactive drill-down chart for the fictitious Zinger Corporation. By the time you're through, you'll know how to build a chart that looks like Figure 1.

Figure 1. This tutorial shows you how to build this chart
You start by building a simple column chart, plotting the units sold for each of Zinger Corporation's product lines for each month of 2003. After the basic chart is constructed, you learn how to customize its appearance through advanced styling, as well as add interactivity and drill-down capabilities. Finally, you learn how to go beyond the built-in chart types to create a custom charting solution of your own.
To complete this tutorial you will need to install the following software and files:
A text editor or Macromedia Flex Builder
Basic experience with the Flex development model and application framework. A passing familiarity with charting concepts would be helpful, but is not required.
In your own applications you can use charts to display data you've loaded from one of the Flex network service components: WebService, HTTPService, or RemoteObject. For this tutorial, start your application by including an ActionScript file that will generate some dummy data:
At the beginning of the file, insert a basic application skeleton with a reference to the ActionScript file that is part of this tutorial's sample files:
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" initialize="initDummyData();" width="100%" height="100%">
<mx:Script source="zingerChartFunctions.as" />
<mx:Panel title="sample chart" width="100%" height="100%">
</mx:Panel>
</mx:Application>
Note: You can find the ActionScript file in the sample flex_charting_tutorials.zip file linked to in the "Requirements" section at the beginning of this article.
Add a simple ColumnChart control inside the panel and connect it to a
simple dataProvider object. The chart dataProvider property
should be the same format as that of the DataGrid control: an Array object
or some other object implementing the simple dataProvider API:
<mx:ColumnChart dataProvider="{zingerManufacturingData}" width="100%" height="100%" >
</mx:ColumnChart>
Note: zingerManufacturingData is
defined in zingerChartFunctions.as.
Save your application and load it in the browser. Your chart should look similar to Figure 2.

Figure 2. This is an empty, unstyled column chart
That's a good start but it doesn't exactly look like a column chart yet. Unlike the DataGrid control, the charting components make no assumptions about which fields of the dataProvider object to render. You'll add the columns in a moment; for now, let's focus on getting those axes in shape.
Although chart types differ in how they display data, fundamentally they are all about mapping (typically two dimensions of) data to a coordinate on the screen. You specify how a particular chart performs that mapping by specifying its axes.
For example, consider the typical column chart. In most column charts, you see a series of category labels along the horizontal axis (for example, cities, products, demographic groups, and so on) and a numeric range (for example, 0 to 100, 1000 to 5000, and so on) along the vertical axis. The chart maps the position of the column along the horizontal axis based on what category it represents and the height of the bar along the vertical axis based on the numeric value it represents.
In Flex, you dictate how the chart should map values along each axis by specifying an axis type and value.
To map the column's position by category, place a CategoryAxis object in the
chart's horizontalAxis property. Use a CategoryAxis object when
you want to map a series of discrete categories evenly along the axis onscreen.
The CategoryAxis object draws the categories from its own dataProvider property.
In this tutorial, you use the same dataProvider property to generate
the category labels and specify which field of the dataProvider property's
content it should draw from by setting the categoryField property.
Add a CategoryAxis object to the horizontalAxis property
inside the ColumnChart tag:
<mx:ColumnChart ...>
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{zingerManufacturingData}" categoryField="Month" />
</mx:horizontalAxis>
</mx:ColumnChart>
Note: As with other Flex controls, the categoryField property
is optional. You can assign an array of strings to the CategoryAxis object's dataProvider property
instead and leave categoryField blank.
Similarly, to map the height of each column to a numeric value in the dataProvider property,
specify a LinearAxis object in the chart's verticalAxis property.
You use a LinearAxis object when you want to map numeric values within
a specific range. You can either explicitly specify the minimum and maximum
values of the range or let the LinearAxis object determine them automatically
from the data being rendered in the chart.
Add a LinearAxis object to the verticalAxis property inside
the ColumnChart tag:
<mx:ColumnChart ...>
...
<mx:verticalAxis>
<mx:LinearAxis />
</mx:verticalAxis>
</mx:ColumnChart>
Note: The vertical and horizontal axis of all the standard chart types (except for the pie chart) default to LinearAxis objects. You don't have to declare them in your chart if you have no additional properties to specify.
Save your application and load it in the browser. Your chart should appear as shown in Figure 3.

Figure 3. This is your column chart with a horizontal category axis
Now your axes are all set to map the chart data properly. Next let's add a couple of series objects to specify which of the dataProvider fields to display.
A chart's relationship to its series is similar to a DataGrid control's relationship
to its columns: just as the DataGridColumn control indicates which fields of
the dataProvider property the grid should display, a series object
indicates which fields of the dataProvider property to render
as columns, lines, plots, and so on. Unlike the DataGrid control, the series
objects in a chart are not optional; with no series specified, a chart will
render no data.
Although DataGridColumn controls use only one field to render data, most series objects can render multiple pieces of data. A PlotSeries class, for example, uses one property of the dataProvider object to determine its horizontal position and another to determine its vertical position. The ColumnSeries class can use one field to determine its height, one field to determine its category (or horizontal position), and one field to determine the base of the column—where the bottom of the column should lie along the vertical axis:
Add an array of two ColumnSeries objects inside the ColumnChart tag's series property:
<mx:ColumnChart ...>
...
<mx:series>
<mx:Array>
<mx:ColumnSeries yField="Widgets" />
<mx:ColumnSeries yField="Blinkies" />
</mx:Array>
</mx:series>
</mx:ColumnChart>
Note: Many field properties on the various series types
are optional. For example, a ColumnSeries object with no xField value
specified will render the data in the order it appears in the dataProvider property—along
the x-axis from left to right. With no minField value specified,
the columns will base themselves at the origin.
Save your application and load it in the browser. Your chart should look similar to Figure 4.

Figure 4. This is your column chart with two ColumnSeries classes added
Now that you have your chart showing the right information, it's time to put some effort into making it look right.
The first task at hand is to do something about those unsightly labels along the horizontal axis. Try resizing the browser window; notice how cluttered and hard to read those labels get when the window's size is reduced? Isn't there a better way to squeeze in those labels?
Well, it turns out there is. The Flash client has a long-standing limitation that says if you want to rotate text, you have to use an embedded font. Your chart component knows this and will only consider rotating those labels to fit if you provide it with an appropriate font:
Add a style block to your Application tag with an embedded
font declaration. Assign this as the font-family style for
your ColumnChart selector:
<mx:Style>
@font-face {
font-family: chartLabelFont;
src: local("Arial");
}
ColumnChart {
font-family: chartLabelFont;
}
</mx:Style>
Save your application and load it in the browser. Your chart should now look similar to Figure 5.

Figure 5. This is your column chart with rotated labels
Now try resizing the browser window. You'll notice that as the chart changes size, the angle and spacing of the horizontal labels change also. While you can specify exact spacing and rotation values through additional style properties, the Flex charts do their best to default always to a reasonable appearance, no matter how much data they render.
Next, make those labels on the vertical axis a little more readable. While
the Axis objects (LinearAxis and CategoryAxis) are responsible for mapping
values from data to screen coordinates, it's the AxisRenderer object that
is responsible for drawing the axes themselves onscreen. Each chart (with
the exception of the pie chart) has two AxisRenderer objects, one for the
horizontal and one for the vertical axis. To format the labels of an axis,
you can provide a labelFunction value to the appropriate AxisRenderer
object.
Add an AxisRenderer object with a labelFunction value specified
in the verticalAxisRenderer property of the ColumnChart tag:
<mx:ColumnChart ...>
...
<mx:verticalAxisRenderer>
<mx:AxisRenderer labelFunction="formatThousands" />
</mx:verticalAxisRenderer>
</mx:ColumnChart>
Note: The formatThousands function
can be found in the zingerChartFunctions.as file.
Rather than specifying a color style to affect the appearance of chart components, Flex 1.5 introduces the Fill object. Using fills rather than numeric RGB values enables you to leverage the full range of the Flash platform's rendering abilities to customize your chart.
Next use different Fill types to customize the way your columns are rendered:
Apply the following SolidColor object to the fill style of
your first ColumnSeries tag:
<mx:ColumnSeries yField="Widgets">
<mx:fill>
<mx:SolidColor color="#82C9EB" />
</mx:fill>
</mx:ColumnSeries>
Apply the following LinearGradient object to the fill style
of your second ColumnSeries tag:
<mx:ColumnSeries yField="Blinkies" >
<mx:fill>
<mx:LinearGradient angle="0">
<mx:entries>
<mx:Array>
<mx:GradientEntry ratio="30" color="#258BC8" />
<mx:GradientEntry ratio="80" color="#82C9EB" />
<mx:GradientEntry ratio="100" color="#258BC8" />
</mx:Array>
</mx:entries>
</mx:LinearGradient>
</mx:fill>
</mx:ColumnSeries>
Save your file and reload it in the browser. Your chart should look similar to Figure 6.

Figure 6. Use Fill objects to style your ColumnSeries class
You can use Cascading Style Sheets (CSS) to specify style properties for nested components of the chart, such as the Axes, GridLines, and Series objects. Next use CSS type selectors to control the appearance of the chart's GridLines and AxisRenderer objects:
Add a CSS selector to the Style tag in your application to
specify the appearance of the gridlines:
<mx:Style>
...
.vBarGridlines {
direction: both;
verticalFill: #FFEEAA;
verticalTickAligned: false;
}
</mx:Style>
Pass the gridlines' new style name to your chart in the gridLinesStyle property
of the ColumnChart selector:
ColumnChart {
font-family: chartLabelFont;
gridLinesStyle: vBarGridlines;
}
Use the horizontalAxisStyle and verticalAxisStyle properties
to change the appearance of the chart's axes. Flex ships with a number
of predefined axis styles; for this tutorial, use the linedNumericAxis and hangingCategoryAxis styles.
Add these properties to the ColumnChart style selector:
ColumnChart {
font-family: chartLabelFont;
gridLinesStyle: vBarGridlines;
verticalAxisStyle: linedNumericAxis;
horizontalAxisStyle: hangingCategoryAxis;
}
Save your file and reload it in the browser. Your chart should appear as shown in Figure 7.

Figure 7. You can style the axes and gridlines with nested CSS selectors
Now that your chart is looking stylish, it's time to make it more than just another pretty face. Charts are great for getting an overall view of the landscape, but most users need to know the specifics as well. Enable the built-in DataTips object of the chart to give your users access to the individual values:
Enable the DataTips object by adding the showDataTips=true attribute
to your ColumnChart tag:
<mx:ColumnChart dataProvider="{zingerManufacturingData}" width="100%"
height="100%" showDataTips="true">
Save your file and reload it in the browser. Try moving your mouse across the chart. You'll see a data tip appear showing you the individual column values (see Figure 8).

Figure 8. Flex supports automatic data tips on every chart type
That's a good start but you can provide additional hints to the chart to help it format the data in the tips. The more information you provide, the easier it will be for your users to understand the data.
Provide a name for your ColumnSeries element by setting the name attribute
to something meaningful to your users:
<mx:ColumnSeries yField="Widgets" name="Luxury Widgets"> ... <mx:ColumnSeries yField="Blinkies" name="Mass Market Blinkies">
Do the same for your Axis objects to label the values displayed in the data tip:
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{zingerManufacturingData}" categoryField="Month" name="Month" />
</mx:horizontalAxis>
...
<mx:verticalAxisRenderer>
<mx:LinearAxis name="Units Sold" />
</mx:verticalAxisRenderer>
Save your file and reload it in the browser. Once again try moving your mouse across the chart. You will now see a friendlier data tip (see Figure 9).
Figure 9. Naming your axes and series can make your data tips more readable
At this point you have a nice-looking chart that gives your users an overall sense of the data trend as well as access to the individual values. In this last section, I show you how to push your application a little bit farther in each direction—customization, styling, and interactivity—to really show off what you can do with the Flex charting components.
A common interaction technique for a chart is to allow the user to drill down on the details of a particular item. For example, in our fictitious Zinger Corporation chart, a user may want to drill down on how many units were sold on each day of any particular month.
To make drill-down interaction possible, you can make use of a few new events
in Flex charts. All Flex components broadcast the mouseOver, mouseOut,
or mouseMove events when the mouse pointer enters its bounds,
leaves its bounds, or moves while over its bounds. With charts, you can also
use the more specific mouseOverData, mouseOutData,
and mouseMoveData events to give you additional information about
where the mouse pointer is with respect to the data being rendered inside the
chart.
As you might expect, the mouseOverData and mouseOutData events
are broadcast when the mouse moves over and away from a data point onscreen,
while the mouseMoveData event is broadcast when the mouse pointer
moves while over a data point. Additionally, a mouseClickData event
is broadcast when the user clicks a data point in the chart.
Each of these new events comes with a reference to an mx.charts.HitData structure,
which contains all the information that describes which data object it relates
to, which series, how far the mouse pointer is, and so on. See the API reference
(ASDoc) included with Flex 1.5 for more information.
Use the mouseClickData event to determine which month the user
wants to drill down on, and fetch additional data for display:
Add a mouseClickData event handler to your ColumnChart tag.
This handler will load the drill-down data based on which specific month
or column was clicked on. Typically you load the new data from one of the
Flex network service types; for this tutorial, use a utility function to
generate sample data. This function can be found in the zingerChartFunctions.as
file included in the flex_tutorials directory:
<mx:ColumnChart dataProvider="{zingerManufacturingData}" width="100%" height="100%"
showDataTips="true"
mouseClickData="getDrillDownDataForMonth(event.hitData.element.yField, event.hitData.item);" >
After your application has loaded the drill-down data, you need to display it somewhere for your users to examine it. You might choose to drill down in place, replacing the current chart with a new one displaying the new data. Alternatively, you could load the data into a grid to display the actual values. In this application, add an additional chart to render the drill-down values side by side.
Rather than using a simple column chart this time, bind the drill-down data into a more advanced combination chart. This chart will show columns for the individual unit sales count broken out by day, plus a trend line showing the running average sales count over a five-day period.
To build combination charts in Flex 1.5, use the CartesianChart component, the base class for all the standard built-in chart types (except for the PieChart component). The CartesianChart component embodies almost all of the behavior you'll find in the various subtypes, with the added benefit that it makes no assumptions about the types of series objects contained within it.
Add a new CartesianChart and Label component beneath your initial ColumnChart
component, inside the Panel tag. This CartesianChart component
will be bound to a new array, drilldownValues. The drilldownValues array
is declared in the generateData.as file that accompanies this tutorial:
<mx:Label id="drilldownLabel" text="{drilldownTitle}" fontSize="16" fontWeight="bold" />
<mx:CartesianChart id="drillDownChart" width="100%" height="30%" dataProvider="{drilldownValues}" fontFamily="chartLabelFont"
horizontalAxisStyle="hangingCategoryAxis" verticalAxisStyle="linedNumericAxis">
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{drilldownValues}" categoryField="week" />
</mx:horizontalAxis>
<mx:horizontalAxisRenderer>
<mx:AxisRenderer canDropLabels="true" />
</mx:horizontalAxisRenderer>
<mx:verticalAxisRenderer>
<mx:AxisRenderer labelFunction="formatThousands" />
</mx:verticalAxisRenderer>
<mx:series>
<mx:Array>
<mx:ColumnSeries yField="sales" />
<mx:LineSeries form="curve" yField="avg" >
</mx:LineSeries>
</mx:Array>
</mx:series>
</mx:CartesianChart>
Save your file and reload it in the browser. Click one of the columns in the top chart. You should see your drill-down chart fill with data (see Figure 10).
Figure 10. You can use the CartesianChart class to build more complex combo charts
Next apply a little more styling to modify the appearance of the trendline in your drill-down chart. First change its color and size by setting a stroke. Similar to Fill objects, Stroke objects are used by the charting components to control the color, weight, and transparency of the lines and edges drawn when rendering the data.
Add a Stroke object to the stroke style of the LineSeries
object in your drill-down chart:
<mx:LineSeries form="curve" yField="avg">
<mx:stroke>
<mx:Stroke weight="3" color="#82C9EB" />
</mx:stroke>
</mx:LineSeries>
Save your file and reload it in the browser. When you drill down on your data, you should see a nice blue trendline (see Figure 11).

Figure 11. Stroke objects can modify the color, weight, and transparency of a chart line
Now for the grand finale. It's time to add some transition effects to your
drill-down chart. Flex 1.5 introduces three new built-in effect types that
are specific to the charting components: SeriesZoom, SeriesSlide, and SeriesInterpolate.
These effects, which are only designed to be used on the various Series types
in the Flex charting components, provide you with a wide variety of ways to
transition the data onscreen when building interactive charts.
You can use these effects in your charting applications by attaching them
to the hideDataEffect and showDataEffect triggers
of the series of any chart. Here's what happens when a chart series detects
a change in the underlying dataProvider property being rendered:
hideDataEffect trigger to transition the old
data values off-screen.showDataEffect trigger to transition the new
data values back onscreen.Now add a SeriesInterpolate effect to your drill-down chart to animate the change as new values are loaded:
Add an Effect tag as a child of your Application tag,
with a SeriesInterpolate definition inside:
<mx:Effect>
<mx:SeriesInterpolate duration="500" elementOffset="5" name="drillDownEffect" />
</mx:Effect>
Assign the new effect to the showDataEffect trigger of the Column and Line series
in your drill-down chart:
<mx:ColumnSeries yField="sales" showDataEffect="drillDownEffect" /> <mx:LineSeries form="curve" yField="avg" showDataEffect="drillDownEffect" >
This tutorial has really only scratched the surface of what you can do with the new charting components in Flex 1.5. Beyond the column and Cartesian charts used in this example, Flex ships with a bar, bubble, pie, line, plot, and area chart, along with their associated series objects. With each chart type you have myriad additional display options—whether to render stacked or overlaid, floating or based, with labels or without—to build exactly the chart your project requires.
Flex 1.5 also ships with a very comprehensive chapter describing the charting platform, explaining and expanding on many of the concepts outlined here. The new API reference also includes complete documentation of the variety of controls and options available on the charting controls.
Beyond that, the best way to get a handle on what's capable with the Flex charting components is to fire up the server and play around with them. If there's something you want to build with the charting components that doesn't seem possible, let us know! There's a wealth of charting features that we can add in future releases of Flex, and your requests and opinions will help guide how we prioritize them.