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.
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.
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 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);
}
}
}
+