Flex 3 Cookbook Sample Chapter


Published on

Flex 3 Cookbook Sample Chapter

Published in: Technology, Art & Photos
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Flex 3 Cookbook Sample Chapter

  1. 1. 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
  2. 2. 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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot;> <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=quot;{simpleCharts}quot; direction=quot;verticalquot; /> <mx:ViewStack id=quot;simpleChartsquot; > <mx:Canvas label=quot;Barquot;> <mx:BarChart dataProvider=quot;{chartDP}quot; > <mx:verticalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP}quot; categoryField=quot;dayquot; /> </mx:verticalAxis> <mx:series> <!-- bar chart uses a BarSeries --> <mx:BarSeries yField=quot;dayquot; xField=quot;rainfallquot; displayName=quot;dayquot; /> </mx:series> </mx:BarChart> 458 | Chapter 16: Charting
  3. 3. </mx:Canvas> <mx:Canvas label=quot;Piequot;> <mx:PieChart dataProvider=quot;{chartDP}quot; > <!-- no axes need to be defined in a pie chart --> <mx:series> <!-- pie chart uses a pie series --> <mx:PieSeries field=quot;rainfallquot; nameField=quot;dayquot; labelPosition=quot;calloutquot; displayName=quot;rainfallquot; /> </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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot;> <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:quot;1-Aug-05quot;,open:42.57,high:43.08,low:42.08,close:42.75}, {date:quot;2-Aug-05quot;,open:42.89,high:43.5,low:42.61,close:43.19}, {date:quot;3-Aug-05quot;,open:43.19,high:43.31,low:42.77,close:43.22}, {date:quot;4-Aug-05quot;,open:42.89,high:43,low:42.29,close:42.71}, {date:quot;5-Aug-05quot;,open:42.49,high:43.36,low:42.02,close:42.99}, {date:quot;8-Aug-05quot;,open:43,high:43.25,low:42.61,close:42.65}, {date:quot;9-Aug-05quot;,open:42.93,high:43.89,low:42.91,close:43.82}, {date:quot;10-Aug-05quot;,open:44,high:44.39,low:43.31,close:43.38}, {date:quot;11-Aug-05quot;,open:43.39,high:44.12,low:43.25,close:44}, {date:quot;12-Aug-05quot;,open:43.46,high:46.22,low:43.36,close:46.1} ]; ]]> </mx:Script> <mx:CandlestickChart dataProvider=quot;{highLowChartDP}quot; showDataTips=quot;truequot;> <mx:verticalAxis> <mx:LinearAxis minimum=quot;40quot; maximum=quot;50quot; /> </mx:verticalAxis> <mx:horizontalAxis> <mx:CategoryAxis categoryField=quot;datequot; /> </mx:horizontalAxis> <mx:series> <mx:CandlestickSeries 16.1 Create a Chart | 459
  4. 4. dataProvider=quot;{highLowChartDP}quot; openField=quot;openquot; highField=quot;highquot; lowField=quot;lowquot; closeField=quot;closequot; displayName=quot;Rainfallquot;/> </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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot;> <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=quot;{chartDP}quot; > <mx:horizontalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP}quot; categoryField=quot;dayquot; /> </mx:horizontalAxis> <mx:series> <mx:AreaSeries alpha=quot;.5quot; 460 | Chapter 16: Charting
  5. 5. yField=quot;rainfallquot; displayName=quot;rainfallquot;> 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=quot;.5quot; alphaTo=quot;1quot; duration=quot;500quot; /> </mx:rollOverEffect> <mx:rollOutEffect> <mx:Fade alphaFrom=quot;1quot; alphaTo=quot;.5quot; duration=quot;500quot; /> </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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot;> <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
  6. 6. ]]> </mx:Script> <mx:SeriesSlide id=quot;dataInquot; duration=quot;500quot; direction=quot;upquot;/> <mx:SeriesSlide id=quot;dataOutquot; duration=quot;500quot; direction=quot;upquot;/> <mx:SeriesZoom id=quot;dataOutquot; duration=quot;500quot;/> <mx:SeriesInterpolate id=quot;dataInquot; duration=quot;1000quot;/> --> <mx:BarChart id=quot;rainfallChartquot; dataProvider=quot;{chartDP1}quot; > <mx:horizontalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP1}quot; categoryField=quot;dayquot; /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries yField=quot;rainfallquot; xField=quot;dayquot; displayName=quot;rainfallquot; showDataEffect=quot;{dataIn}quot; hideDataEffect=quot;{dataOut}quot; /> </mx:series> </mx:BarChart> <mx:HBox> <mx:RadioButton groupName=quot;dataProviderquot; label=quot;Data Provider 1quot; selected=quot;truequot; click=quot;rainfallChart.dataProvider=chartDP1;quot;/> <mx:RadioButton groupName=quot;dataProviderquot; label=quot;Data Provider 2quot; click=quot;rainfallChart.dataProvider=chartDP2;quot;/> </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
  7. 7. 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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;verticalquot; backgroundColor=quot;0xFFFFFFquot;> <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
  8. 8. { 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=quot;barChartquot; dataProvider=quot;{chartDP}quot; selectionMode=quot;multiplequot; change=quot;onSelectionChange()quot;> <mx:verticalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP}quot; categoryField=quot;dayquot; /> </mx:verticalAxis> <mx:series> <mx:BarSeries id=quot;barSeriesquot; selectedIndex=quot;0quot; yField=quot;dayquot; xField=quot;rainfallquot; displayName=quot;dayquot; /> </mx:series> </mx:BarChart> <mx:HBox> <mx:Button click=quot;changeSelectedIndex(1)quot; label=quot;Previousquot; /> <mx:Button click=quot;changeSelectedIndex(−1)quot; label=quot;Nextquot; /> </mx:HBox> <mx:DataGrid id=quot;detailGridquot; > <mx:columns> <mx:DataGridColumn dataField=quot;xValuequot; headerText=quot;rainfallquot; /> <mx:DataGridColumn dataField=quot;yValuequot; headerText=quot;dayquot; /> </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
  9. 9. 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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot;> <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
  10. 10. <mx:Canvas label=quot;Areaquot;> <mx:AreaChart dataProvider=quot;{chartDP}quot; > <mx:horizontalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP}quot; categoryField=quot;dayquot; /> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis id=quot;vertAxisquot; /> </mx:verticalAxis> <mx:verticalAxisRenderers> <mx:AxisRenderer axis=quot;{vertAxis}quot; styleName=quot;customTicksquot; /> </mx:verticalAxisRenderers> <mx:series> <mx:AreaSeries yField=quot;rainfallquot; displayName=quot;rainfallquot; /> </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
  11. 11. 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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;horizontalquot; backgroundColor=quot;0xFFFFFFquot; initialize=quot;onInit()quot;> <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
  12. 12. formatter.useThousandsSeparator = true; } private function currencyAxisLabel(value:Object, previousValue:Object, axis:IAxis):String { return formatter.format(value); } ]]> </mx:Script> <mx:LineChart dataProvider=quot;{chartDP}quot; > <mx:horizontalAxis> <mx:CategoryAxis dataProvider=quot;{chartDP}quot; categoryField=quot;monthquot; /> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis labelFunction=quot;{currencyAxisLabel}quot; /> </mx:verticalAxis> <mx:series> <mx:LineSeries yField=quot;costsquot; xField=quot;monthquot; displayName=quot;Costsquot; /> </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
  13. 13. 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=quot;http://www.adobe.com/2006/mxmlquot;> <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:quot;01/02/2006quot;, total:3000, food:1300, drinks:1700, other:0, expenses:2700, profit:300}, { date:quot;01/08/2006quot;, total:3500, food:1800, drinks:1500, other:200, expenses:2900, profit:600}, { date:quot;01/15/2006quot;, total:2600, food:1000, drinks:1600, other:0, expenses:2700, profit:−100}, { date:quot;01/22/2006quot;, total:3200, food:1300, drinks:1900, other:0, expenses:2900, profit:200 }, { date:quot;02/1/2006quot;, total:2200, food:1200, drinks:1000, other:0, expenses:2100, profit:100 }, { date:quot;02/8/2006quot;, total:2600, food:1300, drinks:1600, other:100, expenses:2700, profit:400 }, { date:quot;02/16/2006quot;, total:4100, food:2300, drinks:1700, other:100, expenses:2700, profit:200 }, { date:quot;02/22/2006quot;, 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 = quot;Daily Breakdownquot;; columnSeries.yField = quot;amountquot;; columnSeries.xField = quot;typequot;; ca1.categoryField = quot;typequot;; mainPanel.title = quot;Profits for quot; + e.hitData.item.date; mainDataProvider = drillDownDataSet; 16.6 Create a Drill-Down Effect for a Columnar Chart | 469
  14. 14. } else { mainDataProvider = overview; columnSeries.displayName = quot;Profit by datequot;; columnSeries.yField = quot;profitquot;; columnSeries.xField = quot;datequot;; ca1.categoryField = quot;datequot;; mainPanel.title = quot;Profit Overviewquot;; } } 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:quot;foodquot;, amount:e.hitData.item.food }; var drinks:Object = { type:quot;drinksquot;, amount:e.hitData.item.drinks }; var other:Object = { type:quot;otherquot;, amount:e.hitData.item.other }; var expenses:Object = { type:quot;expensesquot;, amount:e.hitData.item.expenses }; result.push(food); result.push(drinks); result.push(other); result.push(expenses); return result; } ]]></mx:Script> <mx:SeriesZoom id=quot;slideZoomInquot; duration=quot;1000quot; verticalFocus=quot;bottomquot;/> <mx:SeriesZoom id=quot;slideZoomOutquot; duration=quot;1000quot; verticalFocus=quot;bottomquot;/> <mx:Panel id=quot;mainPanelquot; title=quot;Profitabilityquot;> <mx:ColumnChart id=quot;chartquot; showDataTips=quot;truequot; itemClick=quot;zoomIntoSeries 470 | Chapter 16: Charting
  15. 15. (event)quot; dataProvider=quot;{mainDataProvider}quot;> <mx:series> The showDataEffect and hideDataEffect properties indicate which effect will be played when the dataProvider for a ChartSeries is changed: <mx:ColumnSeries id=quot;columnSeriesquot; displayName=quot;Total profitquot; fillFunction=quot;profitFunctionquot; yField=quot;profitquot; xField=quot;datequot; hideDataEffect=quot;slideZoomOutquot; showDataEffect=quot;slideZoomInquot;/> </mx:series> <mx:horizontalAxis> <mx:CategoryAxis id=quot;ca1quot; categoryField=quot;datequot;/> </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
  16. 16. 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=quot;goalsquot; yField=quot;gamesquot; displayName=quot;Goals per gamequot; itemRenderer= quot;@Embed(source='../assets/soccerball.pngquot;)quot; radius=quot;20quot; legendMarkerRenderer=quot; @Embed(source='../assets/soccerball.png')quot;/> 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
  17. 17. [Embed(source=quot;../../assets/Shakey.pngquot;)] 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=quot;columnquot; dataProvider=quot;{expenses}quot;> <mx:horizontalAxis> <mx:CategoryAxis dataProvider=quot;{expenses}quot; categoryField=quot;Monthquot; /> </mx:horizontalAxis> <mx:series> <mx:Array> <mx:ColumnSeries xField=quot;Monthquot; yField=quot;Expensesquot; displayName=quot;Expensesquot; itemRenderer=quot;oreilly.cookbook.CustomRendererquot; /> </mx:Array> </mx:series> </mx:ColumnChart> 16.7 Skin Chart Items | 473
  18. 18. 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=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;verticalquot; backgroundColor=quot;0xFFFFFFquot; creationComplete=quot;onComplete()quot;> <mx:Script> <![CDATA[ import mx.charts.series.ColumnSet; import mx.charts.series.ColumnSeries; 474 | Chapter 16: Charting
  19. 19. [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 = quot;clusteredquot;; //initialize all of our series dawnSeries = new ColumnSeries(); dawnSeries.yField = quot;dawnRainfallquot;; dawnSeries.xField = quot;dayquot;; dawnSeries.displayName = quot;Dawn Rainfallquot;; morningSeries = new ColumnSeries(); morningSeries.yField = quot;morningRainfallquot;; morningSeries.xField = quot;dayquot;; morningSeries.displayName = quot;Morning Rainfallquot;; midDaySeries = new ColumnSeries(); midDaySeries.yField = quot;midDayRainfallquot;; midDaySeries.xField = quot;dayquot;; midDaySeries.displayName = quot;Mid-day Rainfallquot;; afternoonSeries = new ColumnSeries(); afternoonSeries.yField = quot;afternoonRainfallquot;; afternoonSeries.xField = quot;dayquot;; afternoonSeries.displayName = quot;Afternoon Rainfallquot;; duskSeries = new ColumnSeries(); duskSeries.yField = quot;duskRainfallquot;; duskSeries.xField = quot;dayquot;; duskSeries.displayName = quot;Dusk Rainfallquot;; 16.8 Use ActionScript to Dynamically Add and Remove Columns for a Chart | 475
  20. 20. 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 quot;seriesquot; attribute rainfallChart.series = [columnSet]; } ]]> </mx:Script> <mx:ColumnChart id=quot;rainfallChartquot; dataProvider=quot;{chartDP}quot; > <mx:horizontalAxis> <mx:CategoryAxis categoryField=quot;dayquot; /> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis minimum=quot;0quot; maximum=quot;14quot; /> </mx:verticalAxis> <!-- notice there is no series attribute defined, we do that in AS above --> </mx:ColumnChart> <mx:HBox> <mx:CheckBox id=quot;showDawnCheckBoxquot; label=quot;Dawn Rainfallquot; selected=quot;truequot; change=quot;updateSeries()quot; /> <mx:CheckBox id=quot;showMorningCheckBoxquot; label=quot;Morning Rainfallquot; change=quot;updateSeries()quot; /> <mx:CheckBox id=quot;showMidDayCheckBoxquot; label=quot;Mid-day Rainfallquot; change=quot;updateSeries()quot; /> <mx:CheckBox id=quot;showAfternoonCheckBoxquot; label=quot;Afternoon Rainfallquot; change=quot;updateSeries()quot; /> <mx:CheckBox id=quot;showDuskCheckBoxquot; label=quot;Dusk Rainfallquot; change=quot;updateSeries()quot; /> </mx:HBox> </mx:Application> 476 | Chapter 16: Charting
  21. 21. 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=quot;http://www.adobe.com/2006/mxmlquot; creationComplete=quot;genData()quot;> <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({quot;DJIAquot;: DJIA, quot;NASDACquot;: NASDAC, quot;SP500quot;: SP500 }); } chartData = newArr; } [Bindable] public var chartData:Array = []; ]]> </mx:Script> <mx:SeriesInterpolate id=quot;effquot; elementOffset=quot;1quot; minimumElementDuration=quot;40quot; duration=quot;2000quot;/> <mx:Button click=quot;genData()quot; label=quot;Generate dataquot;/> <mx:ColumnChart y=quot;100quot; width=quot;100%quot; height=quot;100%quot; dataProvider=quot;{chartData}quot;> <mx:series> <mx:ColumnSeries showDataEffect=quot;{eff}quot; yField=quot;DJIAquot;/> <mx:ColumnSeries showDataEffect=quot;{eff}quot; yField=quot;NASDACquot;/> 16.9 Overlap Multiple ChartSeries | 477
  22. 22. <mx:ColumnSeries showDataEffect=quot;{eff}quot; yField=quot;SP500quot;/> </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=quot;http://www.adobe.com/2006/mxmlquot; xmlns:cookbook= quot;oreilly.cookbook.*quot;> <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([{ quot;namequot;: quot;C Ronaldoquot;, quot;sogquot;:128, quot;goalsquot;:20, quot;gamesquot;:33 }, { quot;namequot;:quot;A Adebayorquot;, quot;sogquot;:128, quot;goalsquot;:20, quot;gamesquot;:35 }, { quot;namequot;:quot;F Torresquot;, quot;sogquot;:98, quot;goalsquot;:18, quot;gamesquot;:32 }, { quot;namequot;:quot;W Rooneyquot;, quot;sogquot;:89, quot;goalsquot;:17, quot;gamesquot;:34 }, { quot;namequot;:quot;D Drogbaquot;, quot;sogquot;:114, quot;goalsquot;:16, quot;gamesquot;:31 }]); [Bindable] private var subColl:ArrayCollection = new ArrayCollection([{ quot;namequot;: 478 | Chapter 16: Charting
  23. 23. quot;C Ronaldoquot;, quot;sogquot;:128, quot;goalsquot;:20, quot;gamesquot;:33 }, { quot;namequot;:quot;A Adebayorquot;, quot;sogquot;:128, quot;goalsquot;:20, quot;gamesquot;: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=quot;{subColl}quot; selectionMode=quot;singlequot; dragEnabled=quot;truequot; dropEnabled=quot;truequot; mouseMove=quot;mouseMoveHandler(event)quot; dragDrop= quot;dragDropHandler(event)quot;> <mx:series> <mx:PieSeries field=quot;goalsquot; nameField=quot;namequot; labelField=quot;namequot; labelPosition=quot;calloutquot; selectable=quot;truequot;/> </mx:series> </mx:PieChart> <mx:PieChart dataProvider=quot;{masterArrColl}quot; dragEnabled=quot;truequot; dropEnabled=quot;truequot; selectionMode=quot;singlequot; mouseMove=quot;mouseMoveHandler(event)quot; dragDrop=quot; dragDropHandler(event)quot;> <mx:series> 16.10 Drag and Drop Items in a Chart | 479
  24. 24. <mx:PieSeries field=quot;goalsquot; nameField=quot;namequot; labelField=quot;namequot; labelPosition=quot;calloutquot; selectable=quot;truequot;/> </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=quot;http://www.adobe.com/2006/mxmlquot;> <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: quot;Janquot;, Profit: 2000, Expenses: 1500, Sales: 3550}, { Month: quot;Febquot;, Profit: 1000, Expenses: 200, Sales: 1200}, { Month: quot;Marquot;, Profit: 1500, Expenses: 500, Sales: 2000}, { Month: quot;Aprquot;, Profit: 1800, Expenses: 1200, Sales: 3000}, { Month: quot;Mayquot;, Profit: 2400, Expenses: 575, Sales: 2975}]); 480 | Chapter 16: Charting
  25. 25. // 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 == quot;Expensesquot;) { 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
  26. 26. 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=quot;LineChart and AreaChart Controls Examplequot; height=quot;100%quot; width=quot;100%quot; layout=quot;horizontalquot;> <mx:LineChart id=quot;linechartquot; height=quot;100%quot; width=quot;100%quot; paddingLeft=quot;5quot; paddingRight=quot;5quot; dragDrop=quot;setDragDropData(event)quot; showDataTips=quot;truequot; dataProvider=quot;{expensesAC}quot; selectionMode=quot;singlequot; dragEnabled=quot;truequot; dropEnabled=quot;truequot;> <mx:horizontalAxis> <mx:CategoryAxis categoryField=quot;Monthquot;/> </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=quot;falsequot; id=quot;profitSeriesquot; yField=quot;Profitquot; form=quot;curvequot; displayName=quot;Profitquot; itemRenderer = quot;mx.charts.renderers.CircleItem Rendererquot;/> <mx:LineSeries mouseMove=quot;mouseMoveHandler(event)quot; yField=quot;Expensesquot; form=quot;curvequot; displayName=quot;Expensesquot; selectable=quot;truequot; itemRenderer = quot;mx.charts. renderers.CircleItemRendererquot;/> <mx:LineSeries mouseMove=quot;mouseMoveHandler(event)quot; yField=quot;Salesquot; form=quot;curvequot; displayName=quot;Salesquot; selectable=quot;truequot; itemRenderer = quot;mx.charts. renderers.CircleItemRendererquot;/> </mx:series> </mx:LineChart> <mx:Legend dataProvider=quot;{linechart}quot;/> </mx:Panel> </mx:Application> 482 | Chapter 16: Charting