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

Scrolling and zooming chart with CategoryAxis

August 7th, 2009 Leave a comment Go to comments

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

  13. June 23rd, 2010 at 11:46 | #13

    Hi,
    I observed that when you scroll too much the line chart is compressed and the category labels skip I mean they are displayed at intervals.How can I avoid this?

    Thanks and help will be appreciated

  14. Brian1
    July 8th, 2010 at 19:27 | #14

    Hey , pretty cool!

    But there is a problem. If you have millions value and don’t want to show everything when you zoom in and out, i mean how could we filter out values, so it doesn’t get heavy to pan or zoom?

    I know there is an algorithm call Douglas_Peucker for simplify lines that can be used. But don’t know how to implement it or where..
    How can we me make an function like google stockschart where it depends on the period you chose ?

    Sorry my bad french

    /Thanks

  15. Bran Singstom
    July 18th, 2010 at 15:10 | #15

    Now how can it been modified so that the bars doesn’t disappear when you pan at some direction like its doing now? where in the code is preventing it to be draw all the data, even if its outside the visible area?

    Thanks!

  16. Indu
    August 24th, 2010 at 12:14 | #16

    Hi,
    I would like to know whether i could dynamically change the dataprovider elements.
    i.e instead of – return dp[index].Month;
    how can i access the Month dynamically?

  17. Indu
    August 24th, 2010 at 12:24 | #17

    Hi,
    I would like to know whether i could dynamically change the dataprovider elements.
    i.e instead of – return dp[index].Month;
    how can i change the Month dynamically?

  18. Matias
    January 27th, 2011 at 16:37 | #18

    Hi Iwo.

    You Example works fine, great work, i’m noobie en flex, so, when you do the categoryLabelFunction to use linear axis like a Category axis, if i change the id of array Data provider to my var that take data from RemoteObj Mysql DB, the application Run but don’t finish to charge, don’t see nothing, mi remote connection run fine, because i can populate a Data grid.

    my data provider:

    private var datos:ArrayCollection;

    [Bindable]
    private var datos2:Array;

    private function onInit():void
    {
    miServicio.test_chart.send();
    }

    private function onResult():void
    {
    datos= miServicio.test_chart.lastResult;
    datos2=datos.source;
    dGrid.selectedIndex=0;
    }

    Your Function with my dataprovider Var:

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

    if (index >= 0 && index < datos2.length)

    return datos2[index].fechacompra;
    return "";
    }

    fechacompra is my category axis row, i tried with "datos" and "datos2" no errors, but the application doesn't run.

    Thank you for your time

  19. Alex
    April 13th, 2011 at 14:50 | #19

    Hi, Iwo!
    Thanks for great solution.
    Could you please hint what is the best way to implement datetimeaxis horizontal scrolling within disabled date ranges ?

  20. May 15th, 2011 at 03:21 | #20

    will category version of chart scroller work with flex 4?

    Thanks

  21. the_new_mr
    September 1st, 2011 at 14:32 | #21

    Beautiful Iwo!

    Works a charm!

    I changed the component a little bit so that the user can click to zoom and ctrl+click to zoom out. I shall mail you the changes (though it’s not much).

    Thanks again.

  22. Raheel
    September 10th, 2011 at 19:21 | #22

    How i can handle disable ranges with scrolling and zooming? any body plz help me

  1. No trackbacks yet.