11
2019
12

沿任意轨迹拖动

工作中遇到几个组件开发的功能:1、沿一条纵向的线段拖动,2、沿一条横向的线段拖动,3、沿圆形的轨迹拖动。

想了想,其实可以归为一类问题,分两步实现。

第一步,实现自由拖拽;

第二步,约束到指定的轨迹上。

有点类似于物理引擎里边的约束。

实现起来并不难,先看效果:

获得 Adobe Flash Player

代码如下:

package  {
	
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	
	public class Main extends MovieClip{
		
		public var mc1: MovieClip;
		public var mc2: MovieClip;
		public var mc3: MovieClip;
		private var constraintV: VerticalLineConstraint = new VerticalLineConstraint(new Point(100, 100), 200);
		private var constraintH: HorizontalLineConstraint = new HorizontalLineConstraint(new Point(200, 100), 200);
		private var constraintC: CircleConstraint = new CircleConstraint(new Point(300, 250), 100, 0, 360);
		
		public function Main() {
			// constructor code
			stage?initStage(null):addEventListener(Event.ADDED_TO_STAGE, initStage);
		}
		
		private function initStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, initStage);
			
			drag(mc1);
			drag(mc2);
			drag(mc3);
			
			
			var p1: Point = constraintV.getPercentP(0);
			mc1.x = p1.x;
			mc1.y = p1.y;
			mc1.mouseChildren = false;
			
			var p2: Point = constraintH.getPercentP(0);
			mc2.x = p2.x;
			mc2.y = p2.y;
			mc2.mouseChildren = false;
			
			var p3: Point = constraintC.getPercentP(0);
			mc3.x = p3.x;
			mc3.y = p3.y;
			mc3.mouseChildren = false;
			
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		
		private function enterFrameHandler(e:Event):void 
		{
			updateMc(mc1, constraintV);
			updateMc(mc2, constraintH);
			updateMc(mc3, constraintC);
		}
		
		private function updateMc(mc: MovieClip, constraint: IConstraint):void {
			var p: Point = constraint.getConstraintP(new Point(mc.x, mc.y));
			mc.x = p.x;
			mc.y = p.y;
			mc.tf.text = Math.floor(constraint.getPercent(p) * 100) + "%";
		}
		
		//-----------------------------
		private var curSp:Sprite;
		private var draged:Boolean = false;
		
		private function drag(sp:Sprite):void
		{
			sp.buttonMode = true;
			sp.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		}
		
		private function mouseDownHandler(e:MouseEvent):void
		{
			curSp = e.currentTarget as Sprite;
			curSp.startDrag();
			addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.addEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
		}
		
		private function mouseUpHandler(e:MouseEvent):void
		{
			curSp.stopDrag();
			curSp = null;
			removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.removeEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
		}
		
		private function mouseMoveHandler(e:MouseEvent):void
		{
			//
			draged = true;
		}
		
	}
	
}
import flash.geom.Point;

interface IConstraint{
	function getPercentP(per: Number):Point;
	function getConstraintP(p: Point):Point;
	function getPercent(p: Point):Number;
}

class VerticalLineConstraint implements IConstraint{
	public var p0: Point;
	public var length: Number;
	public function VerticalLineConstraint(p0: Point, length: Number){
		this.p0 = p0;
		this.length = length;
	}
	
	public function getPercentP(per: Number):Point{
		return new Point(p0.x, p0.y + length * per);
	}
	
	public function getConstraintP(p: Point):Point{
		p = p.clone();
		p.y = Utils.limitAB(p.y, p0.y, p0.y + length);
		p.x = p0.x;
		return p;
	}
	
	public function getPercent(p: Point):Number{
		return (p.y - p0.y) / length;
	}
	
}

class HorizontalLineConstraint implements IConstraint{
	public var p0: Point;
	public var length: Number;
	public function HorizontalLineConstraint(p0: Point, length: Number){
		this.p0 = p0;
		this.length = length;
	}
	
	public function getPercentP(per: Number):Point{
		return new Point(p0.x + length * per, p0.y);
	}
	
	public function getConstraintP(p: Point):Point{
		p = p.clone();
		p.x = Utils.limitAB(p.x, p0.x, p0.x + length);
		p.y = p0.y;
		return p;
	}
	
	public function getPercent(p: Point):Number{
		return (p.x - p0.x) / length;
	}
	
}

class CircleConstraint implements IConstraint{
	public var p0: Point;
	public var r: Number;
	public var ang0: Number;
	public var ang1: Number;
	public function CircleConstraint(p0: Point, r: Number, ang0: Number, ang1: Number){
		this.p0 = p0;
		this.r = r;
		this.ang0 = ang0;
		this.ang1 = ang1;
	}
	
	public function getPercentP(per: Number):Point{
		var ang: Number = Utils.ang2rad(per * (ang1 - ang0) + ang0);
		return getAngP(ang);
	}
	
	public function getConstraintP(p: Point):Point{
		var per: Number = getPercent(p);
		per = Utils.limitAB(per, 0, 1);
		return getPercentP(per);
	}
	
	public function getPercent(p: Point):Number{
		var ang: Number = Utils.rad2ang(Math.atan2(p.y - p0.y, p.x - p0.x));
		if (ang < 0){
			ang += 360;
		}
		return (ang - ang0) / (ang1 - ang0);
	}
	
	private function getAngP(ang:Number):Point{
		return new Point(p0.x + r * Math.cos(ang), p0.y + r * Math.sin(ang));
	}
	
}

class Utils{
	public static function limitAB(x: Number, a:Number, b: Number):Number{
		if (a > b){
			var t: Number = a;
			a = b;
			b = t;
		}
		if (x < a){
			return a;
		}
		if (x > b){
			return b;
		}
		return x;
	}
	
	public static function ang2rad(ang: Number): Number{
		return ang * Math.PI / 180;
	}
	
	public static function rad2ang(rad: Number): Number{
		return rad * 180 / Math.PI;
	}
	
}

其中getConstraintP方法可以由另外两个方法组合得到。


源码打包下载

« 上一篇下一篇 »

相关文章:

按下拖动双击编辑  (2016-4-21 9:31:28)

tree组件拖动改变节点顺序  (2016-4-21 8:52:5)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。