6 Replies Latest reply on Oct 5, 2010 12:13 PM by Devtron

    Why does FLEX LineChart render before HTTPService object request supplies data

    Devtron Level 3

      Hello,

       

      I am having trouble binding a LineChart to XML data via HTTPService object.

       


      Here is my code:

       

          <mx:Panel 
              xmlns:mx="http://www.adobe.com/2006/mxml"
              xmlns:ui="flex.utils.ui.*"
              xmlns:charts="flex.utils.ui.charts.*"
              layout="vertical" horizontalAlign="center" verticalGap="2" paddingBottom="0" paddingTop="10" xmlns:local="*"
              creationComplete="getChartDataSrv.send();"
              >
             
              <mx:HTTPService id="getChartDataSrv" result="onResult(event)"  url="http://localhost:8060/BusinessServiceLayer/DataService.asmx/GetDeviceDatasetsByDateGranula r?xxxxxxxx" />
             
              <mx:Script>
                  <![CDATA[
                      import flex.utils.ui.events.CheckBoxLegendItemChangedEvent;
                      import mx.collections.ArrayCollection;
                      import mx.rpc.events.ResultEvent;
                      import mx.controls.Alert;
                     
                      [Bindable]
                      private var deviceData:ArrayCollection;
                     
                      private var deviceData2:ArrayCollection;
                     
                      private function legendItemChanged(event:CheckBoxLegendItemChangedEvent):void {
                          var txt:String = "legendItemChanged: " + event.legendItem.label +
                              " [" + (event.legendItemSelected ? "selected]" : "not selected]");
                          trace(txt);
                          changeLabel.text = txt;
                         
                          // update the vertical axis minimum/maximum values to ignore the hidden series
                          if (updateMinMaxCB.selected) {
                              updateVerticalAxisMinMax();
                          }
                      }
                     
                      private function updateVerticalAxisMinMax():void {
                          var max:Number = 0;
                          var min:Number = 0;
                          var count:int = 0;
                          for each (var series:LineSeries in linechart.series) {
                              if (series.visible) {
                                  // contains LineSeriesItem objects
                                  var items:Array = series.items;
                                  // Get the min and max y values for each item from the yNumber property
                                  var minMax:Array = getMinMax(items, "yNumber");
                                  min = Math.min(min, minMax[0]);
                                  max = Math.max(max, minMax[1]);
                                  count++;
                              }
                          }
                          if (count > 0) {
                              // change the min/max to the next interval
                              max = Math.ceil(max / vAxis.interval) * vAxis.interval;
                              min = Math.floor(min / vAxis.interval) * vAxis.interval;
                              //set the new minimum/maxmimum values
                              vAxis.maximum = max;
                              vAxis.minimum = min;
                          }
                      }
                     
                      private function getMinMax(items:Array, field:String = null):Array {
                          var min:Number = 0;
                          var max:Number = 0;
                          for each (var item:* in items) {
                              if (item) {
                                  var num:Number = NaN;
                                  if (field && item.hasOwnProperty(field)) {
                                      num = Number(item[field]);
                                  } else {
                                      num = Number(item);
                                  }
                                  if (!isNaN(num)) {
                                      max = Math.max(max, num);
                                      min = Math.min(min, num);
                                  }
                              }
                          }
                          return [ min, max ];
                      }
                     
                      private function updateMinMaxCBClicked(event:Event):void {
                          if (updateMinMaxCB.selected) {
                              updateVerticalAxisMinMax();
                          } else {
                              // reset the minimum & maximum values so that the axis will calculate them properly
                              vAxis.minimum = NaN;
                              vAxis.maximum = NaN;
                          }
                      }
                     
                      private function swapDataProvider():void {
                          if (changeDataBtn.selected) {
                              linechart.dataProvider = deviceData2;
                          } else {
                              linechart.dataProvider = deviceData;
                          }
                          // validate first, then update the vertical axis min/max values
                          linechart.validateNow();
                          if (updateMinMaxCB.selected) {
                              updateVerticalAxisMinMax();
                          }
                      }
         
                      private function onResult(evt:ResultEvent):void {
                          linechart.dataProvider = evt.result.ArrayOfDAIX.DAIX;
                          linechart.invalidateDisplayList();
                      }
                     
                  ]]>
              </mx:Script>
             
              <mx:Stroke id = "s1" color="haloGreen"  weight="2"/>
              <mx:Stroke id = "s2" color="haloOrange" weight="2"/>
              <mx:Stroke id = "s3" color="haloBlue" weight="2"/>
              <mx:Stroke id = "s4" color="red" weight="2"/>
              <mx:Stroke id = "s5" color="yellow" weight="2"/>
             
              <mx:Label text="LineChart with CheckBox Legend" color="0xffffff"
                        fontSize="14" textDecoration="underline" fontWeight="bold"/>
             
              <mx:VBox enabled="true" paddingTop="10" paddingRight="5" paddingBottom="10" paddingLeft="5"
                       backgroundColor="white" width="100%" height="100%" horizontalAlign="center">
                  <mx:LineChart id="linechart" color="#FDFDFD" width="100%" height="100%"
                                showDataTips="true" dataProvider="{getChartDataSrv.lastResult.ArrayOfDAIX.DAIX}">
                      <mx:horizontalAxis>
                          <mx:CategoryAxis categoryField="w"/>
                      </mx:horizontalAxis>
                      <mx:verticalAxis>
                          <mx:LinearAxis id="vAxis"/>
                      </mx:verticalAxis>
                      <mx:series>               
                          <mx:LineSeries yField="v1" form="curve" displayName="Column 1" lineStroke="{s1}"/>
                          <mx:LineSeries yField="v2" form="curve" displayName="Column 2" lineStroke="{s2}"/>
                          <mx:LineSeries yField="v3" form="curve" displayName="Column 3" lineStroke="{s3}"/>
                          <mx:LineSeries yField="v4" form="curve" displayName="Column 4" lineStroke="{s4}"/>
                          <mx:LineSeries yField="v5" form="curve" displayName="Column 5" lineStroke="{s5}"/>
                      </mx:series>
                  </mx:LineChart>
                 
                  <ui:TitledBorderBox title="Legend" borderColor="#666666" id="legendBox">
                      <charts:CheckBoxLegend dataProvider="{linechart}" color="white" direction="vertical"
                                             toggleChartSeries="true" change="legendItemChanged(event)" id="legend"/>
                  </ui:TitledBorderBox>
                 
              </mx:VBox>
             
              <mx:Label id="changeLabel" color="#ffffff"/>
              <mx:HBox horizontalAlign="left">
                  <mx:CheckBox id="cb" selected="true" label="{cb.selected ? 'Select None' : 'Select All'}"
                               click="legend.selectAllOrNone(cb.selected)"/>
                  <mx:Spacer width="10" height="10"/>
                  <mx:CheckBox label="Update Vertical Axis Min/Max?" id="updateMinMaxCB"
                               toolTip="Check this box to update the vertical axis minimum and maximum values when the legend items change"
                               change="updateMinMaxCBClicked(event)"/>
              </mx:HBox>
              <mx:Button label="Change Data" toggle="true" id="changeDataBtn" click="swapDataProvider()"
                         toolTip="Change the data provider to a different set of values"/>
         
          </mx:Panel>

       

       

       

      Originally I had written a static array of data, to get this example working. It worked fine, until I made the HTTPService object and appropriate WebService calls.

       

      When I debug this code, I can see that my HTTPService object is returning the array correctly, it has 96 items, which is desired.

       

      The problem is, the LineChart graph is already rendered to the browser, and I cannot get my data into my LineChart. The static array worked fine but I am at a loss on why it will not work with my ResultEvent and HTTPService object.

       

      **Why can I not bind my Chart within my ResultEvent, or directly, with the result object?** Even if I explicitly set the dataprovider of "linechart" (in the ResultEvent method) it does not update the LineChart data.

       

      Also, if I use "linechart.invalidateDisplayList();", it too does not populate or redraw my LineChart. Is that because it's contained within a Panel?

       

      Any ideas? Also, take note that this is all happening within a Panel and not within an Application. I cannot use Application tags on this component, so I am fairly confused about this. Why does the LineChart render first, and then my HTTPService produce the data the Chart will not use?

        • 1. Re: Why does FLEX LineChart render before HTTPService object request supplies data
          Balakrishnan V Level 3

          On the result handler, use a [Bindable] data:ArrayCollection to store the event.result as ArrayCollection. Set the dataprovider property of the LineChart to this data:ArrayCollection. (This should work)

           

          You cannot bind the result to the dataProvider directly because, the creation of the the LineChart happens at the same time as the creation of the panel and the sending of the HTTPService.

           

          Tell me if you would need more details .

           

          balakrishnan v

          • 2. Re: Why does FLEX LineChart render before HTTPService object request supplies data
            Flex Rock Level 1

            Why does FLEX LineChart render before HTTPService object request supplies data

             

            You just remove the data proivder property from the design tag. Because it will be compiled before compiling your creation complete.Thats why you are getting the error.Just bind the data in Result event.

            • 4. Re: Why does FLEX LineChart render before HTTPService object request supplies data
              Devtron Level 3

              Balakrishnan, I understand what you mean, but that did not work either.

              • 5. Re: Why does FLEX LineChart render before HTTPService object request supplies data
                Devtron Level 3

                Here is my newest code, which is not working: Maybe it has something to do with Initialize and Pre-Initialize? Maybe I need to remove the dataProvider attribute from the LineChart tag? I dont know but this is overly complicated for something that should be quite easy.

                 

                 

                <?xml version="1.0"?>
                <mx:Panel 
                    xmlns:mx="http://www.adobe.com/2006/mxml"
                    xmlns:ui="flex.utils.ui.*"
                    xmlns:charts="flex.utils.ui.charts.*"
                    layout="vertical" horizontalAlign="center" verticalGap="2" paddingBottom="0" paddingTop="10" xmlns:local="*"
                    preinitialize="OnCreationComplete();"
                    >   
                    <mx:HTTPService result="onResult(event)" id="getChartDataSrv" url="http://localhost:8060/BusinessServiceLayer/DataService.asmx/myDataServiceXXX?XXXXXX" />
                   
                    <mx:Script>
                        <![CDATA[
                            import flex.utils.ui.events.CheckBoxLegendItemChangedEvent;
                            import mx.collections.ArrayCollection;
                            import mx.rpc.events.ResultEvent;
                            import mx.controls.Alert;
                           
                            [Bindable]
                            private var deviceData:ArrayCollection;
                            [Bindable]
                            private var deviceData2:ArrayCollection;           
                           
                            private function legendItemChanged(event:CheckBoxLegendItemChangedEvent):void {
                                var txt:String = "legendItemChanged: " + event.legendItem.label +
                                    " [" + (event.legendItemSelected ? "selected]" : "not selected]");
                                trace(txt);
                                changeLabel.text = txt;
                               
                                // update the vertical axis minimum/maximum values to ignore the hidden series
                                if (updateMinMaxCB.selected) {
                                    updateVerticalAxisMinMax();
                                }
                            }
                           
                            private function updateVerticalAxisMinMax():void {
                                var max:Number = 0;
                                var min:Number = 0;
                                var count:int = 0;
                                for each (var series:LineSeries in linechart.series) {
                                    if (series.visible) {
                                        // contains LineSeriesItem objects
                                        var items:Array = series.items;
                                        // Get the min and max y values for each item from the yNumber property
                                        var minMax:Array = getMinMax(items, "yNumber");
                                        min = Math.min(min, minMax[0]);
                                        max = Math.max(max, minMax[1]);
                                        count++;
                                    }
                                }
                                if (count > 0) {
                                    // change the min/max to the next interval
                                    max = Math.ceil(max / vAxis.interval) * vAxis.interval;
                                    min = Math.floor(min / vAxis.interval) * vAxis.interval;
                                    //set the new minimum/maxmimum values
                                    vAxis.maximum = max;
                                    vAxis.minimum = min;
                                }
                            }
                           
                            private function getMinMax(items:Array, field:String = null):Array {
                                var min:Number = 0;
                                var max:Number = 0;
                                for each (var item:* in items) {
                                    if (item) {
                                        var num:Number = NaN;
                                        if (field && item.hasOwnProperty(field)) {
                                            num = Number(item[field]);
                                        } else {
                                            num = Number(item);
                                        }
                                        if (!isNaN(num)) {
                                            max = Math.max(max, num);
                                            min = Math.min(min, num);
                                        }
                                    }
                                }
                                return [ min, max ];
                            }
                           
                            private function updateMinMaxCBClicked(event:Event):void {
                                if (updateMinMaxCB.selected) {
                                    updateVerticalAxisMinMax();
                                } else {
                                    // reset the minimum & maximum values so that the axis will calculate them properly
                                    vAxis.minimum = NaN;
                                    vAxis.maximum = NaN;
                                }
                            }
                           
                            private function swapDataProvider():void {
                                if (changeDataBtn.selected) {
                                    linechart.dataProvider = deviceData2;
                                } else {
                                    linechart.dataProvider = deviceData;
                                }
                                // validate first, then update the vertical axis min/max values
                                linechart.validateNow();
                                if (updateMinMaxCB.selected) {
                                    updateVerticalAxisMinMax();
                                }
                            }
                           
                            protected function OnCreationComplete():void
                            {
                               
                                BindChartData();
                               
                                deviceData2 = new ArrayCollection();
                                deviceData2.addItem({v1: 13.19, v2: 42.44, v3: 23.33, v4: 16.67, v5: 48.42, w: '2010-07-28T00:00:00'});
                                deviceData2.addItem({v1: 11.19, v2: 32.44, v3: 21.33, v4: 18.68, v5: 54.42, w: '2010-07-28T00:15:00'});
                                deviceData2.addItem({v1: 13.19, v2: 14.14, v3: 13.33, v4: 19.61, v5: 50.42, w: '2010-07-28T00:30:00'});
                                deviceData2.addItem({v1: 14.19, v2: 54.10, v3: 13.33, v4: 21.22, v5: 46.42, w: '2010-07-28T00:45:00'});
                               
                            }
                           
                            private function onResult(evt:ResultEvent):void {
                                deviceData = new ArrayCollection();
                                deviceData = evt.result.ArrayOfDAIX.DAIX;   
                                linechart.dataProvider = deviceData;
                                linechart.invalidateDisplayList();
                            }
                           
                            private function BindChartData():void{
                                getChartDataSrv.send();
                            }
                           
                        ]]>
                    </mx:Script>
                   
                    <mx:Stroke id = "s1" color="haloGreen"  weight="2"/>
                    <mx:Stroke id = "s2" color="haloOrange" weight="2"/>
                    <mx:Stroke id = "s3" color="haloBlue" weight="2"/>
                    <mx:Stroke id = "s4" color="red" weight="2"/>
                    <mx:Stroke id = "s5" color="yellow" weight="2"/>
                   
                    <mx:Label text="LineChart with CheckBox Legend" color="0xffffff"
                              fontSize="14" textDecoration="underline" fontWeight="bold"/>
                   
                    <mx:VBox id="myVBOX" enabled="true" paddingTop="10" paddingRight="5" paddingBottom="10" paddingLeft="5"
                             backgroundColor="white" width="100%" height="100%" horizontalAlign="center">
                        <mx:LineChart id="linechart" color="#FDFDFD" width="100%" height="100%" showDataTips="true" dataProvider="{deviceData}">
                            <mx:horizontalAxis>
                                <mx:CategoryAxis categoryField="w"/>
                            </mx:horizontalAxis>
                            <mx:verticalAxis>
                                <mx:LinearAxis id="vAxis"/>
                            </mx:verticalAxis>
                            <mx:series>               
                                <mx:LineSeries yField="v1" form="curve" displayName="Indoor Temp" lineStroke="{s1}"/>
                                <mx:LineSeries yField="v2" form="curve" displayName="Outdoor Temp" lineStroke="{s2}"/>
                                <mx:LineSeries yField="v3" form="curve" displayName="Cool Point" lineStroke="{s3}"/>
                                <mx:LineSeries yField="v4" form="curve" displayName="Heat Point" lineStroke="{s4}"/>
                                <mx:LineSeries yField="v5" form="curve" displayName="Humidity" lineStroke="{s5}"/>
                            </mx:series>
                        </mx:LineChart>
                       
                        <ui:TitledBorderBox title="Legend" borderColor="#666666" id="legendBox">
                            <charts:CheckBoxLegend dataProvider="{linechart}" color="white" direction="vertical"
                                                   toggleChartSeries="true" change="legendItemChanged(event)" id="legend"/>
                            <!-- if you set toggleChartSeries="false" then the series won't be automatically hidden
                            and you can handle the change event in the above legendItemChanged function -->
                        </ui:TitledBorderBox>
                       
                    </mx:VBox>
                   
                    <mx:Label id="changeLabel" color="#ffffff"/>
                    <mx:HBox horizontalAlign="left">
                        <mx:CheckBox id="cb" selected="true" label="{cb.selected ? 'Select None' : 'Select All'}"
                                     click="legend.selectAllOrNone(cb.selected)"/>
                        <mx:Spacer width="10" height="10"/>
                        <mx:CheckBox label="Update Vertical Axis Min/Max?" id="updateMinMaxCB"
                                     toolTip="Check this box to update the vertical axis minimum and maximum values when the legend items change"
                                     change="updateMinMaxCBClicked(event)"/>
                    </mx:HBox>
                    <mx:Button label="Change Data" toggle="true" id="changeDataBtn" click="BindChartData()"
                               toolTip="Change the data provider to a different set of values"/>
                    <mx:Button label="Get Data" toggle="true" id="getDataBtn" click="BindChartData()"
                               toolTip="Get the data provider"/>
                   
                </mx:Panel>

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                As you can see, I use deviceData, a bindable array collection, that get's instantiated and loaded in the ResultEvent (listener event) for the Web Service call. The data is valid and it is present in my ArrayCollection. My problem is that the grid does not load any data, or redraw with any data in it.

                • 6. Re: Why does FLEX LineChart render before HTTPService object request supplies data
                  Devtron Level 3

                  I remembered I fixed this by using the correct field names in my LineSeries.

                   

                  Yes, they are case sensitive. I needed to make "v1" actually "V1". LAME!!! I KNOW!!

                   

                  No, FLEX does not tell you that, nor does it error or give you any warnings about your LineSeries field names being incorrect.

                   

                  Very much like Javascript, you just guess at it.