views:

52

answers:

1

I have a problem zooming in on a line chart with a dateTimeAxis as horizontal axis. I want to zoom in and out, by setting the minimum and the maximum attribute of the dateTimeAxis with a slider. The date labels change as should, but the lines disappear as I set the minimum or the maximum.

Here's a part of the code I have:

private function updateBoundariesFromSlider():void
        {
            leftBoundary = slider.values[0];
            rightBoundary = slider.values[1];
            updateMainData();
        }

        private function updateMainData():void
        {

            dateAxis.minimum = new Date(leftBoundary);
            dateAxis.maximum = new Date(rightBoundary);

        }


public function setChartData( data:XML, shown:Array, minDate:Date, maxDate:Date ):void
        {
            globalLeftBoundary = minDate.getTime();
            globalRightBoundary = maxDate.getTime();
            leftBoundary = minDate.getTime();
            rightBoundary = maxDate.getTime();

            for each( var s:String in shown )
            {
                var localXML:XMLList = data.track.(type == s);

                // Create the new series and set its properties.
                var localSeries:LineSeries = new LineSeries();
                localSeries.dataProvider = localXML;
                localSeries.yField = "value";
                localSeries.xField = "time";

                localSeries.displayName = s;

                mySeries.push(localSeries);


            }


            hAxis = new DateTimeAxis();

            hAxis.dataUnits = "minutes";
            hAxis.dataInterval = 1;
            hAxis.labelFunction = showLabel;
            hAxis.alignLabelsToUnits = true;
            hAxis.parseFunction = createDate;
            //hAxis.minimum = new Date( leftBoundary );
            //hAxis.maximum = new Date( rightBoundary );
            Alert.show( (new Date( leftBoundary )).toString());

            dateAxis = hAxis;
        }

        private function createDate(s:String):Date {

            var dateTime:Array = s.split(" ");

            var date:Array = dateTime[0].split("-");
            var time:Array = dateTime[1].split(":");

            var newDate:Date = new Date(date[0],date[1],date[2],time[0],time[1],time[2]);
            return newDate;
        }


<mx:LineChart id="lineChart" left="10" top="10" bottom="47" right="10" series="{mySeries}" horizontalAxis="{dateAxis}" />

<mx:Legend dataProvider="{lineChart}" height="23" bottom="16" left="10" id="legend" width="100"/>
<flexlib:HSlider id="slider" height="25"
                allowTrackClick="true" allowThumbOverlap="false" 
                liveDragging="true" change="updateBoundariesFromSlider()"
                showDataTip="false"
                showTrackHighlight="true"
                thumbCount="2" snapInterval="0"
                values="{[leftBoundary, rightBoundary]}"
                minimum="{globalLeftBoundary}" maximum="{globalRightBoundary}"
                right="50" left="198" y="155"
                />
+1  A: 

I had an application with a similar chart zooming requirement, and I found that filtering the charts data provider based of the upper and lower bounds looks much better than modifying the minimum and maximum on the charts horizontal axis. Here is a simple, working example (Flex 3, UPDATE 6-29-10: Modified example to use XMLListCollection):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="vertical" initialize="{init()}"
>

    <mx:Script>
        <![CDATA[
            import mx.collections.XMLListCollection;
            import mx.collections.ArrayCollection;
            public static const MIN_DATE:Number = 1900;
            public static const MAX_DATE:Number = 2010;

            public var mainData:XML = function():XML{
                var ret:XML = <data></data>;
                for(var i:Number = MIN_DATE;
                    i <= MAX_DATE; i++)
                {
                    ret.appendChild(
                        XMLList(
                            '<datum><date>' 
                                + i + 
                                '</date><value>' 
                                + Math.random() + 
                            '</value></datum>'
                        )
                    );
                }
                return ret;
            }();

            [Bindable]
            public var selectedData:XMLListCollection = 
                    new XMLListCollection(mainData.child('datum'));

            public function init():void
            {
                selectedData.filterFunction = filterData;
                selectedData.refresh();
            }

            private function filterData(o:Object):Boolean
            {
                return o.date >= minStepper.value && o.date <= maxStepper.value;
            }
        ]]>
    </mx:Script>


    <mx:LineChart 
        id="lineChart" 
        dataProvider="{selectedData}"
    >
        <mx:horizontalAxis>
            <mx:DateTimeAxis 
                id="hAxis" 
                parseFunction="{
                    function(obj:Object):Date
                    {
                        return new Date(obj.toString(), 1);
                    }
                }"
            />
        </mx:horizontalAxis>
        <mx:verticalAxis>
            <mx:LinearAxis 
                id="vAxis" 
            />
        </mx:verticalAxis>
        <mx:series>
            <mx:LineSeries 
                xField="date" 
                yField="value" 
            />
        </mx:series>
    </mx:LineChart>
    <mx:HBox>
        <mx:NumericStepper 
            id="minStepper" 
            minimum="{MIN_DATE}" 
            maximum="{Math.min(maxStepper.value - 1, MAX_DATE)}" 
            change="{selectedData.refresh();}"
            value="{MIN_DATE}"
        />
        <mx:NumericStepper id="maxStepper" 
            maximum="{MAX_DATE}" 
            minimum="{Math.max(minStepper.value + 1, MIN_DATE)}" 
            change="{selectedData.refresh();}"
            value="{MAX_DATE}"
        />
    </mx:HBox>

Ryan Lynch
The problem is i have my data in xml, not ArrayCollection :(
Biroka
An array collection wraps an Array, an XMLListCollection wraps an XMLList. Both are ListCollectionView's, and both can take a filter function. I've updated the example above to use an XMLListCollection instead of an ArrayCollection.
Ryan Lynch