import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.geom.Point; import mx.containers.Canvas; import mx.controls.Image; import mx.events.ResizeEvent; /** * 图片浏览器 * 利用仿射变矩阵实现图片的平移、放缩和旋转 * 其中放缩和平移已经集成在滚轮事件中,放缩调用zoom方法,旋转调用roll方法,居中复位调用reset方法 * @author lijy 20160114 * */ public class ImageViewer extends Canvas { //图片对象 private var _image:Image = null; //鼠标按下时记录的位置信息,用于平移时计算平移量 private var _mouseDownPoint:Point = null; //记录总放缩比 private var _totalScaleRatio:Number = 1; /** * 最大放缩比,最大放缩量由放缩比确定 * */ public var maxScaleRatio:Number = 5; /** * 最小放缩边长,最小放缩量由最小边长确定 * */ public var minScaleLength:Number = 50; /** * 加载图像或 SWF 文件 * */ public function load(url:Object=null):void{ this._image.load(url); } /** * 获取作为内容加载的 URL、对象、类或类的字符串名称 * */ public function get source():Object{ return this._image.source; } /** * 设置作为内容加载的 URL、对象、类或类的字符串名称 * */ public function set source(value:Object):void{ this._image.source=value; } /** * 构造函数初始化图片对象 * */ public function DistImageViewer(){ this._image = new Image(); } /** * 添加Image到Canvas中,并添加鼠标事件监听 * */ override protected function createChildren():void{ this.addChild(this._image); this._image.addEventListener(MouseEvent.MOUSE_DOWN,imgMouseDown); this._image.addEventListener(MouseEvent.MOUSE_MOVE,imgMouseMove); this._image.addEventListener(MouseEvent.MOUSE_WHEEL,imgMouseWheel); this._image.addEventListener(ResizeEvent.RESIZE,imgSizeChanged); this._image.addEventListener(Event.COMPLETE,imgLoadComplete); super.createChildren(); } /** * 设置滚轮策略,但是貌似不起作用,需要在调用处重新设置 * */ override protected function updateDisplayList(w:Number, h:Number):void{ this.setStyle('verticalScrollPolicy','off'); this.setStyle('horizontalScrollPolicy','off'); super.updateDisplayList(w,h); } /** * 鼠标滚轮事件处理用于放缩图片 * 图片默认的放缩是以左上角为中心点的,要实现以光标位置为中心放缩,需要在放缩后平移图片以保持光标点位置不变 * */ private function imgMouseWheel(e:MouseEvent):void{ //本次放缩比 var scaleRatio:Number = e.delta>0?1.1:0.9; this.zoom(scaleRatio); e.stopPropagation(); } /** * 鼠标点击时,记录点击位置信息,用于在平移时计算平移量 * */ private function imgMouseDown(e:MouseEvent):void{ var matrix:Matrix = this._image.transform.matrix; var x:Number = matrix.tx-this.contentMouseX; var y:Number = matrix.ty-this.contentMouseY; _mouseDownPoint = new Point(x,y); } /** * 鼠标移动,使用鼠标按下时记录的位置信息平移图片 * */ private function imgMouseMove(e:MouseEvent):void{ if(e.buttonDown && _mouseDownPoint!=null){ var matrix:Matrix = this._image.transform.matrix; matrix.tx = _mouseDownPoint.x+this.contentMouseX; matrix.ty = _mouseDownPoint.y+this.contentMouseY; this._image.transform.matrix = matrix; } } /** * 重新加载新的图片后会引起尺寸改变,此事件用于重新加载图片后居中图片 * 对于尺寸一样的两个图片,参见imgLoadComplete * */ private function imgSizeChanged(e:Event):void{ this.reset(); } /** * 图片加载完成时会触发该事件,但如果此时获取图片的尺寸仍然会得到上一个图片的尺寸 * 因此在该事件仅能用于居中前后两个尺寸一样的图片,对于尺寸不一样的两个图片,参见imgSizeChanged * */ private function imgLoadComplete(e:Event):void{ this.reset(); } /** * 图片放缩 * @scaleRatio 图片放缩比,通常放大用1.1,缩小用0.9 * */ public function zoom(scaleRatio:Number):void{ //如果超出放缩比则直接返回 if(_totalScaleRatio*scaleRatio>maxScaleRatio || _totalScaleRatio*scaleRatio*_image.width<minScaleLength || _totalScaleRatio*scaleRatio*_image.height<minScaleLength) return; //获取图片变换矩阵 var matrix:Matrix = this._image.transform.matrix; //把图片参照系上的鼠标点转换为父容器屏幕参照系坐标 var mousePoint:Point = matrix.transformPoint(new Point(this._image.contentMouseX,this._image.contentMouseY)); //计算图片放缩后光标所在点位置的偏移量,用于放缩后把平移图片,使得放缩后光标所在点位置不变 var dx:Number=(mousePoint.x-matrix.tx)*(1-scaleRatio)+matrix.tx; var dy:Number=(mousePoint.y-matrix.ty)*(1-scaleRatio)+matrix.ty; //放缩图片 matrix.scale(scaleRatio,scaleRatio); //重置图片平移量 matrix.tx=dx; matrix.ty=dy; //应用变换矩阵 this._image.transform.matrix = matrix; _totalScaleRatio*=scaleRatio; } /** * 图片旋转,先平移图片使图片中心点与参照系原点重叠,然后旋转图片,最后把图片平移回原位 * @angle 旋转角度,正数顺时针,负数逆时针 * */ public function roll(degree:Number = 90):void{ var angle:Number = degree * (Math.PI / 180); var matrix:Matrix = this._image.transform.matrix; var centerPoint:Point = matrix.transformPoint(new Point(this._image.width/2, this._image.height/2)); matrix.translate(-centerPoint.x, -centerPoint.y); matrix.rotate(angle); matrix.translate(centerPoint.x, centerPoint.y); this._image.transform.matrix = matrix; } /** * 图片居中复位 * 其中tx和ty的偏移量中额外添加了一个像素的负偏移量,用于强制图片在初始化状态的时候被Canvas容器压盖 * 否则图片将浮与Canvas上面,而无法被Canvas边框裁剪,(似乎是Flex的Bug) * */ public function reset():void{ var wScale:Number = this.width/this._image.width; var hScale:Number = this.height/this._image.height; var scale:Number = wScale<hScale?wScale:hScale; var offsetX:Number = (this.width-this._image.width*scale)/2-1; var offsetY:Number = (this.height-this._image.height*scale)/2-1; var matrix:Matrix = new Matrix(scale,0,0,scale,offsetX,offsetY); this._image.transform.matrix=matrix; _totalScaleRatio = scale; } }