FLEX 动态绑定chart 数据

The chart controls have a dataProvider property that defines the data for the chart. The data provider creates a level of abstraction between Flex components and the data that you use to populate them. You can populate multiple charts from the same data provider, switch data providers for a chart at run time, and modify the data provider so that changes are reflected by all charts using the data provider.

Using chart data

To use the data from a data provider in your chart control, you map the xField and yField properties of the chart series to the fields in the data provider. The xField property defines the data for the horizontal axis, and the yField property defines the data for the vertical axis.

For example, assume your data provider has the following structure:

{Month: "Feb", Profit: 1000, Expenses: 200, Amount: 60}

You can use the Profit and Expenses fields and ignore the Month field by mapping the xField property of the series object to one field and the yField property of the series object to another field, as the following example shows:

<mx:PlotSeries xField="Profit" yField="Expenses"/>

The result is that each data point is the intersection of the Profit and Expenses fields from the data provider.

To place the data points into a meaningful grouping, you can choose a separate property of the data provider as the categoryField. In this case, to sort each data point by month, you map the Month field to the categoryField property of the horizontal axis:

<mx:horizontalAxis>
    <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month"/>
</mx:horizontalAxis>

In some cases, depending on the type of chart and the type of data you are representing, you use either the xField property or the yField property to define the data series. In a ColumnChart control, for example, the yField property defines the height of the column. You do not have to specify an xField property. To get an axis label for each column, you specify a categoryField property for the horizontalAxis.

The data provider can contain complex objects, or objects within objects. For example, a data provider object can have the following structure:

{month: "Aug", close: {High:45.87,Low:12.2}, open:25.19}

In this case, you cannot simply refer to the field of the data provider by using a categoryField, xField, or similar flat naming convention. Rather, you use the dataFunction of the series or axis to drill down into the data provider. For more information on working with complex data, see Structure of chart data.

When you use chart data, keep the following in mind:

  1. You usually match a series with a data provider field if you want to display that series. However, this is not always true. If you do not specify an xField for a ColumnSeries, Flex assumes the index is the value. If you do not specify a yField, Flex assumes the data provider is a collection of y values, rather than a collection of objects that have y values. For example, the following series renders correctly for a ColumnChart control:
    <mx:ColumnSeries dataProvider="{[1,2,3,4,5]}"/>
    
    
  • Some series use only one field from the data provider, while others can use two or more. For example, you specify only a field property for a PieSeries object, but you can specify an xField and a yField for a PlotSeries object and an xField, yField, and radiusField for a BubbleSeries object.
  • Most of the series can determine suitable defaults for their nonprimary dimensions if no field is specified. For example, if you do not explicitly set an xField for the ColumnSeries, LineSeries, and AreaSeries, Flex maps the data to the chart's categories in the order in which the data appears in the data provider. Similarly, a BarSeries maps the data to the categories if you do not set a yField.

For a complete list of the fields that each data series can use, see the data series entry in Adobe Flex Language Reference. For more information on data providers, see Data provider controls.

Sources of chart data

You can supply data to a data provider in the following ways:

  • Define it in a <mx:Script> block.
  • Define it in an external XML, ActionScript, or text file.
  • Return it by using a WebService call.
  • Return it by using a RemoteObject component.
  • Return it by using an HTTPService component.
  • Define it in MXML.

There are some limitations on the structure of the chart data, and how to reference chart data if it is constructed with complex objects. For more information, see Structure of chart data.

For more information on data providers, see Using Data Providers and Collections.

Using static Arrays as data providers

Using a static Array of objects for the data provider is the simplest approach. You typically create an Array of objects, as the following example shows:

<?xml version="1.0"?>
<!-- charts/ArrayOfObjectsDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;
     [Bindable]
     private var expenses:Array = [
        {Month:"January",Profit:2000,Expenses:1500,Amount:450},
        {Month:"February",Profit:1000,Expenses:200,Amount:600},
        {Month:"March",Profit:1500,Expenses:500,Amount:300},
        {Month:"April",Profit:500,Expenses:300,Amount:500},
        {Month:"May",Profit:1000,Expenses:450,Amount:250},
        {Month:"June",Profit:2000,Expenses:500,Amount:700}
     ];

  ]]></mx:Script>
  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis 
                dataProvider="{expenses}" 
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also use MXML to define the content of an Array, as the following example shows:

<?xml version="1.0"?>
<!-- charts/ArrayOfMXMLObjectsDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Array id="expenses">
     <mx:Object
        Month="January"
        Profit="2000"
        Expenses="1500"
        Amount="450"
     />
     <mx:Object
        Month="February"
        Profit="1000"
        Expenses="200"
        Amount="600"
     />
     <mx:Object
        Month="March"
        Profit="1500"
        Expenses="500"
        Amount="300"
     />
     <mx:Object
        Month="April"
        Profit="500"
        Expenses="300"
        Amount="500"
     />
     <mx:Object
        Month="May"
        Profit="1000"
        Expenses="450"
        Amount="250"
     />
     <mx:Object
        Month="June"
        Profit="2000"
        Expenses="500"
        Amount="700"
     />
  </mx:Array>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis 
                dataProvider="{expenses}" 
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also define objects in MXML with a more verbose syntax, as the following example shows:

<?xml version="1.0"?>
<!-- charts/ArrayOfVerboseMXMLObjects.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Array id="expenses">
     <mx:Object>
       <mx:Month>January</mx:Month>
       <mx:Profit>2000</mx:Profit>
       <mx:Expenses>1500</mx:Expenses>
       <mx:Amount>450</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>February</mx:Month>
       <mx:Profit>1000</mx:Profit>
       <mx:Expenses>200</mx:Expenses>
       <mx:Amount>600</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>March</mx:Month>
       <mx:Profit>1500</mx:Profit>
       <mx:Expenses>500</mx:Expenses>
       <mx:Amount>300</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>April</mx:Month>
       <mx:Profit>500</mx:Profit>
       <mx:Expenses>300</mx:Expenses>
       <mx:Amount>300</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>May</mx:Month>
       <mx:Profit>1000</mx:Profit>
       <mx:Expenses>450</mx:Expenses>
       <mx:Amount>250</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>June</mx:Month>
       <mx:Profit>2000</mx:Profit>
       <mx:Expenses>500</mx:Expenses>
       <mx:Amount>700</mx:Amount>
     </mx:Object>
  </mx:Array>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expenses}"
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

A disadvantage of using a simple Array as a chart's data provider is that you can use only the methods of the Array class to manipulate the data. In addition, when you use an Array as a data provider, the data in it must be static. Even if you make the Array bindable, when data in an Array changes, the chart does not reflect those changes. For more robust data manipulation and data binding, you can use a collection for the chart data provider, as described in Using collections as data providers.

Using collections as data providers

Collections are a more robust data provider mechanism than Arrays. They provide operations that include the insertion and deletion of objects as well as sorting and filtering. Collections also support change notification. An ArrayCollection object provides an easy way to expose an Array as an ICollectionView or IList interface.

As with Arrays, you can use MXML to define the contents of a collection, as the following example shows:

<?xml version="1.0"?>
<!-- charts/ArrayCollectionOfMXMLObjectsDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:ArrayCollection id="expenses">
     <mx:Object
        Month="January"
        Profit="2000"
        Expenses="1500"
        Amount="450"
     />
     <mx:Object
        Month="February"
        Profit="1000"
        Expenses="200"
        Amount="600"
     />
     <mx:Object
        Month="March"
        Profit="1500"
        Expenses="500"
        Amount="300"
     />
     <mx:Object
        Month="April"
        Profit="500"
        Expenses="300"
        Amount="500"
     />
     <mx:Object
        Month="May"
        Profit="1000"
        Expenses="450"
        Amount="250"
     />
     <mx:Object
        Month="June"
        Profit="2000"
        Expenses="500"
        Amount="700"
     />
  </mx:ArrayCollection>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis 
                dataProvider="{expenses}" 
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

Or you can define an object in MXML usig child tags rather than attributes:

<?xml version="1.0"?>
<!-- charts/ArrayCollectionOfVerboseMXMLObjects.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:ArrayCollection id="expenses">
     <mx:Object>
       <mx:Month>January</mx:Month>
       <mx:Profit>2000</mx:Profit>
       <mx:Expenses>1500</mx:Expenses>
       <mx:Amount>450</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>February</mx:Month>
       <mx:Profit>1000</mx:Profit>
       <mx:Expenses>200</mx:Expenses>
       <mx:Amount>600</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>March</mx:Month>
       <mx:Profit>1500</mx:Profit>
       <mx:Expenses>500</mx:Expenses>
       <mx:Amount>300</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>April</mx:Month>
       <mx:Profit>500</mx:Profit>
       <mx:Expenses>300</mx:Expenses>
       <mx:Amount>300</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>May</mx:Month>
       <mx:Profit>1000</mx:Profit>
       <mx:Expenses>450</mx:Expenses>
       <mx:Amount>250</mx:Amount>
     </mx:Object>
     <mx:Object>
       <mx:Month>June</mx:Month>
       <mx:Profit>2000</mx:Profit>
       <mx:Expenses>500</mx:Expenses>
       <mx:Amount>700</mx:Amount>
     </mx:Object>
  </mx:ArrayCollection>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expenses}"
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can create an ArrayCollection object in ActionScript. If you define an ArrayCollection in this way, ensure that you import the mx.collections.ArrayCollection class, as the following example shows:

<?xml version="1.0"?>
<!-- charts/ArrayCollectionOfObjects.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;

     [Bindable]
     private var expenses:ArrayCollection = new ArrayCollection([
        {Month:"January", Profit:2000, Expenses:1500, Amount:450},
        {Month:"February", Profit:1000, Expenses:200, Amount:600},
        {Month:"March", Profit:1500, Expenses:500, Amount:300},
        {Month:"April", Profit:500, Expenses:300, Amount:500},
        {Month:"May", Profit:1000, Expenses:450, Amount:250},
        {Month:"June", Profit:2000, Expenses:500, Amount:700}
     ]);

  ]]></mx:Script>
  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expenses}"
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

If your data is in an Array, you can pass the Array to the ArrayCollection's constructor to convert it to an ArrayCollection. The following example creates an Array, and then converts it to an ArrayCollection:

<?xml version="1.0"?>
<!-- charts/ArrayConvertedToArrayCollection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;

     private var expenses:Array = [
        {Month:"January", Profit:2000, Expenses:1500, Amount:450},
        {Month:"February", Profit:1000, Expenses:200, Amount:600},
        {Month:"March", Profit:1500, Expenses:500, Amount:300},
        {Month:"April", Profit:500, Expenses:300, Amount:500},
        {Month:"May", Profit:1000, Expenses:450, Amount:250},
        {Month:"June", Profit:2000, Expenses:500, Amount:700}
     ];

     [Bindable]
     public var expensesAC:ArrayCollection = 
        new ArrayCollection(expenses);

  ]]></mx:Script>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expensesAC}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expensesAC}"
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries
                xField="Month"
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries
                xField="Month"
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

Similarly, you can use an <mx:ArrayCollection> tag to perform the conversion:

<?xml version="1.0"?>
<!-- charts/ArrayConvertedToArrayCollectionMXML.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;

     [Bindable]
     private var expenses:Array = [
        {Month:"January", Profit:2000, Expenses:1500, Amount:450},
        {Month:"February", Profit:1000, Expenses:200, Amount:600},
        {Month:"March", Profit:1500, Expenses:500, Amount:300},
        {Month:"April", Profit:500, Expenses:300, Amount:500},
        {Month:"May", Profit:1000, Expenses:450, Amount:250},
        {Month:"June", Profit:2000, Expenses:500, Amount:700}
     ];
  ]]></mx:Script>

  <mx:ArrayCollection id="expensesAC" source="{expenses}"/>

  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" dataProvider="{expensesAC}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis 
                dataProvider="{expensesAC}" 
                categoryField="Month"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                xField="Month" 
                yField="Profit"
                displayName="Profit"
           />
           <mx:ColumnSeries 
                xField="Month" 
                yField="Expenses"
                displayName="Expenses"
           />
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

The data in ArrayCollections can be bound to the chart's data provider so that the data can be updated in real-time. The following example creates an object with elapsed time and total memory usage every second. It then pushes that new object onto an ArrayCollection that is used as the data provider for a line chart. As a result, the chart itself updates every second showing memory usage of Adobe® Flash® Player or Adobe® AIR™ over time.

