[Flex]给图表添加告警线(背景线,水平线)

有时候我们需要在图表的背景上添加上参考线,用来比较。 在<mx:backgroundElements>节点中,添加自定义的ChartElement即可。


效果图如下

图表代码如下

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:hangge="com.hangge.*" creationComplete="init(event)">
	<mx:Script>
		<![CDATA[
			import mx.charts.chartClasses.IAxisRenderer;
			import mx.events.FlexEvent;
			
			private var xml:XML = <data date='2014-06-02' flag='curve'  toptop='' top='65.01' bottom="40" bottombottom="">
									<item value='54.6' time='00:00' />
									<item value='55.0' time='00:05' />
									<item value='54.4' time='00:10' />
									<item value='54.6' time='00:15' />
									<item value='54.8' time='00:20' />					
								</data>

			
			private function categoryLabelFunction(axisRenderer:IAxisRenderer, label:String):String {
				return " "+label+" ";
			} 
			
			protected function init(event:FlexEvent):void
			{
				chart1.dataProvider = xml.item;
				
				vAxis.displayName = "湿度";
				
				vAxis.maximum = 60;
				vAxis.minimum = 50;
				
				tt.yValue = 58;
				bb.yValue = 52;
			}
			
		]]>
	</mx:Script>
	
	<mx:Canvas width="60%" height="60%" horizontalCenter="0" verticalCenter="0" backgroundColor="0xD0E0E4">
		<mx:LineChart id="chart1"  width="100%" height="100%" showDataTips="true">  
			<mx:backgroundElements>
				<mx:GridLines direction="horizontal">
					<mx:horizontalStroke>
						<mx:Stroke color="0xFFFFFF" alpha="0.25"/>
					</mx:horizontalStroke>
				</mx:GridLines>
				<hangge:DashedLines id="tt" lineColor="0xFF0000" displayName="上上限" yMax="100" yMin="0"/>
				<hangge:DashedLines id="bb"  lineColor="0xFF0000" displayName="下下限" yMax="100" yMin="0"/>
			</mx:backgroundElements>
			<mx:fill>
				<mx:SolidColor color="0x000000" alpha="0"/>
			</mx:fill>
			<mx:horizontalAxis>  
				<mx:CategoryAxis id="hAxis" categoryField="@time" displayName="时间"/>  
			</mx:horizontalAxis>  
			<mx:horizontalAxisRenderers>
				<mx:AxisRenderer  axis="{hAxis}" tickPlacement="none" minorTickPlacement="none" color="0x000000" fontSize="14" fontFamily="微软雅黑" canDropLabels="true" labelFunction="categoryLabelFunction">
					<mx:axisStroke>
						<mx:Stroke weight="2" color="0xFFFFFF"/>
					</mx:axisStroke>
				</mx:AxisRenderer>
			</mx:horizontalAxisRenderers>
			
			<mx:verticalAxis>  
				<mx:LinearAxis id="vAxis" baseAtZero="false"/>  
			</mx:verticalAxis> 
			
			<mx:verticalAxisRenderers>
				<mx:AxisRenderer axis="{vAxis}" tickPlacement="none" minorTickPlacement="none" fontSize="14" color="0x000000" fontFamily="微软雅黑">
					<mx:axisStroke>
						<mx:Stroke color="0xFFFFFF" weight="2"/>
					</mx:axisStroke>
				</mx:AxisRenderer>
			</mx:verticalAxisRenderers> 
			
			<mx:series>  
				<mx:LineSeries id="ls" form="curve" xField="@time" yField="@value">
					<mx:lineStroke>
						<mx:Stroke color="0x00fff5"/>
					</mx:lineStroke>
				</mx:LineSeries>		  
			</mx:series>  
		</mx:LineChart>
	</mx:Canvas>	
</mx:Application>


使用到的DashedLines代码如下

