Flex4 用LineChart实现实时曲线图,并在其中添加自定义的虚线水平线

本示例首先是为了显示实时曲线。然后呢,要显示个水平线,比如我要显示一个变量的变化过程,但它有一个标准值,就可以用该种方式。

示例:



然后是代码:
先看Application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application 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:chartClasses="lip.charts.chartClasses.*">
	
	<fx:Script>
		<![CDATA[
			import lip.utils.DateFormatter;
			
			import mx.collections.ArrayCollection;
			import mx.utils.ObjectProxy;
			
			private static const DELAY:int = 1000;
			
			private static const MAX_COUNT:int = 10;
			
			[Bindable]
			private var ac:ArrayCollection;
			
			private var timer:Timer;
			
			protected function startCalc(event:MouseEvent):void
			{
				if(!timer)
				{
					timer = new Timer(DELAY);
					timer.addEventListener(TimerEvent.TIMER, timer_timerHandler);
				}
				timer.start();
			}
			
			protected function stopCalc(event:MouseEvent):void
			{
				if(timer)
					timer.stop();
				
				ac = null;
			}
			
			protected function timer_timerHandler(event:TimerEvent):void
			{
				var now:Date = new Date();
				var nowTime:String;
				
				if(!ac)
				{
					ac = new ArrayCollection();
					now.setTime(now.time - 1000 * MAX_COUNT);
					for (var i:int = 0; i < MAX_COUNT; i++) 
					{
						nowTime = DateFormatter.getInstance().formatTime(now);
						ac.addItem(new ObjectProxy({time:nowTime, gas:0}));
						now.setTime(now.time + 1000);
					}
					
				}
				
				nowTime = DateFormatter.getInstance().formatTime(now);
				var item:ObjectProxy = new ObjectProxy({time:nowTime, gas:Math.round(Math.random() * 100) * .01});
				
				if(ac.length < 10)
				{
					ac.addItem(item);
				}
				else
				{
					ac.removeItemAt(0);
					ac.addItem(item);
				}
				
				trace(item.time, ":", item.gas);
			}
			
			protected function changeDashedLine(event:MouseEvent):void
			{
				nn = Math.round((Math.random() / 5 + 0.8) * 100) * .01;
			}
			
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
		<mx:SeriesInterpolate id="effect" duration="1000" />
		<fx:Number id="nn">0.3</fx:Number>
	</fx:Declarations>
	
	<s:Panel width="600" height="500" title="测试实时曲线">
		<s:controlBarContent>
			<s:HGroup width="100%" height="20" horizontalAlign="center" verticalAlign="middle">
				<s:Button label="start" click="startCalc(event)"/>
				<s:Button label="stop" click="stopCalc(event)"/>
				<s:Button label="change dashed line" click="changeDashedLine(event)"/>
			</s:HGroup>
		</s:controlBarContent>
		<mx:LineChart id="chart" width="500" height="400" horizontalCenter="0" showDataTips="true"
					  verticalCenter="0" dataProvider="{ac}" >
			<mx:backgroundElements>
				<mx:GridLines gridDirection="both"/>
				<chartClasses:DashedLines lineColor="0xFF0000" yValue="{nn}"/>
			</mx:backgroundElements>
			
			<mx:horizontalAxis>
				<mx:CategoryAxis categoryField="time" displayName="Time" title="时间" />
			</mx:horizontalAxis>
			
			<mx:verticalAxis>
				<mx:LinearAxis minimum="0" maximum="1"/>
			</mx:verticalAxis>
			
			<mx:series>
				<mx:LineSeries displayName="瓦斯" xField="time" yField="gas" form="curve"/>
			</mx:series>
		</mx:LineChart>
		
	</s:Panel>
</s:Application>


接下来是里面的DashedLines:
package lip.charts.chartClasses
{
	import flash.display.Graphics;
	import flash.geom.Point;
	
	import lip.utils.GraphicUtils;
	
	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();
		}

		private var _yValue:Number = NaN;

		/**
		 * 该线对应的y值
		 */
		public function get yValue():Number
		{
			return _yValue;
		}

		/**
		 * @private
		 */
		public function set yValue(value:Number):void
		{
			_yValue = 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
		{
			// TODO Auto Generated method stub
			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 y:Number = dataToLocal(0, yValue).y;
			
			var pFrom:Point = new Point(0, y);
			var pTo:Point = new Point(w, y);
			
			GraphicUtils.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);
		}
	}
}


还有其中用到的GraphicUtils.drawDashed()方法:

package lip.utils
{
	import flash.display.Graphics;
	import flash.geom.Point;

	/**
	 * 一些绘图相关的方法
	 * @author lip
	 */
	public class GraphicUtils
	{
		public function GraphicUtils()
		{
		}
		
		
		/**
		 * 画虚线
		 * @param graphics 你懂的
		 * @param pFrom 起点
		 * @param pTo 终点
		 * @param length 实线段的长度
		 * @param gap 实线段的间距
		 * @param thickness 线的宽度
		 * @param color 线的颜色
		 */
		public static 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;
			}
		}
	}
}


代码不太多,就不详细解释了。

你可能感兴趣的:(Flex,虚线,LineChart,水平线)