<?xml version="1.0"?>
<!-- charts/RealTimeArrayCollection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize=
"initTimer()">
  <mx:Script><![CDATA[
  import flash.utils.Timer;
  import flash.events.TimerEvent;
  import mx.collections.ArrayCollection;

  [Bindable]
  public var memoryUsage:ArrayCollection = new ArrayCollection();

  public function initTimer():void {
     // The first parameter in the Timer constructor
     // is the interval, in milliseconds.
     // The second parameter is how many times to run (0 is
     // infinity).
     var myTimer:Timer = new Timer(1000, 0);

     // Add the listener for the timer event.
     myTimer.addEventListener("timer", timerHandler);
     myTimer.start();
  }

  public function timerHandler(event:TimerEvent):void {
     var o:Object = new Object();

     // Get the number of milliseconds since Flash Player or AIR started.
     o.time = getTimer();

     // Get the total memory Flash Player or AIR is using.
     o.memory = flash.system.System.totalMemory;
     trace(o.time + ":" + o.memory);

     // Add new object to the ArrayCollection, which is bound 
     // to the chart's data provider.
     memoryUsage.addItem(o);
  }
  ]]></mx:Script>

  <mx:LineChart id="chart" dataProvider="{memoryUsage}"
     showDataTips="true">
     <mx:horizontalAxis>
        <mx:LinearAxis/>
     </mx:horizontalAxis>
     <mx:verticalAxis>
        <mx:LinearAxis minimum="5000000"/>
     </mx:verticalAxis>
     <mx:series>
        <mx:LineSeries yField="memory"/>
     </mx:series>
  </mx:LineChart>
</mx:Application>

The executing SWF file for the previous example is shown below:

Data collections can be paged, which means that data is sent to the client in chunks as the application requests it. But Flex charting controls display all of the data all of the time, by default. As a result, when you use data collections with charts, you should disable the paging features or use non-paged views of the data collection for chart data. For more information on using collections, see Using Data Providers and Collections.

Using an XML file as a data provider

You can define data provider data in a structured file. The following example shows the contents of the data.xml file:

<data>
    <result month="Jan-04">
        <apple>81768</apple>
        <orange>60310</orange>
        <banana>43357</banana>
    </result>
    <result month="Feb-04">
        <apple>81156</apple>
        <orange>58883</orange>
        <banana>49280</banana>
    </result>
</data>

You can load the file directly as a source of a Model, as the following example shows:

<?xml version="1.0"?>
<!-- charts/XMLFileDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Model id="results" source="../assets/data.xml"/>
  <mx:Panel title="Line Chart">
     <mx:LineChart id="myChart" dataProvider="{results.result}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries yField="banana" displayName="Banana"/>
           <mx:LineSeries yField="apple" displayName="Apple"/>
           <mx:LineSeries yField="orange" displayName="Orange"/>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>     
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can use more complex XML to define the data provider's data. For example, an XML-based data provider can have nested tags. In that case, however, you must use a dataFunction to define the fields that the chart uses. For more information, see Structure of chart data.

To use an ArrayCollection as the chart's data provider, you convert the Model to an ArrayCollection, as the following example shows:

<?xml version="1.0"?>
<!-- charts/XMLFileToArrayCollectionDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    width="100%" height="100%">
  <mx:Script>
     import mx.utils.ArrayUtil;
  </mx:Script>

  <mx:Model id="results" source="../assets/data.xml"/>
  <mx:ArrayCollection id="myAC" 
        source="{ArrayUtil.toArray(results.result)}"
  />

  <mx:Panel title="Line Chart">
     <mx:LineChart id="myChart" dataProvider="{myAC}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries yField="banana" displayName="Banana"/>
           <mx:LineSeries yField="apple" displayName="Apple"/>
           <mx:LineSeries yField="orange" displayName="Orange"/>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>     
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also define the XML file as a URL for an HTTPService component, and then bind the HTTPService result directly to the chart's data provider, as the following example shows:

<?xml version="1.0"?>
<!-- charts/HTTPServiceDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    width="100%" height="100%" creationComplete="srv.send()">
  <mx:HTTPService id="srv" url="../assets/data.xml"/>

  <mx:Panel title="Line Chart">
     <mx:LineChart id="myChart" 
        dataProvider="{srv.lastResult.data.result}"
        showDataTips="true"
     >
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/>
           <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/>
           <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>     
  </mx:Panel>   
</mx:Application>

The executing SWF file for the previous example is shown below:

To use an ArrayCollection, you convert the HTTPService result to an ArrayCollection, as the following example shows:

<?xml version="1.0"?>
<!-- charts/HTTPServiceToArrayCollectionDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="srv.send()">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;
     [Bindable]
     public var myData:ArrayCollection;
  ]]></mx:Script>

  <mx:HTTPService 
     id="srv" 
     url="assets/data.xml" 
     useProxy="false" 
     result="myData=ArrayCollection(srv.lastResult.data.result)"
  />
  <mx:Panel title="Line Chart">
     <mx:LineChart id="myChart" dataProvider="{myData}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/>
           <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/>
           <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>     
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also set the result format of the HTTPService to E4X, and then use it as a source for an XMLListCollection object, as the following example shows:

<?xml version="1.0"?>
<!-- charts/HTTPServiceToXMLListCollection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="srv.send()">
  <mx:Script><![CDATA[
     import mx.utils.ArrayUtil;
  ]]></mx:Script>

  <mx:HTTPService id="srv"
    url="assets/data.xml"
    resultFormat="e4x"
  />

  <mx:XMLListCollection id="myAC" 
    source="{srv.lastResult.result}"
  />

  <mx:Panel title="Line Chart">
     <mx:LineChart id="myChart" dataProvider="{myAC}" showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/>
           <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/>
           <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>     
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

Randomly generating chart data

A useful way to create data for use in sample charts is to generate random data. The following example generates test data for use with the chart controls:

<?xml version="1.0"?>
<!-- charts/RandomDataGeneration.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()">
  <mx:Script><![CDATA[
     import mx.collections.*;

     // Define data provider array for the chart data.
     [Bindable]
     public var dataSet:ArrayCollection;

     // Define the number of elements in the array.
     public var dsLength:Number = 10;

     public function initApp():void {
        // Initialize data provider array.
        dataSet = new ArrayCollection(genData());
     }

     public function genData():Array {
        var result:Array = [];

        for (var i:int=0;i<dsLength;i++) {
           var localVals:Object = {
                valueA:Math.random()*100,
                valueB:Math.random()*100,
                valueX:Math.random()*100,
                valueY:Math.random()*100
           };

           // Push new object onto the data array.
           result.push(localVals);
        }
        return result;
     }
  ]]></mx:Script>

  <mx:Panel title="Plot Chart">
     <mx:PlotChart id="myChart" dataProvider="{dataSet}" showDataTips="true">
        <mx:series>
           <mx:PlotSeries 
                xField="valueX" 
                yField="valueY" 
                displayName="Series 1"
           />
           <mx:PlotSeries 
                xField="valueA" 
                yField="valueB" 
                displayName="Series 2"
           />
        </mx:series>
     </mx:PlotChart>
     <mx:Legend id="l1" dataProvider="{myChart}"/>
  </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

Structure of chart data

In most cases, the data that is used as the chart's data provider is made up of scalar values. For example, objects contain a single set of fields:

{month: "Aug", close: 45.87, open:25.19},

Or XML data contains a single set of child tags in a flat structure:

<stock>
    <month>Aug</month>
    <close>45.87</close>
    <open>25.19</open>
</stock>

In these cases, you assign the data provider's fields to items in the chart by using the xField and yField for the series, or the categoryField for the axis; for example:

<mx:ColumnSeries yField="close"/>
<mx:CategoryAxis categoryField="month"/>

However, the structure of the chart data can be made up of more complex objects, such as objects within objects or XML with nested child tags. For example, you can embed an object within an object:

{month: "Aug", close: {High:45.87,Low:12.2}, open:25.19}

Or use nested tags in an XML object:

<stock>
    <date>
        <month>Aug</month>
    </date>
    <price>
        <close>45.87</close>
        <open>25.19</open>
    </price>
</stock>

In these cases, you cannot refer to the target data by using the flat naming such as yField="close". You also cannot use dot notation. For example, yField="values.close" or categoryField="data.month" are not valid. Instead, you must use a dataFunction method to define which ChartItem fields are populated by the data provider.

For the CategoryAxis class, the dataFunction has the following signature:

function_name(axis:AxisBase, item:Object):Object

Where axis is the base class for the current axis, and item is the item in the data provider.

For the Series class, the dataFunction has the following signature:

function_name(series:Series, item:Object, fieldName:String):Object

Where series is a reference to the current series, item is the item in the data provider, and fieldName is the field in the current ChartItem that will be populated.

The following example creates two functions that access complex data for both the axis and the series:

<?xml version="1.0"?>
<!-- charts/DataFunctionExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">

  <mx:Script><![CDATA[
    import mx.charts.chartClasses.AxisBase;
    import mx.charts.chartClasses.Series;
    import mx.charts.CategoryAxis;
    import mx.charts.chartClasses.IAxis;
    import mx.charts.chartClasses.ChartBase;        
    import mx.charts.chartClasses.CartesianTransform;
    
    // This data provider contains complex, nested objects.
    [Bindable]
    public var SMITH:Array = [
        {month: "Aug", close: {High:45.87,Low:12.2}, open:25.19},
        {month: "Sep", close: {High:45.74,Low:10.23}, open:35.29},
        {month: "Oct", close: {High:45.77,Low:12.13}, open:45.19},
        {month: "Nov", close: {High:46.06,Low:10.45}, open:15.59},
    ];

    private function dataFunc(series:Series, item:Object, fieldName:String):Object {
        trace("fieldName: " + fieldName);
        if(fieldName == "yValue" && series.id=="highClose")
            return(item.close.High);
        else if(fieldName == "yValue" && series.id=="lowClose")
            return(item.close.Low);
        else if(fieldName == "xValue")
            return(item.month);
        else
            return null;
      }
    private function catFunc(axis:AxisBase, item:Object):Object {
        for (var s:String in item) {
            trace(s + ":" + item[s]);
        }
      
        return(item.month);
    }
   ]]></mx:Script>

    <mx:ColumnChart id="chart" 
        dataProvider="{SMITH}" 
        showDataTips="true" 
        width="100%" 
        height="100%"
    >
        <mx:horizontalAxis>
            <!-- The dataFunction replaces "categoryField='month'. -->
            <mx:CategoryAxis id="h1" dataFunction="catFunc"/>
        </mx:horizontalAxis>
        <mx:series>
            <!-- The dataFunction replaces yField value, which cannot drill 
            down into an object (close.High is not valid). -->
            <mx:ColumnSeries id="highClose" 
                displayName="Close (High)" 
                dataFunction="dataFunc"
            />

            <!-- The dataFunction replaces yField value, which cannot drill 
            down into an object (close.Low is not valid). -->
            <mx:ColumnSeries id="lowClose" 
                displayName="Close (Low)" 
                dataFunction="dataFunc"
            />
        </mx:series>
    </mx:ColumnChart>
</mx:Application>

The executing SWF file for the previous example is shown below:

Changing chart data at run time

Using ActionScript, you can change a charting control's data at run time by using a variety of methods.

You can change a chart or a series data provider. The following example binds the data provider to a local variable. It then toggles the chart's data provider using that local variable when the user clicks the button.

<?xml version="1.0"?>
<!-- charts/ChangeDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        public var expenses: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}
        ]);

        [Bindable]
        public var expenses2:ArrayCollection = new ArrayCollection([
            {Month:"Jan", Profit:2400, Expenses:1509, Amount:950},
            {Month:"Feb", Profit:3000, Expenses:2200, Amount:400},
            {Month:"Mar", Profit:3500, Expenses:1200, Amount:200}
        ]);

        [Bindable]
        public var dp:ArrayCollection = expenses;

        public function changeDataProvider():void {
            if (dp==expenses) {
                dp = expenses2;
            } else {
                dp = expenses;
            }
        }
    ]]></mx:Script>

    <mx:Panel title="Line Chart">
        <mx:LineChart id="myChart" dataProvider="{dp}" showDataTips="true">
            <mx:horizontalAxis>
                <mx:CategoryAxis 
                    dataProvider="{dp}" 
                    categoryField="Month"
                />
            </mx:horizontalAxis>
            <mx:series>
                <mx:LineSeries 
                    yField="Profit" 
                    displayName="Profit"
                />
                <mx:LineSeries 
                    yField="Expenses" 
                    displayName="Expenses"
                />
                <mx:LineSeries 
                    yField="Amount" 
                    displayName="Amount"
                />
            </mx:series>
        </mx:LineChart>
        <mx:Legend dataProvider="{myChart}"/>
    </mx:Panel>

    <mx:Button id="b1"
        label="Change Data Provider" 
        click="changeDataProvider()"
    />
</mx:Application>

The executing SWF file for the previous example is shown below:

You can add or remove a data point from a series. The following example adds an item to the existing data provider when the user clicks the button:

<?xml version="1.0"?>
<!-- charts/AddDataItem.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*">
    <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;
        [Bindable]
        public var dpac:ArrayCollection =  new ArrayCollection([
           {A:2000},
           {A:3000},
           {A:4000},
           {A:4000},
           {A:3000},
           {A:2000},
           {A:6000}
        ]);
    
        public function addDataItem():void {
            var o:Object = {"A":2000};
            dpac.addItem(o);
        }
        
        private function removeItem():void {
            var i:int = dpac.length;
            if (i > 0) {
                dpac.removeItemAt(i - 1);
            }
        }
    ]]></mx:Script>
  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart" 
        showDataTips="true"
        height="400" 
        width="600" 
        dataProvider="{dpac}"
     >
        <mx:series> 
            <mx:ColumnSeries yField="A" displayName="Series 1"/>
        </mx:series>
     </mx:ColumnChart>  
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>
  <mx:HBox>
      <mx:Button label="Add Data Item" click="addDataItem();"/>
      <mx:Button label="Remove Data Item" click="removeItem();"/>
  </mx:HBox>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can also change the fields of a series to change chart data at run time. You do this by changing the value of the data provider field (such as xField or yField) on the series object. To get a reference to the series, you use the series' id property or the chart control's series index. The following example toggles the data series when the user clicks on the Change Series button:

<?xml version="1.0"?>
<!-- charts/ToggleSeries.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize=
"initApp();">
  <mx:Script><![CDATA[
     [Bindable]
     public var dataSet:Array;
     public var myStates:Array =
        ["Wisconsin","Ohio","Arizona","Penn"];
     public var curSeries:String;
     public function initApp():void {
        var newData:Array = [];
        for(var i:int=0;i<myStates.length;i++) {
           newData[i] = {
             Apples: Math.floor(Math.random()*150),
             Oranges: Math.floor(Math.random()*150),
             myState: myStates[i]
           }
        }
        dataSet = newData;
        curSeries = "apples";
     }
     public function changeData():void {
        var series:Object = myChart.series[0];
        if (curSeries == "apples") {
           curSeries="oranges";
           series.yField = "Oranges";
           series.displayName = "Oranges";
           series.setStyle("fill",0xFF9933);
        } else {
           curSeries="apples";
           series.yField = "Apples";
           series.displayName = "Apples";
           series.setStyle("fill",0xFF0000);
        }
     }
  ]]></mx:Script>
  <mx:Panel title="Column Chart">
     <mx:ColumnChart id="myChart"
        dataProvider="{dataSet}"
        showDataTips="true"
     >
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{dataSet}"
                categoryField="myState"
           />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries 
                yField="Apples" 
                displayName="Apples"
            >
            <mx:fill>
                <mx:SolidColor color="0xFF0000"/>
            </mx:fill>
           </mx:ColumnSeries>
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </mx:Panel>

  <mx:Button id="b1" 
     label="Toggle Series" 
     click="changeData()"
  />

</mx:Application>

The executing SWF file for the previous example is shown below:

You can take advantage of data binding to make your chart reflect data changes in real time. The following example uses a Timer to define the intervals at which it checks for new data. Because the chart's data provider is bound to an ArrayCollection, whenever a new data point is added to the collection, the chart is automatically updated.

<?xml version="1.0"?>
<!-- charts/WatchingCollections.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    initialize="initData();">
    <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        public var dataSet:ArrayCollection;

        [Bindable]
        public var revenue:Number = 100;

        private var t:Timer;

        private function initData():void {
            dataSet = new ArrayCollection();
            t = new Timer(500);     
        }   

        private function startApp():void {
            t.addEventListener(TimerEvent.TIMER, addData);
            t.start();
        }

        private function addData(e:Event):void {
            /* Add a maximum of 100 data points before user has to click
               the Start button again. */
            if (dataSet.length > 100) {
                stopApp();
            }

            dataSet.addItem( { revenue: revenue } );
            revenue += Math.random() * 10 - 5;          
        }
        
        private function stopApp():void {
            t.stop();
            t.removeEventListener(TimerEvent.TIMER, addData);        
        }
    ]]></mx:Script>

    <mx:SeriesInterpolate id="interp"
        elementOffset="0"
        duration="300"
        minimumElementDuration="0"
    />

    <mx:Panel title="Line Chart">
        <mx:LineChart id="myChart" dataProvider="{dataSet}">
            <mx:series>
                <mx:LineSeries 
                    yField="revenue" 
                    showDataEffect="{interp}"
                    displayName="Revenue"
                />
            </mx:series>
            <mx:horizontalAxis>
                <mx:LinearAxis autoAdjust="false"/>
            </mx:horizontalAxis>
        </mx:LineChart>        
        <mx:Legend dataProvider="{myChart}"/>
    </mx:Panel>

    <mx:HBox>
        <mx:Button id="b1" label="Start" click="startApp()"/>
        <mx:Button id="b2" label="Stop" click="stopApp()"/>
    </mx:HBox>

</mx:Application>

The executing SWF file for the previous example is shown below:

You can also use system values to update charts at run time. The following example tracks the value of the totalMemory property in a LineChart control in real time:

<?xml version="1.0"?>
<!-- charts/MemoryGraph.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize=
"initTimer()">
  <mx:Script><![CDATA[
  import flash.utils.Timer;
  import flash.events.TimerEvent;
  import mx.collections.ArrayCollection;

  [Bindable]
  public var memoryUsage:ArrayCollection = new ArrayCollection();

        public function initTimer():void {
           // The first parameter in the Timer constructor
           // is the interval, in milliseconds. The second
           // parameter is how many times to run (0 is 
           // infinity).
           var myTimer:Timer = new Timer(1000, 0);

           // Add the listener for the timer event.
           myTimer.addEventListener("timer", timerHandler);
           myTimer.start();
        }

        public function timerHandler(event:TimerEvent):void {
           var o:Object = new Object();

           // Get the number of milliseconds since Flash 
           // Player started.
           o.time = getTimer();

           // Get the total memory Flash Player is using.
           o.memory = flash.system.System.totalMemory;

           // Add new object to the ArrayCollection, which 
           // is bound to the chart's data provider.
           memoryUsage.addItem(o);
        }
  ]]></mx:Script>

  <mx:LineChart id="chart" 
        dataProvider="{memoryUsage}" 
        showDataTips="true"
  >
     <mx:horizontalAxis>
        <mx:LinearAxis/>
     </mx:horizontalAxis>

     <mx:verticalAxis>
        <mx:LinearAxis minimum="5000000"/>
     </mx:verticalAxis>
     <mx:series>
        <mx:Array>
           <mx:LineSeries yField="memory"/>
        </mx:Array>
     </mx:series>
  </mx:LineChart>
</mx:Application>

The executing SWF file for the previous example is shown below:


Comments (7)


  • Hello,
      
    Not very clear on how this works. Some assistance in documentation towards explaining this should be great:
      
            <mx:Month>May</mx:Month>
            <mx:Profit>1000</mx:Profit>
            <mx:Expenses>450</mx:Expenses>
            <mx:Amount>250</mx:Amount>
      
    The tags Profit, Expenses etc are not defined as tags in the standard MXML Namespace. But the code compiles fine and does not through exception.

  • These are properties of the Object tag that contains them.  Objects are dynamic, so you can add whatever properties you want to them.  If you look at the example right above the one you're commenting on, you can see it has pretty much the identical code without using the mx namespace.

  • For the HTTPServiceToXMLListCollection example, you need to change the categoryField from "month" to "@month". This is required to access the properties properly with XML.  
      
    matt horn  
    flex docs

  • Hey All,  
      
    Very well explained doc.  
    I just wanted to know as to how can we include a scroll bar in the line chart wit the x axis.  
    Assume that My line chart has lots of data and it becomes messy to view the same, if there would be a scrollbar it would be real great.  
      
    Thanks,  
    Nimesh

  • Nimesh Sharma,
    I'm sorry, I don't know the answer to your question. In general, you will get faster and better responses to questions like this by posting them to the Adobe Flex Forums or the Flexcoders Yahoo group. These  sites receive much more traffic than single pages in the Flex online documentation.
      
    Best regards,
    Randy Nielsen
    Flex Documentation Manager
    Adobe Systems Incorporated

  • How does one use a web service to populate the data of a column chart?

  • Mike Marcavage,
    You would use mx:WebService in a way similar to the mx:HTTPService example, about halfway down the page. 

    ref:http://livedocs.adobe.com/flex/3/html/charts_intro_8.html

原文地址:https://www.cnblogs.com/zcy_soft/p/1966697.html