Flex4 画线,把直线打折



 实现的效果:

1.选择直线的起始或结束节点时,可以移动直线

2.当按住Ctrl后,再点击直线,可以创建出一个折线,如下图:

Flex4 画线,把直线打折

基本思路:

当直线被MouseDown后,判断选择的位置,如果是起始或结束节点的范围,则移动该节点,重新绘制直线。

如果有Ctrl按下,则在MouseMove事件中根据鼠标的位置,绘制出一条拆线,当MouseUp后,添加一个新的UIComponent把那条拆线重新绘制一次。

 

UXLine 简单地封装了画直线的类

package cn.ui
{
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	
	import mx.collections.ArrayCollection;
	import mx.core.UIComponent;
	
	import spark.filters.GlowFilter;
	
	/**
	 * 线条类
	 * [email protected]
	 **/
	public class UXLine extends UIComponent
	{
		/** 常量0,未选择节点 */
		public static const SELECTED_NONE_NODE:int = 0;
		/** 常量1,选择了From节点 */
		public static const SELECTED_FROM_NODE:int = 1;
		/** 常量2,选择了To节点 */
		public static const SELECTED_TO_NODE:int = 2;
		
		/** 选择了From 或To节点 LineMove的事件 */
		public static const EVENT_LINE_NODE_MOVE:String = "EVENT_LINE_NODE_MOVE";
		/** 拆线形成拆线的事件 */
		public static const EVENT_LINE_BROKEN:String = "EVENT_LINE_BROKEN";
		
		private var _xFrom:Number = 0;
		private var _xTo:Number = 0;
		private var _yFrom:Number = 0;
		private var _yTo:Number = 0;
		
		private var _selectedNode:int = SELECTED_NONE_NODE;
		private var _lineStyle:int = 2;
		private var _lineColor:uint = 0x0099ff;
		
		// 关联的线条
		//private var _linkLines:ArrayCollection = new ArrayCollection;
		private var _linkLines:Dictionary = new Dictionary;
		
		/** 有效范围(半径) */
		private const _EFFECT_RANGE:int = 3;
		
		public function UXLine()
		{
			super();
			this._selectedNode = SELECTED_NONE_NODE;
			this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		}
		
		
		/** 0 未选择,1选择了起始节点,2选择了结束节点 */
		public function get selectedNode():int
		{
			return _selectedNode;
		}

		public function get yTo():Number
		{
			return _yTo;
		}

		public function set yTo(value:Number):void
		{
			_yTo = value;
		}

		public function get yFrom():Number
		{
			return _yFrom;
		}

		public function set yFrom(value:Number):void
		{
			_yFrom = value;
		}

		public function get xTo():Number
		{
			return _xTo;
		}

		public function set xTo(value:Number):void
		{
			_xTo = value;
		}

		public function get xFrom():Number
		{
			return _xFrom;
		}

		public function set xFrom(value:Number):void
		{
			_xFrom = value;
		}

		public function set lineStyle(value:int):void{
			_lineStyle = value;
		}
		public function get lineStyle():int{
			return _lineStyle;
		}
		public function set lineColor(value:uint):void{
			_lineColor = value
		}
		public function get lineColor():uint{
			return _lineColor;
		}
		
		/**
		 * 绑定MouseDown事件 
		 **/
		private function onMouseDown(event:MouseEvent):void{
			var eventType:String = EVENT_LINE_NODE_MOVE;// 线节点移动
			
			this._selectedNode = SELECTED_NONE_NODE;
			// 判断鼠标的位置,如果位于起点或终点的一个有效区域范围内时,触发可移动事件
			var mousePoint:Point = new Point(event.localX, event.localY);
			if(isInRange(_xFrom, _yFrom, event.localX, event.localY)){
				this._selectedNode = SELECTED_FROM_NODE;
			}else if(isInRange(_xTo, _yTo, event.localX, event.localY)){
				this._selectedNode = SELECTED_TO_NODE;
			}else if(event.ctrlKey){
				// 生成新的线条的时候
				eventType = EVENT_LINE_BROKEN;
			}else{
				// 其他事件,由外层容器去实现
				return;
			}
			
			// 阻击冒泡,并派发自己的事件
			event.stopPropagation(); 
			var newEvent:MouseEvent = new MouseEvent(eventType, true);
			newEvent.localX = event.stageX;    
			newEvent.localY = event.stageY; 
			dispatchEvent(newEvent);
		}
		
		/**
		 * 检测某一点是否在另一个点的范围内
		 * @param x 
		 * @param y  
		 * @param testX 测试点X坐标
		 * @param testY 测试点Y坐标
		 * @param effectRange 有效半径
		 **/
		private function isInRange(x:int, y:int, testX:int, testY:int, effectRange:int=_EFFECT_RANGE):Boolean{
			return ((x - effectRange <= testX) && (x + effectRange >= testX)
				&& (y - effectRange <= testY) && (y + effectRange >= testY));
		}
		
		/**
		 * 绘制直线
		 **/ 
		public function draw():void{
			this.graphics.clear();
			this.graphics.lineStyle(_lineStyle,_lineColor,1); 
			this.graphics.moveTo(_xFrom, _yFrom);
			this.graphics.lineTo(_xTo, _yTo);
		}
		
		/**
		 * 绘制拆线
		 **/ 
		public function draw2Line(pointX:int, pointY:int):void{
			this.graphics.clear();
			this.graphics.lineStyle(_lineStyle,_lineColor,1); 
			this.graphics.moveTo(_xFrom, _yFrom);
			this.graphics.lineTo(pointX, pointY);
			this.graphics.lineTo(_xTo, _yTo);
		}
	}
}

 

