7 Replies Latest reply on Jan 22, 2009 12:07 PM by yantzgh

    CartesianDataCanvas

    yantzgh
      I'm trying to draw onto a Flex ColumnChart to add trend lines to grouped items. The chart's xAxis has 3 groups (5 credits and below, 6 or 7 credits, and 8 or more credits) and within each of these groups there is three years of data for the school in question. I need to add a trend line for the school board on top of each of these groupings (so that each group has its own trend line). I can easily add a trend that crosses the groups (using the CartesianDataCanvas moveTo and lineTo methods), but that isn't the desired effect.

      Is there a way to pass in a non group-name variable to these methods? Whenever I pass a number, the drawing silently fails. If I pass the group name, the trend won't draw correctly (it just draws straight up and down at the center point of the group).

      Any help would be greatly appreciated.
        • 1. Re: CartesianDataCanvas
          matthew horn Level 3
          Can you post a relatively simple code sample that illustrates the current behavior? Thanks,

          matt horn
          flex docs
          • 2. Re: CartesianDataCanvas
            yantzgh Level 1
            Here the code that puts the trend lines straight up and down (not the desired effect). Basically, I just need to modify the moveTo and lineTo methods calls to allow me to position the grouped trend lines correctly.

            <?xml version="1.0" encoding="utf-8"?>
            <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute">
            <mx:Script>
            <![CDATA[
            import mx.collections.ArrayCollection;

            [Bindable]
            private var _dataGroups:ArrayCollection = new ArrayCollection([
            {
            label: '2004-05',
            datakey: '_data1'
            },
            {
            label: '2005-06',
            datakey: '_data2'
            },
            {
            label: '2006-07',
            datakey: '_data3'
            }
            ]);
            [Bindable]
            private var _dataSchool:ArrayCollection = new ArrayCollection([
            {
            _group: '5 or less credits',
            _data1: 15,
            _data2: 10,
            _data3: 5
            },
            {
            _group: '6 or 7 credits',
            _data1: 20,
            _data2: 15,
            _data3: 10
            },
            {
            _group: '8 or more credits',
            _data1: 65,
            _data2: 75,
            _data3: 85
            }
            ]);
            [Bindable]
            private var _dataBoard:ArrayCollection = new ArrayCollection([
            {
            _group: '5 or less credits',
            _data1: 20,
            _data2: 15,
            _data3: 10
            },
            {
            _group: '6 or 7 credits',
            _data1: 25,
            _data2: 20,
            _data3: 15
            },
            {
            _group: '8 or more credits',
            _data1: 55,
            _data2: 65,
            _data3: 75
            }
            ]);
            private function setTrend():void{
            chart_canvas.clear();
            chart_canvas.lineStyle(
            4,
            0xCCCCCC,
            .75,
            true,
            LineScaleMode.NORMAL,
            CapsStyle.ROUND,
            JointStyle.MITER,
            2
            );
            // Trend for: 5 or less credits
            chart_canvas.moveTo(_dataBoard.getItemAt(0)._group, _dataBoard.getItemAt(0)._data1);
            chart_canvas.lineTo(_dataBoard.getItemAt(0)._group, _dataBoard.getItemAt(0)._data2);
            chart_canvas.lineTo(_dataBoard.getItemAt(0)._group, _dataBoard.getItemAt(0)._data3);
            // Trend for: 6 or 7 credits
            chart_canvas.moveTo(_dataBoard.getItemAt(1)._group, _dataBoard.getItemAt(1)._data1);
            chart_canvas.lineTo(_dataBoard.getItemAt(1)._group, _dataBoard.getItemAt(1)._data2);
            chart_canvas.lineTo(_dataBoard.getItemAt(1)._group, _dataBoard.getItemAt(1)._data3);
            // Trend for: 8 or more credits
            chart_canvas.moveTo(_dataBoard.getItemAt(2)._group, _dataBoard.getItemAt(2)._data1);
            chart_canvas.lineTo(_dataBoard.getItemAt(2)._group, _dataBoard.getItemAt(2)._data2);
            chart_canvas.lineTo(_dataBoard.getItemAt(2)._group, _dataBoard.getItemAt(2)._data3);
            }
            ]]>
            </mx:Script>
            <mx:ColumnChart id="chart" dataProvider="{_dataSchool}" creationComplete="setTrend()">
            <mx:annotationElements>
            <mx:CartesianDataCanvas id="chart_canvas" includeInRanges="true" />
            </mx:annotationElements>
            <mx:horizontalAxis>
            <mx:CategoryAxis id="xAxis" categoryField="_group" />
            </mx:horizontalAxis>
            <mx:verticalAxis>
            <mx:LinearAxis id="yAxis" />
            </mx:verticalAxis>
            <mx:series>
            <mx:ColumnSeries xField="_group" yField="_data1" labelField="{_dataGroups.getItemAt(0).label}" />
            <mx:ColumnSeries xField="_group" yField="_data2" labelField="{_dataGroups.getItemAt(1).label}" />
            <mx:ColumnSeries xField="_group" yField="_data3" labelField="{_dataGroups.getItemAt(2).label}" />
            </mx:series>
            </mx:ColumnChart>
            </mx:Application>
            • 3. Re: CartesianDataCanvas
              yantzgh Level 1
              As a follow up, from all of my searching on CartesianDataCanvas, the moveTo method accepts to Objects (as oppose to 2 numbers like all other moveTo methods). The 2nd parameter can be a number, but from all of my testing, the 1st parameter has to be a String of some sort. Passing a number as the 1st parameter results in no drawing taking place.
              • 4. Re: CartesianDataCanvas
                matthew horn Level 3
                I tried a bunch of different things and couldn't get this working the way you wanted. Have you tried posting to the Flexcoders mailing list?

                matt horn
                flex docs
                • 5. Re: CartesianDataCanvas
                  yantzgh Level 1
                  Nope. I didn't know there was a Flexcoders mailing list. I'll try that.

                  Alternatively, I'm working on a way to use a Canvas, instead of CartesianDataCanvas and then drawing the trend in myself. The hard part in that will be figuring out the y values based on the chart axis.
                  • 6. Re: CartesianDataCanvas
                    matthew horn Level 3
                    Here's a link:

                    http://groups.yahoo.com/group/flexcoders/

                    The only other solution I thought of was creating a separate data provider for the trend line, and then adding it as a LineSeries, but I couldn't perfect that in my attempts either.

                    matt
                    • 7. Re: CartesianDataCanvas
                      yantzgh Level 1
                      I finally have it working!

                      I use the yAxis maximum and CartesianDataCanvas height properties to figure out the data value offsets and loop through ColumnSeries.item array to look at their itemRenderer's x value. I combine these with the real data and then use CartesianDataCanvas.graphics.moveTo and CartesianDataCanvas.graphics.lineTo (instead of the moveTo and lineTo methods of the CartesianDataCanvas itself). It took 3 days to get it working, but it works!!

                      Here's the working solution (a nice looping nightmare!)...

                      <?xml version="1.0" encoding="utf-8"?>
                      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute"
                      backgroundColor="#FFFFFF" backgroundAlpha="1" backgroundGradientColors="null"
                      creationComplete="init()"
                      >
                      <mx:Script>
                      <![CDATA[
                      import mx.charts.series.items.ColumnSeriesItem;
                      import mx.collections.ArrayCollection;

                      [Bindable]
                      private var _dataGroups:ArrayCollection = new ArrayCollection([
                      {
                      label: '2004-05',
                      datakey: '_data1'
                      },
                      {
                      label: '2005-06',
                      datakey: '_data2'
                      },
                      {
                      label: '2006-07',
                      datakey: '_data3'
                      }
                      ]);
                      [Bindable]
                      private var _dataSchool:ArrayCollection = new ArrayCollection([
                      {
                      _group: '5 or less credits',
                      _data1: 15,
                      _data2: 10,
                      _data3: 5
                      },
                      {
                      _group: '6 or 7 credits',
                      _data1: 20,
                      _data2: 15,
                      _data3: 10
                      },
                      {
                      _group: '8 or more credits',
                      _data1: 65,
                      _data2: 75,
                      _data3: 85
                      }
                      ]);
                      [Bindable]
                      private var _dataBoard:ArrayCollection = new ArrayCollection([
                      {
                      _group: '5 or less credits',
                      _data1: 20,
                      _data2: 15,
                      _data3: 10
                      },
                      {
                      _group: '6 or 7 credits',
                      _data1: 25,
                      _data2: 20,
                      _data3: 15
                      },
                      {
                      _group: '8 or more credits',
                      _data1: 55,
                      _data2: 65,
                      _data3: 75
                      }
                      ]);
                      private function setTrend():void{
                      chart_canvas.graphics.clear();
                      chart_canvas.graphics.lineStyle(
                      1,
                      0x336699,
                      .5,
                      true,
                      LineScaleMode.NORMAL,
                      CapsStyle.ROUND,
                      JointStyle.MITER,
                      2
                      );
                      // Calculate the data offset for drawing
                      var yAxisMax:int = yAxis.maximum;
                      var yAxisHeight:int = chart_canvas.height;
                      var dataOffset:Number = yAxisHeight / yAxisMax;
                      // Generate the data array
                      var dataArray:Array = new Array(chart.series.length);
                      for(var i:int = 0; i < dataArray.length; i++){
                      dataArray = new Array();
                      }
                      // Fill the data array
                      for(i = 0; i < chart.series.length; i++){
                      var columnSeries:ColumnSeries = chart.series
                      as ColumnSeries;
                      for(var j:int = 0; j < columnSeries.items.length; j++){
                      var columnSeriesItem:ColumnSeriesItem = columnSeries.items[j] as ColumnSeriesItem;
                      var xPos:Number = columnSeriesItem.itemRenderer.x + (columnSeriesItem.itemRenderer.width / 2);
                      var yPos:Number = yAxisHeight - (_dataBoard.getItemAt(j)['_data'+ (i+1)] * dataOffset);
                      if(i == 0){
                      dataArray[j].push(new Point(xPos, yAxisHeight));
                      }
                      dataArray[j].push(new Point(xPos, yPos));
                      if(i == chart.series.length - 1){
                      dataArray[j].push(new Point(xPos, yAxisHeight));
                      }
                      }
                      }
                      // Draw to the CartesianDataCanvas
                      chart_canvas.graphics.beginFill(0xFFFF00, 0.10);
                      for(i = 0; i < dataArray.length; i++){
                      var dataSet:Array = dataArray as Array;
                      for(j = 0; j < dataSet.length; j++){
                      var point:Point = dataSet[j] as Point;
                      if(j == 0){
                      chart_canvas.graphics.moveTo(point.x, point.y);
                      chart_canvas.graphics.lineStyle(1, 0x336699, 0);
                      }else{
                      chart_canvas.graphics.lineTo(point.x, point.y);
                      chart_canvas.graphics.lineStyle(
                      3,
                      0x336699,
                      .75,
                      true,
                      LineScaleMode.NORMAL,
                      CapsStyle.ROUND,
                      JointStyle.MITER,
                      2
                      );
                      if(j == dataSet.length - 2){
                      chart_canvas.graphics.lineStyle(1, 0x336699, 0);
                      }
                      }
                      }
                      }
                      chart_canvas.graphics.endFill();
                      }
                      ]]>
                      </mx:Script>
                      <mx:ColumnChart id="chart" dataProvider="{_dataSchool}" creationComplete="setTrend()">
                      <mx:annotationElements>
                      <!-- <mx:Canvas id="chart_canvas" /> -->
                      <mx:CartesianDataCanvas id="chart_canvas" includeInRanges="true" />
                      </mx:annotationElements>
                      <mx:horizontalAxis>
                      <mx:CategoryAxis id="xAxis" categoryField="_group" />
                      </mx:horizontalAxis>
                      <mx:verticalAxis>
                      <mx:LinearAxis id="yAxis" />
                      </mx:verticalAxis>
                      <mx:series>
                      <mx:ColumnSeries id="chart_series1" selectable="true" xField="_group" yField="_data1" labelField="{_dataGroups.getItemAt(0).label}" />
                      <mx:ColumnSeries id="chart_series2" selectable="true" xField="_group" yField="_data2" labelField="{_dataGroups.getItemAt(1).label}" />
                      <mx:ColumnSeries id="chart_series3" selectable="true" xField="_group" yField="_data3" labelField="{_dataGroups.getItemAt(2).label}" />
                      </mx:series>
                      </mx:ColumnChart>
                      </mx:Application>