package com.hangge{
	
	import flash.display.Graphics;
	import flash.geom.Point;
	import flash.text.TextField;
	
	import mx.charts.chartClasses.CartesianChart;
	import mx.charts.chartClasses.CartesianTransform;
	import mx.charts.chartClasses.ChartElement;
	import mx.charts.chartClasses.ChartState;
	import mx.charts.chartClasses.IAxis;
	
	public class DashedLines extends ChartElement {
		
		public function DashedLines() {
			super();  
		}  
		
		/** 
		 * 该线对应的y值 
		 */
		private var _yValue:Number = NaN;  
		
		public function get yValue():Number {  
			return _yValue;  
		}  
		
		public function set yValue(value:Number):void {  
			_yValue = value;  
			invalidateDisplayList();  
		}
		
		/** 
		 * 该线对应的y轴最大值 
		 */  
		private var _yMax:Number = NaN;
		
		public function get yMax():Number {  
			return _yMax;  
		}
		
		public function set yMax(value:Number):void {  
			_yMax = value;  
			invalidateDisplayList();  
		}
		
		/** 
		 * 该线对应的y轴最小值 
		 */
		private var _yMin:Number = NaN;
		
		public function get yMin():Number {  
			return _yMin;  
		}  
		
		public function set yMin(value:Number):void {  
			_yMin = value;  
			invalidateDisplayList();  
		}
		
		/** 
		 * 实线部分的长度 
		 * @default 10 
		 */  
		public var length:Number = 10;  
		
		/** 
		 * 空白部分的长度 
		 * @default 5 
		 */  
		public var gap:Number = 5;  
		
		/** 
		 * 线条的宽度 
		 * @default 1 
		 */  
		public var lineThickness:Number = 1;  
		
		/** 
		 * 线条的颜色 
		 * @default 黑色 
		 */  
		public var lineColor:uint = 0;  
		
		private var _displayName:String;  
		
		/**
		 * 该线所对应的数值名称(平均值,最大值等等)
		 * @default
		 */
		public function get displayName():String {
			return _displayName;
		}
		
		/**
		 * @private
		 */
		public function set displayName(value:String):void {
			_displayName = value;
			invalidateDisplayList();
		}
		
		protected var label:TextField;
		
		
		override protected function createChildren():void {  
			super.createChildren();  
			
			if(!label) {  
				label = new TextField();  
				label.mouseEnabled = false;  
				addChild(label);  
			}  
		}  
		
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {  
			super.updateDisplayList(unscaledWidth, unscaledHeight);  
			
			if (!chart|| 
				chart.chartState == ChartState.PREPARING_TO_HIDE_DATA ||  
				chart.chartState == ChartState.HIDING_DATA) {  
				return;
			}
			
			var g:Graphics = this.graphics;
			g.clear();
			
			// 如果没有设置数据,不显示
			if(isNaN(yValue)) {  
				return;
			}
			
			var w:Number = unscaledWidth;
			var h:Number = unscaledHeight;
			var vAxis:IAxis = CartesianChart(this.chart).verticalAxis;
			
			var posyValue:Number = (yValue - yMin) / (yMax - yMin) * 100;
			
//			var y:Number = dataToLocal(0, yValue).y;
			var y:Number = dataToLocal(0, posyValue).y;
			
			var pFrom:Point = new Point(0, y);
			var pTo:Point = new Point(w, y);
			
			drawDashed(g, pFrom, pTo, this.length, this.gap, this.lineThickness, this.lineColor);  
			
			label.text = (displayName ? (displayName + " : ") : "") + yValue;  
			label.x = 1;  
			label.y = y > 21 ? y - 21 : y + 1;  
		}
		
		
		// 这个方法复制自LineSeries  
		override public function dataToLocal(... dataValues):Point {  
			var data:Object = {};
			var da:Array /* of Object */ = [ data ];  
			var n:int = dataValues.length;  
			
			if (n > 0) {
				data["d0"] = dataValues[0];
				dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).mapCache(da, "d0", "v0");
			}
			
			if (n > 1) {
				data["d1"] = dataValues[1];
				dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).mapCache(da, "d1", "v1");
			}
			
			dataTransform.transformCache(da,"v0","s0","v1","s1");
			
			return new Point(data.s0 + this.x, data.s1 + this.y);  
		}
		
		/** 
		 * 画虚线 
		 * @param graphics 你懂的 
		 * @param pFrom 起点 
		 * @param pTo 终点 
		 * @param length 实线段的长度 
		 * @param gap 实线段的间距 
		 * @param thickness 线的宽度 
		 * @param color 线的颜色 
		 */
		private function drawDashed(graphics:Graphics, pFrom:Point, pTo:Point, length:Number = 5, gap:Number = 5, thickness:Number = 1, color:uint = 0):void {  
			var max:Number = Point.distance(pFrom, pTo);  
			var l:Number = 0;  
			var p3:Point;  
			var p4:Point;  
			graphics.lineStyle(thickness, color);  
			while (l < max)  
			{  
				p3 = Point.interpolate(pTo, pFrom, l / max);  
				l += length;  
				if (l > max)  
					l = max;  
				p4 = Point.interpolate(pTo, pFrom, l / max);  
				graphics.moveTo(p3.x, p3.y)  
				graphics.lineTo(p4.x, p4.y)  
				l += gap;  
			}  
		}  
	}
}
THE END