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;
}
}