Not yet rated

Problem

1- You have a chart to which you added a DataDrawingCanvas or CartesianDataCanvas or PolarDataCanvas instance in the backgroundElements or annotationsElements array 2- You want to use this chart as an item renderer So, you implement the IListItemRenderer interface (in Flex 3) or IItemRenderer interface (in Flex 4), but there are some display glitches occuring when the chart is renderered as an item renderer. The problem is with the DataDrawingCanvas object lifecycle. First, the chart is created. Then the DataDrawingCanvas is created. Then the data is passed to the chart. Then the chart is invalidated and updateDisplayList is called. When updateDisplayList is called, your drawing takes place.

Solution

Instead of using the chart as an item renderer in a list, what you can do is create a Canvas based MXML component, instantiate your chart in it, override the data setter that will pass along the data for the dataProvider for the series and any data you need for DataDrawingCanvas. Then you dynamically addChild instances of that MXML component to e.g a VBox or a Group or BorderContainer, and you add an event listener to it for FlexEvent.CREATION_COMPLETE. In the FlexEvent.CREATION_COMPLETE handler, set the data property to pass the data to your chart. This way, there are no rendering problems and no display glitches.

Detailed explanation

You have a chart that extends a MX chart:
        public class TrendPlotChart extends PlotChart {}

And adds a DataDrawingCanvas instance to it in the constructor:

public function TrendPlotChart() {

      background = new DataDrawingCanvas();            

       // Add the newly created DataDrawingCanvas instances to the backgroundElements array
       this.backgroundElements.push(background);
}
Override updateDisplayList to draw in the DataDrawingCanvas:

        override protected function updateDisplayList(unscaledWidth:Number,
                                                      unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);

            // Render
           
            if(dataProvider)
            {
                drawBackgroundFills(); // methods that draw in theDataDrawingCanvas
                drawBackgroundLines();
            }
        }
Create a Canvas  based MXML component that instantiate your custom chart. Although this class is not used directly as an item renderer, the data property of the Canvas class is written to and used to populate data in the chart series as well as to draw lines and gradients in its DataDrawingCanvas instance.
 
        <?xml version="1.0" encoding="utf-8"?>

