Home > charts, reusable components > Scrolling and zooming chart with CategoryAxis

Scrolling and zooming chart with CategoryAxis

August 7th, 2009

Title of this post is a little bit misleading because it is not possible to use ChartScroller directly with CategoryAxis. This is because ChartScroller relays on axis minimum/maximum properties which are not present in CategoryAxis. Luckily it is possible to simulate CategoryAxis behavior with LinearAxis which is supported by ChartScroller. I will describe how to do it in this post.

Simple scenario

The simplest and quite common scenario is having one data provider containing objects with single property determining category and further properties determining values of the series. Such data provider may look something like this (code copied from Flex API examples):

[Bindable]
public var dp:ArrayCollection = new ArrayCollection( [
    { Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
    { Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
    { Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
    { Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
    { Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);

In such case we have to do three things to simulate CategoryAxis behavior with LinearAxis:

  • Declare only yField property of series (not xField).
  • Create label function converting data provider index to category name.
  • Declare LinearAxis using created label function with interval property set to 1.

Label function may look like this (If xField of series is not specified Flex passes item index as labelValue so all we have to do is find correct item and return category value):

public function categoryLabelFunction(labelValue:Object,
                        previousValue:Object, axis:IAxis):String
{
    var index:int = int(labelValue);

    if (index >= 0 && index < dp.length)
        return dp[index].Month;
    return "";
}

As you can see chart MXML code is only slightly modified compared to code using standard CategoryAxis:

<mx:ColumnChart id="columnChart" width="100%" height="100%"
    gutterLeft="50" gutterRight="40" dataProvider="{dp}">
    <mx:series>
        <!-- Note that xField is not specified -->
        <mx:ColumnSeries yField="Profit" />
        <mx:ColumnSeries yField="Expenses" />
        <mx:ColumnSeries yField="Amount" />
    </mx:series>
    <mx:horizontalAxis>
        <!-- LinearAxis simulating CategoryAxis -->
        <mx:LinearAxis interval="1"
            labelFunction="categoryLabelFunction" />
    </mx:horizontalAxis>
</mx:ColumnChart>

View source is enabled, you can download zipped sources from here.

More complex scenario

In some cases you may need to use xField series properties. For example you may be using separate data providers of different length for different series. In such case additional parse function have to be created to convert category name to numeric value which can be placed along LinearAxis. You can find full example of such scenario here.

View source is enabled, you can download zipped sources from here.

  1. nyeh
    August 12th, 2009 at 15:09 | #1

    It looks nice. I wonder if ChartScroller will work with dynamic dataProvider binding?

  2. Iwo Banas
    August 12th, 2009 at 15:22 | #2

    It should work without any problems.
    Notice that changing dataProvider will not reset axis minimum/maximum values so if you want a to have axis minimum/maximum values adjusted to data (so that all data are visible) you may have to set them to NaN after dataProvider is changed.

  3. Tiago
    August 19th, 2009 at 22:49 | #3

    Good afternoon Friend, His/her work was very good… I don’t only know like you would do to put the showDataTips = “true” and to bring the category of each column. Could he/she become trained?

  4. Iwo Banas
    August 19th, 2009 at 23:00 | #4

    Hi Tiago,
    Try using dataTipFunction
    http://livedocs.adobe.com/flex/3/langref/mx/charts/chartClasses/ChartBase.html#dataTipFunction
    hitData.item should contain data related to the given column so you should be able to extract column name (category) easily.

  5. Nimesh
    August 31st, 2009 at 13:26 | #5

    Hey Iwo,
    great work … I am using dataprovider from backend, bt the vertical axis for me shows from 0 to 100 (inspite of me having data greater than 100) … do i have to set some property for the same ..
    Thanks,
    cheers,

  6. Iwo Banas
    August 31st, 2009 at 19:43 | #6

    Hi Nimesh,
    0/100 is the default minimum/maximum of linear axis. I can’t tell you why this values are preserved without having a look at your code, but I can give you a workaround: Set the vertical axis minimum/maximum values to NaN after dataProvider is changed, this should cause axis range to be adjusted to data.

  7. Omer
    September 9th, 2009 at 13:10 | #7

    Hi,
    Is it possible to use this on LineChart? I tired and I got vertical line only.
    Thanks

  8. Iwo Banas
    September 9th, 2009 at 15:10 | #8

    Hi Omer,
    I tested it on the example above, by changing ColumnChart to LineChart and ColumnSeries to LineSeries, and it works.
    Only horizontal axis looks different, but previous look can be restored by setting horizontalAxisStyleName="blockNumericAxis" on LineChart or by creating axis renderer with styleName="blockNumericAxis".

  9. January 8th, 2010 at 15:29 | #9

    Can any one let me know how to prevent the X-axis scrolling if there is no data further or earlier than first node?
    Because it is continue to scrolling even if there is no data?

    Thanks in Advance.

  10. Iwo Banas
    January 31st, 2010 at 22:30 | #10

    For now there is no such feature. In my project we quite often scroll beyond the data and than fetch remaining data. It would be possible to define global minimum/maximum which will block further scrolling but I don’t have time to do it… I’ve just changed the job and moved and I’m really busy…

  11. Newbie
    March 22nd, 2010 at 13:20 | #11

    hi, you wrote nice code it helps me a lot. but i find a small problem. Replace dataprovider to the following and find some undesired results.
    [Bindable]
    public var dp:ArrayCollection = new ArrayCollection
    ([{ Month: "Jan", Profit: 2000} ]);

    you will find that loop goes on some 100 times(100 traces) and chart includes only 1 thin line on left hand side corner.

  12. Julien
    May 20th, 2010 at 18:14 | #12

    Hi,

    I’ve tried your code on a LineChart, and it works amazingly. I’ve modified the labelFunction and parseFunction for the horizontal axis in order to get a DD/MM dateformat. Unfortunately, I got a disturbing issue : when I ZoomOut too much, the order of my dates is inversed (from right to left) whereas the Graph stays the same… What sould I do?

    Thank you in advance

  1. No trackbacks yet.