不废话,直接上MXML

<?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" minWidth="955" minHeight="600" creationComplete="onLoad();" >
	<fx:Style source="BrokenLineDemo.css"/>
	
	<fx:Script>
		<![CDATA[
			import cn.ui.UXCanvas;
			import cn.ui.UXLine;
			
			import flash.display.Sprite;
			import flash.geom.Point;
			
			import mx.core.DragSource;
			import mx.core.UIComponent;
			import mx.events.DragEvent;
			import mx.events.MenuEvent;
			import mx.managers.DragManager;
			
			// 最原始的线条对象
			private var uxLine:UXLine = new UXLine;
			// 拖动初始点
			private var dragPoint:Point = new Point;
			
			// 当前线条对象
			private var currentLine:UXLine = null;
			
			private function onLoad():void{
				// 初始化表格线
				initGridLine(mxCanvas);
				
				// 初始化uxLine
				uxLine.xFrom = 50;
				uxLine.yFrom = 50;
				uxLine.xTo = 250;
				uxLine.yTo = 250;
				uxLine.draw();
				
				mxCanvas.addElement(uxLine);
				
				mxCanvas.addEventListener(UXLine.EVENT_LINE_BROKEN, onLineBroken);
				mxCanvas.addEventListener(UXLine.EVENT_LINE_NODE_MOVE, onLineNodeMove);
							}
						
			
			// 线条分割事件
			private function onLineBroken(event:MouseEvent):void{
				if(event.target is UXLine){
					currentLine = UXLine(event.target);
					systemManager.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove4LB, true); 
					systemManager.addEventListener(MouseEvent.MOUSE_UP, onMouseUp4LB, true); 
				}
			}
			// 线条分割选择点后 开始移动
			private function onMouseMove4LB(event:MouseEvent):void{
				event.stopImmediatePropagation();
				if(currentLine != null){
					currentLine.draw2Line(event.localX, event.localY);
				}
			}
			// 线条分割选择点后 移动完成
			private function onMouseUp4LB(event:MouseEvent):void{
				event.stopImmediatePropagation();
				systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove4LB, true); 
				systemManager.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp4LB, true );
				
				var pointX:Number = event.localX;
				var pointY:Number = event.localY;
				// 把线条拆分开,即新增加一条线来实现
				if(currentLine != null){
					var newLine:UXLine = new UXLine;
					newLine.xFrom = currentLine.xFrom;
					newLine.yFrom = currentLine.yFrom;
					newLine.xTo = pointX;
					newLine.yTo = pointY;
					newLine.draw();
					mxCanvas.addElement(newLine);
					
					currentLine.graphics.clear();
					currentLine.xFrom = pointX;
					currentLine.yFrom = pointY;
					currentLine.draw();
					//mxCanvas.removeElement(currentLine);
				}
				currentLine = null;
			}
			
			// 选择线起点或终点的移动事件
			private function onLineNodeMove(event:MouseEvent):void{
				if(event.target is UXLine){
					currentLine = UXLine(event.target);
					systemManager.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove4Line, true); 
					systemManager.addEventListener(MouseEvent.MOUSE_UP, onMouseUp4Line, true);
				}
			}
			
			// 选择线起点或终点的移动事件
			private function onMouseMove4Line(event:MouseEvent):void{
				event.stopImmediatePropagation();
				
				if(currentLine != null){
					if(currentLine.selectedNode == UXLine.SELECTED_FROM_NODE){
						currentLine.xFrom = event.localX;
						currentLine.yFrom = event.localY;
					}else if(currentLine.selectedNode == UXLine.SELECTED_TO_NODE){
						currentLine.xTo = event.localX;
						currentLine.yTo = event.localY;
					}
					currentLine.draw();
				}
			}
			
			// 释放移动动作
			private function onMouseUp4Line(event:MouseEvent):void{
				event.stopImmediatePropagation();  
				systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove4Line, true); 
				systemManager.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp4Line, true );
				currentLine = null;
			}
			
			
			/**
			 *  初始化表格线条
			 **/
			private function initGridLine(uiComponent:UIComponent):void{
				const LINE_LENGTH:int = 4;
				const LINE_MARGIN:int = 2;
				const LINE_OFFSET:int = 24;
				var rowIndex:int;
				var colIndex:int;
				var rowCount:int = Math.floor(this.height / LINE_OFFSET);
				var colCount:int = Math.floor(this.width / LINE_OFFSET);
				var startX:Number;
				var startY:Number;
				var endX:Number;
				var endY:Number;
				var lineIndex:int;
				var lineCount:int;
				var lineLength:int = (LINE_LENGTH + LINE_MARGIN);
				var thickness:Number = 0.5;
				var lineColor:uint = 0x000000;
				
				uiComponent.graphics.clear();
				uiComponent.graphics.beginFill(0xFFFFFF);
				uiComponent.graphics.drawRect(0, 0, this.width, this.height);
				uiComponent.graphics.endFill();
				
				uiComponent.graphics.lineStyle(thickness, lineColor, 0.5);
				
				// 画出横线
				lineCount = Math.floor(uiComponent.width / lineLength);
				for(rowIndex = 1; rowIndex <= rowCount; rowIndex ++){
					startY = endY = rowIndex * LINE_OFFSET;
					if(rowIndex%2 == 0){
						thickness = 1;
						uiComponent.graphics.lineStyle(thickness, lineColor, 0.3);
					}else{
						thickness = 0.5;
						uiComponent.graphics.lineStyle(thickness, lineColor, 0.1);
					}
					for(lineIndex = 0; lineIndex < lineCount; lineIndex ++){
						startX = lineIndex * lineLength;
						endX = startX + LINE_LENGTH; 
						uiComponent.graphics.moveTo(startX, startY);
						uiComponent.graphics.lineTo(endX, endY);
					}
				}
				// 画出竖线
				lineCount = Math.floor(uiComponent.height / lineLength);
				for(colIndex = 1; colIndex <= colCount; colIndex ++){
					startX = endX = colIndex * LINE_OFFSET;
					if(colIndex % 2 == 0){
						thickness = 1;
						uiComponent.graphics.lineStyle(thickness, lineColor, 0.3);
					}else{
						thickness = 0.5;
						uiComponent.graphics.lineStyle(thickness, lineColor, 0.1);
					}
					
					for(lineIndex = 0; lineIndex < lineCount; lineIndex ++){
						startY = lineIndex * lineLength;
						endY = startY + LINE_LENGTH;
						uiComponent.graphics.moveTo(startX, startY);
						uiComponent.graphics.lineTo(endX, endY);
					}
				}
			}
			
		]]>
	</fx:Script>
	<mx:Canvas id="mxCanvas" height="100%" width="100%">
		<s:Label text="提示:按住Ctrl再选择线条画折线,选择线的两端可移动线条" toolTip="按住Ctrl再选择线条画折线"  x="278" y="11"/>
	</mx:Canvas>
	
</s:Application>