<mx:Canvas xmlns:fx="http://ns.adobe.com/mxml/2009"
           xmlns:s="library://ns.adobe.com/flex/spark"
           xmlns:mx="library://ns.adobe.com/flex/mx"
           xmlns:db="com..mycompany.component.*"
           xmlns:parsley="http://www.spicefactory.org/parsley"
           width="100%"
           height="225">
    <fx:Declarations>

        <parsley:Configure />
    </fx:Declarations>

    <fx:Metadata>
        [Event(name="removeMetric", type="com.mycompany.event.AddRemoveMetricEvent")]
    </fx:Metadata>

    <fx:Script>
        <![CDATA[

            import com.mycompany.model.applications.TrendPlotChartVO;
            import com.mycompany.model.applications.ModelLocator;
            import com.mycompany.event.AddRemoveMetricEvent;

            [Bindable]
            [Inject]
            public var model:ModelLocator;

            override public function set data(value:Object):void
            {
                super.data = value;

                plotSeries.displayName = (data as TrendPlotChartVO).metric + " for " + (data as TrendPlotChartVO).serverName
                trendPlotChart.dataProvider = TrendPlotChartVO(data).dataProvider;
                trendPlotChart.trendPointY1 = TrendPlotChartVO(data).trendPointY1;
                trendPlotChart.trendPointY2 = TrendPlotChartVO(data).trendPointY2;
                trendPlotChart.physicalLimit = TrendPlotChartVO(data).physicalLimit;
                trendPlotChart.safeOperationLevel = TrendPlotChartVO(data).safeOperationLevel;
                trendPlotChart.leadTime = TrendPlotChartVO(data).leadTime;
                trendPlotChart.intersectionOfTrendAndSOLX = TrendPlotChartVO(data).intersectionOfTrendAndSOLX;
                xAxis.dataUnits = TrendPlotChartVO(data).dataUnits;
                xAxis.minimum = TrendPlotChartVO(data).xMinimum;
                xAxis.maximum = TrendPlotChartVO(data).xMaximum;
                yAxis.minimum = TrendPlotChartVO(data).yMinimum;
                yAxis.maximum = TrendPlotChartVO(data).yMaximum;
            }

        ]]>
    </fx:Script>

    <db:TrendPlotChart id="trendPlotChart"
                       width="100%"
                       height="200"
                       top="0" right="0"
                       paddingLeft="5" paddingRight="5"
                       showDataTips="true"
                       dataTipMode="single"
                       dataTipRenderer="com.mycompany.renderer.TrendDataTipItemRenderer"
                       dataTipFunction="{model.trendChartDataTipFunction}"
                       physicalLimitStroke="{model.dataModel.physicalLimitStroke}"
                       safeOperationLevelStroke="{model.dataModel.safeOperatingLevelStroke}"
                       leadTimeStroke="{model.dataModel.leadTimeStroke}"
                       intersectionOfTrendAndSOLStroke="{model.dataModel.intersectionOfTrendAndSOLStroke}"
                       trendStroke="{model.dataModel.trendStroke}"
                       topSectionFillColors="{[0x666666, 0x000000]}"
                       topSectionFillAlphas="{[1, 0.5]}"
                       topSectionFillRatios="{[0, 255]}"
                       firstSectionFillColors="{[0xAA0000, 0x770000]}"
                       firstSectionFillAlphas="{[0.5, 0.8]}"
                       firstSectionFillRatios="{[0, 255]}"
                       secondSectionFillColors="{[0xCC5500, 0xAA2200]}"
                       secondSectionFillAlphas="{[0.5, 0.8]}"
                       secondSectionFillRatios="{[0, 255]}"
                       thirdSectionFillColors="{[0x00AA55, 0x008822]}"
                       thirdSectionFillAlphas="{[0.8, 0.8]}"
                       thirdSectionFillRatios="{[0, 255]}"
                       color="white">

        <db:horizontalAxis>
            <mx:DateTimeAxis id="xAxis" />
        </db:horizontalAxis>

        <db:verticalAxis>
            <mx:LinearAxis id="yAxis" />
        </db:verticalAxis>

        <db:horizontalAxisRenderers>
            <mx:AxisRenderer axisStroke="{model.dataModel.axisRendererStroke}" axis="{xAxis}" />
        </db:horizontalAxisRenderers>

        <db:verticalAxisRenderers>
            <mx:AxisRenderer axisStroke="{model.dataModel.axisRendererStroke}" axis="{yAxis}" />
        </db:verticalAxisRenderers>

        <db:series>
            <mx:PlotSeries id="plotSeries"
                           xField="timeAndDate"
                           yField="snapshotValue"
                           itemRenderer="mx.charts.renderers.DiamondItemRenderer"
                           fill="{model.dataModel.sc2}">
            </mx:PlotSeries>
        </db:series>

    </db:TrendPlotChart>

    <mx:Legend id="legend"
               dataProvider="{trendPlotChart}"
               color="white"
               direction="horizontal"
               bottom="0"
               left="15">
    </mx:Legend>

    <s:Button id="removeChartButton"
              bottom="0"
              right="15"
              skinClass="com.mycompany.skins.MinusButtonSkin"
              click="dispatchEvent(new AddRemoveMetricEvent(AddRemoveMetricEvent.REMOVE_METRIC, data, true));
                       parent.removeChild(this)">
    </s:Button>

</mx:Canvas>
 
 
 
 
  

Create a VBox based MXML component (or BorderContainer based with a VerticalLayout) to which you will add the "item renderer" instances:

        package com.mycompany.component
{
    import com.mycompany.model.applications.TrendPlotChartVO;
    import com.mycompany.event.AddRemoveMetricEvent;
    import com.mycompany.event.MetricEvent;
    import com.mycompany.core.util.DateUtils;
    // import spark.components.BorderContainer;
    // import spark.layouts.VerticalLayout;

    import flash.events.Event;

    import mx.containers.VBox;
    import mx.controls.Alert;
    import mx.events.FlexEvent;

    // For Flex 4, you can extend BorderContainer instead of VBox

    public class TrendChartStack extends VBox
    {
        private var trendPlotChartCanvas:TrendPlotChartCanvas;
        private var chartData:TrendPlotChartVO;
       
        public function TrendChartStack(){
            // Flex 4 only: if you use BorderContainer instead of VBox, set up a VerticalLayout
            // this.layout = new VerticalLayout();
        } 

        // Call this method to add a chart to the vertical stack
        public function addChart(event:AddRemoveMetricEvent):void
        {               
            chartData = event.payload as TrendPlotChartVO;
            trendPlotChartCanvas = new TrendPlotChartCanvas();
            trendPlotChartCanvas.addEventListener(FlexEvent.CREATION_COMPLETE, onChartCreationComplete);
            this.addChild(trendPlotChartCanvas); // use addElement() with BorderContainer instead
        }

        private function onChartCreationComplete(event:FlexEvent):void
        {
            trendPlotChartCanvas.data = chartData;
            trendPlotChartCanvas.removeEventListener(FlexEvent.CREATION_COMPLETE, onChartCreationComplete);
        }
    }
}
 
 
 
 
  

+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes