0 Replies Latest reply on Jun 16, 2010 4:03 PM by Peter Chaim Weinstein

    charts in Flex 3 compatibility mode are hosed

    Peter Chaim Weinstein

      I spent an 11 hour day struggling to get a LineChart working in Flex 3 compatibility mode that worked fine otherwise. I encountered a multitude of problems, spent hours tracing through Flex code, and finally have something almost working except for minor details like the horizontal axis insists on displaying on the top only (and the vertical on the right) even if I use the axis renderer placement tags to specify otherwise (and with any other values except "bottom" and "left" the data does not draw properly!). To give you a feeling for what I learned, a major breakthrough was setting gutters explicitly (the data points were calculated as NaN otherwise).

       

      If someone could suggest what might need setting to get the axes to display where I want them to I will be very grateful.

       

      To summarize -- LineCharts appear to be badly broken in Flex 3 compatibility mode.

       

      If an Adobe developer would like to verify, here is my source, including an example of the data I'm using. I posted earlier today wondering what the situation is and give some more details there.

       

      Thanks, Peter (peterw@umich.edu)

       

      <?xml version="1.0"?>
      <!-- charts/BasicLine.mxml -->
      <mx:Application
          xmlns:mx="http://www.adobe.com/2006/mxml"
          xmlns:bwc="*"
          creationComplete="initialization()"
          width="1200" height="800" layout="absolute" >       
         
          <mx:Label id="titleLabel" x="30" y="10" text="Progress Chart for " fontSize="16" />
          <!--mx:Label id="measureLabel" x="688" y="25" text="Measure:" fontSize="12" width="67"/-->
          <mx:ComboBox id="measureCombo" x="300" y="14" width="300" dataProvider="{patientMeasureNames}"
                       editable="false" change="loadPatientData()" />   
          <mx:SolidColorStroke id="axisStroke"
                               color="#000000"
                               weight="2"
                               alpha="1"
                               caps="square" />
          <mx:SolidColorStroke id="tickStroke"
                               color="#000000"
                               weight="1"
                               alpha="1" />
          <mx:SolidColorStroke id="minorTickStroke"
                               color="#000000"
                               weight="1"
                               alpha="1" />
          <mx:SolidColorStroke id="dataStroke"
                               color="0x11538C"
                               weight="3"
                               alpha="1" />
          <mx:Canvas id="chartCanvas" x="30" y="50" width="600" height="500" borderStyle="solid" >
              <mx:LineChart id="progressChart" x="10" y="10" width="550" height="450"
                            dataProvider="{patientData}"
                            showDataTips="true"     
                            horizontalAxisStyleNames="{styleNames}" verticalAxisStyleNames="{styleNames}"
                            gutterBottom="10" gutterLeft="10" gutterRight="10" gutterTop="10" gridLinesStyleName=""
                            >
                  <mx:annotationElements>
                      <mx:CartesianDataCanvas id="annotationCanvas" includeInRanges="true"  width="800" height="400"/>
                  </mx:annotationElements>
                  <mx:horizontalAxis>
                      <mx:DateTimeAxis id="hAxis" parseFunction="makeDateFromString"
                                       alignLabelsToUnits="true" displayLocalTime="true"
                                       title="" labelFunction="formatDateLabel" maximum="{maxDate}"
                                        /> <!--  -->
                  </mx:horizontalAxis>
                  <mx:verticalAxis>
                      <mx:LinearAxis id="vAxis" interval="1" maximum="{this.maxValue}" title="" /> <!--  -->
                  </mx:verticalAxis>
                  <mx:series>
                      <bwc:BwcLineSeries xField="date" yField="value" displayName="(measure)" stroke="{dataStroke}"
                                     itemRenderer="mx.charts.renderers.CircleItemRenderer"
                                     lineSegmentRenderer="mx.charts.renderers.LineRenderer"
                                      width="700" height="350" lineStroke="{dataStroke}" radius="4"
                                     >
                      </bwc:BwcLineSeries>               
                  </mx:series>
                  <mx:seriesFilters>
                      <mx:Array/>
                  </mx:seriesFilters>
                  <mx:horizontalAxisRenderers>
                      <mx:AxisRenderer axis="{hAxis}"
                                       axisStroke="{axisStroke}" tickStroke="{tickStroke}" minorTickStroke="{minorTickStroke}"
                                       showLine="true" showLabels="true" labelRenderer="mx.charts.chartClasses.ChartLabel"
                                       placement="bottom" tickPlacement="cross" tickLength="5" fontSize="12"
                                       />
                  </mx:horizontalAxisRenderers>           
                  <mx:verticalAxisRenderers>
                      <mx:AxisRenderer axis="{vAxis}"
                                       axisStroke="{axisStroke}" tickStroke="{tickStroke}" minorTickStroke="{minorTickStroke}"
                                       showLine="true" showLabels="true" labelRenderer="mx.charts.chartClasses.ChartLabel"
                                       placement="left" tickPlacement="cross" tickLength="5" fontSize="12"
                                       />
                  </mx:verticalAxisRenderers>
              </mx:LineChart>
              <!--mx:Legend id="chartLegend"
                         x="20" y="{chartCanvas.height - chartLegend.height - 20}"
                         dataProvider="{progressChart}" /-->
          </mx:Canvas>
         
          <mx:Script>
              <![CDATA[
                  import com.bewellcommunication.pvg.model.BackendService;
                  import com.bewellcommunication.pvg.model.Utilities;
                 
                  import flash.events.TimerEvent;
                 
                  import mx.charts.chartClasses.IAxis;
                  import mx.charts.series.items.LineSeriesItem;
                  import mx.collections.ArrayCollection;
                  import mx.collections.XMLListCollection;
                  import mx.controls.RadioButton;
                  import mx.controls.RadioButtonGroup;
                  import mx.rpc.events.ResultEvent;
                 
                  [Bindable]
                  private var patientMeasureNames:ArrayCollection;
                  private var patientMeasureIds:Array;
                  private var dataVideoIds:Array;
                  private var videoButtons:Array;
                 
                  [Bindable]
                  private var patientData:XMLListCollection;
                 
                  [Bindable]
                  private var maxDate:Date;
                 
                  [Bindable]
                  private var maxValue:Number;

       

                  [Bindable]
                  private var styleNames:Array = new Array("axisStroke");
                 
                  private function initialization():void
                  {
                      var service:BackendService = new BackendService();
                      var xml:String = "<LoadPatientMeasures>"
                          + "\n<clientId>" + 2 + "</clientId>"
                          + "\n</LoadPatientMeasures>";
                      service.request(xml, loadPatientMeasuresFinish);
                  }
                 
                  public function loadPatientMeasuresFinish(re:ResultEvent):void
                  {
                      var xmlResult:XML = XML(re.result.valueOf().toString());
                      var error:String = xmlResult.error;
                      if (error != null && error != "")                   
                          trace(xmlResult.error + "Problem loading patient measures");        // PENDING: bwcAlert
                      else
                      {
                          this.patientMeasureNames = new ArrayCollection();
                          this.patientMeasureNames.addItem("(Select measure)");
                          this.patientMeasureIds = new Array();
                          this.patientMeasureIds.push(0);
                         
                          var xmlMeasures:XMLList = xmlResult.measures.children();
                          for each (var xmlMeasure:Object in xmlMeasures)
                          {
                              this.patientMeasureIds.push(Number(xmlMeasure.measureId));
                              var name:String = xmlMeasure.measureName;                        // PENDING: utils.makeSafe()
                              this.patientMeasureNames.addItem(name);       
                          }
                      }                   
                  }
                 
                  public function loadPatientData():void
                  {
                      var measureIndex:int = this.measureCombo.selectedIndex;
                      if (measureIndex < 1)
                          return;
                      var service:BackendService = new BackendService();
                      var xml:String = "<LoadPatientData>"
                          + "\n<clientId>" + 2 + "</clientId>"
                          + "\n<measureId>" + this.patientMeasureIds[measureIndex] + "</measureId>"
                          + "\n</LoadPatientData>";
                      service.request(xml, loadPatientDataFinish);               
                  }
                 
                  public function loadPatientDataFinish(re:ResultEvent):void
                  {
                      var xmlResult:XML = XML(re.result.valueOf().toString());
                      var error:String = xmlResult.error;
                      if (error != null && error != "")                   
                          trace(xmlResult.error + "Problem loading patient data");        // PENDING: bwcAlert
                      else
                      {
                          // re-initialize
                          this.annotationCanvas.removeAllChildren();                   
                         
                          // set data for graphing
                          this.patientData = new XMLListCollection(xmlResult.results.result);
                          this.dataVideoIds = new Array();
                          // calculate mins and maximums for axis spacing
                          var xmlResults:XMLList = xmlResult.results.children();
                          var minDate:Number = Number.MAX_VALUE;
                          var maxDate:Number = Number.MIN_VALUE;
                          var minVal:Number = Number.MAX_VALUE;
                          var maxVal:Number = Number.MIN_VALUE;
                          for each (var result:Object in xmlResults)
                          {
                              var date:Number = Number(result.date);
                              var val:Number = Number(result.value);
                              if (!isNaN(val))
                              {
                                  if (date < minDate)
                                      minDate = date;
                                  if (date > maxDate)
                                      maxDate = date;
                                  if (val < minVal)
                                      minVal = val;
                                  if (val > maxVal)
                                      maxVal = val;
                              }
                             
                              // also store the video id
                              var videoId:Number = Number(result.videoId);
                              this.dataVideoIds.push(videoId);
                          }
                          // set scale max for each axis
                          this.maxDate = new Date(maxDate + ((maxDate - minDate) * 0.1));
                          this.maxValue = maxVal * 1.1;
                          // draw links to videos
                          var utils:Utilities = new Utilities();
                          utils.relinquishThenFinish(drawLinksToVideos, 500);
                      }                   
                  }
                 
                  private function drawLinksToVideos(e:TimerEvent):void
                  {
                      var rect:Rectangle = new Rectangle(0, 0, 99999, 99999);        // get all items
                      var items:Array = this.progressChart.getItemsInRegion(rect);
                      var i:int;
                      var rbg:RadioButtonGroup = new RadioButtonGroup(this.annotationCanvas);
                      this.videoButtons = new Array();
                      for (i = 0; i < items.length; i++)
                      {
                          var liveButton:RadioButton = null;
                          if (this.dataVideoIds[i] > 0)
                          {
                              var item:LineSeriesItem = items[i];
                              var radio:RadioButton = new RadioButton();
                              radio.group = rbg;
                              liveButton = radio;
                              radio.addEventListener(Event.CHANGE, loadAndPlayVideo);
                              this.annotationCanvas.addDataChild(radio, item.xValue, item.yValue);
                          }
                          this.videoButtons.push(liveButton);    // one for each item
                      }
                  }
                 
                  private function loadAndPlayVideo(e:Event):void
                  {
                      var utils:Utilities = new Utilities();
                      utils.relinquishThenFinish(finishLoadAndPlayVideo);
                  }
                  private function finishLoadAndPlayVideo(e:TimerEvent):void
                  {
                      // identify video to play
                      var i:int;
                      var target:int = -1;
                      for (i=0; target == -1 && i < this.videoButtons.length; i++)
                      {
                          var radio:RadioButton = this.videoButtons[i] as RadioButton;
                          if (radio != null && radio.selected)
                              target = i;
                      }
                     
                      // play video
                      if (target > -1)
                      {
                          trace("play video: index=" + target + " id=" + this.dataVideoIds[target]);
                      }
                  }
                 
                  private function makeDateFromString(dateStr:String):Date
                  {
                      var dateNum:Number = Number(dateStr);
                      var date:Date = new Date(dateNum);
                      trace("date=" + date.toLocaleString());
                      return date;
                  }
                 
                  private function formatDateLabel(cur:Date, prev:Date, axis:IAxis):String
                  {
                      var label:String = cur.month + "/" + cur.date + " " + cur.hours + ":" + cur.minutes;
                      return label;
                  }
                 
              ]]>
          </mx:Script>
         
      </mx:Application>

       

       

      package
      {
          import mx.charts.series.LineSeries;
         
          public class BwcLineSeries extends LineSeries
          {
              public function BwcLineSeries()
              {
                  super();
              }
             
              override protected function updateDisplayList(unscaledWidth:Number,
                                                            unscaledHeight:Number):void
              {
                  var useWidth:Number = unscaledWidth;
                  var useHeight:Number = unscaledHeight;
                  /*if (isNaN(useWidth))
                  {
                      useWidth = 745.5;
                      useHeight = 365;
                  }*/
                  super.updateDisplayList(useWidth, useHeight);
              }
                 
          }
      }

       

      <data>
        <measure/>
        <results>
          <result>
            <date>1276613823585</date>
            <value>180.0</value>
            <videoId>0</videoId>
          </result>
          <result>
            <date>1276613923383</date>
            <value>170.0</value>
            <videoId>0</videoId>
          </result>
          <result>
            <date>1276614556024</date>
            <value>210.0</value>
            <videoId>0</videoId>
          </result>
          <result>
            <date>1276628450502</date>
            <value>150.0</value>
            <videoId>104</videoId>
          </result>
          <result>
            <date>1276628667114</date>
            <value>180.0</value>
            <videoId>106</videoId>
          </result>
        </results>
      </data>