flex 图片旋转(解决公转和自转问题)
在Flex中图片的旋转是既有公转和自转的。这样在图片旋转的时候就有一定小麻烦;
为了更好地说明问题,先引入两个概念:“自转”和“公转”。想象一下,地球在绕着太阳公转的同时,它自己也在自转。Flash应用中的显示对象可以进行自身的自转,也可以绕着某个点公转,也可以两者同时进行。
实现旋转常用的方法
1) displayObject.rotation=degree; //实现显示对象的自转(flash|Flex)
2) spark.effects.Rotate; //实现显示对象的自转(Flex)
3) matrix.rotate; //同时实现显示对象的自转和公转(flash|Flex)
本文重点介绍matrix.rotate的实现细节。
最近做的一个小项目需要实现“图片绕中心旋转”的效果。在网上搜索了相关的资料,在很多帖子中都推荐使用Matrix来实现。代码如下:
var matrix:Matrix = img.transform.matrix;
matrix.translate(-img.width/2,-img.height/2);
matrix.rotate(radian);
matrix.translate(+img.width/2,+img.height/2);
img.transform.matrix = matrix;
相信做过“图片绕中心旋转”效果的朋友都见过这段代码。实现原理就是先把图片的中点移动到左上角,然后进行旋转操作,最后再把图片移回来。看起来很好理解,但是这段代码在我的Flex应用中却不能正常工作。又回到网上搜索了很长时间,发现这段代码出现在很多论坛博客中,没有一个说这段代码有问题的。通过测试,最后才发现了问题所在:此段代码需要在特定的前提下才能正常使用。这个前提下面会细说。现在我们先来看matix.rotate这个方法究竟做了什么。
matix.rotate做了什么
在Flash IDE中做了一系列试验:在场景中放置一个影片剪辑,影片剪辑的注册点分别在左上角和中心,影片剪辑的x,y分别在(0,0)和(70,70)。
试验的结论是:
matrix.rotate方法让目标对象同时进行“自转和公转”,旋转的实现跟“影片剪辑的注册点的位置”和“影片剪辑的初始位置”有很大的关系。详见下面的4个场景(灰色框为场景,黑色框为旋转目标):
场景1:影片剪辑的注册点在左上角,影片剪辑在场景中的初始位置为(0,0)。
结果:影片剪辑自转的同时绕着(0,0)公转。因为公转的半径为0,所以没有体现在图片上。
场景2:影片剪辑的注册点在左上角,影片剪辑在场景中的初始位置为(70,70)。
结果:影片剪辑自转的同时绕着(0,0)公转,公转的半径为70。
场景3:影片剪辑的注册点在中心,影片剪辑在场景中的初始位置为(0,0)。
结果:影片剪辑自转的同时绕着(0,0)公转,因为公转的半径为0,所以没体现在图上。
场景4:影片剪辑的注册点在中心,影片剪辑在场景中的初始位置为(125,30)。
结果:影片剪辑自转的同时绕着(0,0)公转,因为公转的半径为125。
在上面的这些场景中,第三个场景的影片剪辑是绕中心旋转的。也就是说,影片剪辑在满足以下两个条件时,才能使用matrix.rotate方法实现绕中心旋转。
1) 影片剪辑的注册点在中心;
2) 影片剪辑的中心点与场景(或父影片剪辑)的(0,0)重叠。
再重新观察上面的那段代码:
var matrix:Matrix = img.transform.matrix;
matrix.translate(-img.width/2,-img.height/2);
matrix.rotate(radian);
matrix.translate(+img.width/2,+img.height/2);
img.transform.matrix = matrix;
代码中使用了translate方法,很显然目的就是为了让img的中心点与父影片剪辑的(0,0)点重叠。所以,使用这段代码的前提条件是:
1) 在Flash IDE中开发;(才能调整注册点的位置)
2) 目标影片剪辑的注册点在中心;
3) 把目标影片剪辑放在一个空影片剪辑中,并设置x,y为(0,0)。
善了个哉的,网上这么多篇文章提到这段代码,居然没有一篇提到上述的条件,坑爹呐!
如果是在Flash IDE环境中进行开发,实现旋转还有一个更方便的可选项,那就是MatrixTransformer.rotateAroundInternalPoint和MatrixTransformer.rotateAroundExternalPoint。这两个静态方法用起来可比matrix.rotate方便多了。不需要考虑注册点的问题,也不需要把目标影片剪辑放到空的影片剪辑中。只可惜在Flex中没有这个类。
如何在Flex中实现旋转
在Flex环境中没有影片剪辑,它使用自己的一套组件,注册点默认在左上角,不能调整注册点的位置。我们如何实现组件的旋转呢?
1) 使用rotation属性。但是因不能调整组件的注册点,所以只能让组件绕左上角旋转。
2) 使用spark.effects.Rotate类。可以通过设置autoCenterTransform为true或false来控制组件是绕中心点旋转还是绕左上角旋转。
3) 使用matrix.rotate方法。通过控制组件的“自转”和“公转”来实现我们需要的旋转。
调用matrix.rotate方法,会使目标对象同时进行“自转”和“公转”,这可以从上面的场景2和场景4中明显看出。其实在场景1中和场景3中,目标对象也是同时进行了“自转”和“公转”,只是因为公转的半径为0,所以看不出来而已。
如果目标对象的初始位置不是(0,0)的话,如何实现目标对象的绕点旋转呢?首先,对于旋转目标的自转,我们不需要做什么。因为自转是必须的。而对于旋转目标的公转,我就需要做一些额外的操作了。因为公转改变了旋转目标的位置,这也是影响旋转目标是否绕点旋转的因素。调用matrix.rotate方法时,我们不能阻止旋转目标的公转,所以,解决办法只能是:在调用matrix.rotate之前,取得旋转中心点的位置,然后在旋转后,再取得旋转中心点的位置,然后计算点的位移,最后用matrix.translate方法将旋转目标调整到“正确位置”。
下面两组图是两个不同旋转中心下的旋转,旋转之后,我们再通过matrix.translate方法把旋转后的粉色的原点移动到它原始的状态及可。见图。
注册点在左上角,绕中心旋转。
注册点在左上角,绕左上角旋转。这种情况下,使用matrix.rotate方法显然是多余的,因为简单地使用displayObject.rotation属性就可以实现想要的旋转了。在这里我们使用matrix.rotate方法是为了更好地说明matrix.rotate方法的实现细节。
注册点在中心,绕中心点旋转。如果需要在Flash中用matrix.rotate方法实现旋转,且不依赖父影片剪辑,则使用该方法。
注册点在中心,绕左上角旋转。
最后提供一段代码,此代码实现让一个注册点在左上角的对象绕它的中心点旋转。代码如下:
//旋转之前获取旋转对象的中心点
var p1:Point = rotatedObject.localToGlobal(new Point(rotatedObject.width/2, rotatedObject.height/2));
//旋转
var matrix1:Matrix = rotatedObject.transform.matrix;
matrix1.rotate(radian);
rotatedObject.transform.matrix = matrix1;
//旋转后获取旋转对象的中心点
var p2:Point = rotatedObject.localToGlobal(new Point(rotatedObject.width/2, rotatedObject.height/2));
//位移
var matrix2:Matrix = rotatedObject.transform.matrix;
matrix2.translate(p1.x-p2.x,p1.y-p2.y);
rotatedObject.transform.matrix = matrix2;
2012-5-5补充:
更新一个新的旋转方式。这个方法是MatrixTransformer类中rotateAroundInternalPoint静态方法的做法。
假设有一个图片A,我们希望将图片绕O点旋转。O点在图片内部的坐标是(x,y)。我们可以先移动图片,让图片的O点与父容器的(0,0)点重合,调用rotate方法进行旋转,然后再将图片移动回正确的位置。代码如下:
var point:Point = new Point(x, y);
point = m.transformPoint(point);//将图片内部的点转换成父容器坐标的点
m.tx -= point.x;
m.ty -= point.y;
m.rotate(angleDegrees*(Math.PI/180));
m.tx += point.x;
m.ty += point.y;
MatrixTransformer类的另一个rotateAroundExternalPoint静态方法的做法类似,但是因为是以“外部的点”为旋转中心,所以代码有些不同:
var point:Point = new Point(x, y);
m.tx -= point.x;
m.ty -= point.y;
m.rotate(angleDegrees*(Math.PI/180));
m.tx += point.x;
m.ty += point.y;
在这个方法中,“外部的点”是在父容器的坐标空间中,所以不需要再转换该点了。
另一个旋转方式:
这个方法是某Transform tool中的做法。注意,这个方法跟上边补充的第一种方法不一样。
anchor = new Point(width/2, height/2); //旋转对象的坐标空间内旋转对象的中心点
// 把旋转对象的中心点转换成父容器坐标空间中的点
var globalAnchor:Point = matrix.transformPoint(anchor);
// calculates position
var m:Matrix = new Matrix(); //创建了一个新的matrix对象
//下面的操作是把这个matrix对象转化成我们想要的
m.translate(-anchor.x, -anchor.y);//将目标的中心点移动到与父容器坐标系统的(0,0)重叠
m.rotate((rotation + angle)*Math.PI/180);//旋转目标
m.translate(globalAnchor.x, globalAnchor.y);//将目标的中心点移动到合适的位置
为什么var globalAnchor:Point = matrix.transformPoint(anchor);能把旋转对象的中心点的坐标转换成旋转对象的父容器的坐标呢?
当旋转对象放在父容器中,没有应用任何matrix变形时,它的坐标系统和父容器的坐标系统是重叠的,也就是说,旋转对象的中心点在父容器坐标系统中的坐标就是它的本地坐标。当旋转对象发生matrix变形后,旋转对象的中心点在父容器坐标系统的坐标发生了变化,而这个变化正是应用在旋转对象上的matrix对象带来变形效果。因此,matrix的transformPoint方法能把本地坐标转换成父容器坐标。
左上角的图形是变形前的,右边的图形是变形之后的。中心点1的本地坐标是(2,2),因为在没有使用任何matrix效果时,它的本地坐标系统跟父容器的坐标系统是重叠的。因此它在父容器中的坐标也是(2,2)。这个点在经过matrix变形后,就变成了(9,5),也就是图形中心点在父容器坐标系统中的新坐标。
解决方案就是把图片放到父容器的(0,0)点进行旋转,在平一会你想好要的位置;
public function draw( displayTarget : Sprite , point : Point , index : int ) : void
{
var graphics : Graphics = displayTarget.graphics ;
var metrix : Matrix = new Matrix( 1.0 , 0.0 , 0.0 , 1.0 , 0 , 0 );
graphics.beginBitmapFill( this._image , metrix , false , true );
graphics.drawRect( 0,0, this.size, this.size);
graphics.endFill(); //求等腰三角形斜边长 的一办
var halfDiagonal : Number = (this.size/2)*Math.sqrt(2);
var rotateAngle : Number = 0; displayTarget.rotation = angle; if(0 <= angle && angle < 45)
{
rotateAngle = (angle+45)* (Math.PI/180); displayTarget.x = point.x - Math.cos(rotateAngle)*halfDiagonal;
displayTarget.y = point.y - Math.sin(rotateAngle)*halfDiagonal; }else if(45 <= angle && angle < 135)
{
rotateAngle = (angle - 45)* (Math.PI/180); displayTarget.x = point.x + (Math.sin(rotateAngle)*halfDiagonal);
displayTarget.y = point.y - (Math.cos(rotateAngle)*halfDiagonal);
} else if(135 <= angle && angle < 225)
{
rotateAngle = (angle - 135)* (Math.PI/180); displayTarget.x = point.x + (Math.cos(rotateAngle)*halfDiagonal);
displayTarget.y = point.y + (Math.sin(rotateAngle)*halfDiagonal);
} else if(225 <= angle && angle < 315)
{
rotateAngle = (angle - 225)* (Math.PI/180); displayTarget.x = point.x - (Math.sin(rotateAngle)*halfDiagonal);
displayTarget.y = point.y + (Math.cos(rotateAngle)*halfDiagonal);
} else if(315 <= angle && angle < 360)
{
rotateAngle = (angle - 315)* (Math.PI/180); displayTarget.x = point.x - (Math.cos(rotateAngle)*halfDiagonal);
displayTarget.y = point.y - (Math.sin(rotateAngle)*halfDiagonal);
} }
flex 图片旋转(解决公转和自转问题)的更多相关文章
- 使用Flex实现图片旋转。
当用flex实现图片旋转的时候,遇到了这样的问题:截图之后,图片还是会继续旋转,应该是canvas这个还有旋转的角度,所以看到效果跟你截图保存下来的效果不一样. 函数: 角度转换为弧度,这里面涉及到了 ...
- JQuery插件让图片旋转任意角度且代码极其简单
引入下方的jquery.rotate.js文件,然后通过$("选择器").rotate(角度);可以旋转任意角度, 例如$("#rotate-image").r ...
- Flex内存泄露解决方法和内存释放优化原则
Flex内存泄露解决方法和内存释放优化原则 你对Flex内存泄露的概念是否了解,这里和大家分享一下Flex内存释放优化原则和Flex内存泄露解决方法,希望本文的介绍能让你有所收获. Flex内存释放优 ...
- JS实现图片base64转blob对象,压缩图片,预览图片,图片旋转到正确角度
base64转blob对象 /** 将base64转换为文件对象 * @param {String} base64 base64字符串 * */ var convertBase64ToBlob = f ...
- file上传图片,base64转换、压缩图片、预览图片、将图片旋转到正确的角度
/** * 将base64转换为文件对象 * (即用文件上传输入框上传文件得到的对象) * @param {String} base64 base64字符串 */ function convertBa ...
- JQuery插件让图片旋转任意角度且代码极其简单 - 摘自网友
JQuery插件让图片旋转任意角度且代码极其简单 2012-04-01 09:57:03 我来说两句 收藏 我要投稿 引入下方的jquery.rotate.js文件,然后通过$ ...
- drawable-实现图片旋转
今天因为需要,所以要让一个图片随着某种需要进行旋转.但是,又不能一张张的做动态图片.所以就在网上找了这么个方法.但是,这个方法有个问题,就是虽然能实现图片的旋转.但是,图片旋转以后会进行缩放.具体原因 ...
- ios手机竖屏拍照图片旋转90°问题解决方法
手机拍照会给图片添加一个Orientaion信息(即拍照方向),如下: 用ios手机拍照,系统会给图片加上一个方向的属性, ios相机默认的拍照方向是后摄Home键在右为正,前摄Home键在左为正. ...
- H5 拍照图片旋转、压缩和上传
原文地址:github.com/whinc/blog/… 最近接到一个“发表评论”的需求:用户输入评论并且可以拍照或从相册选择图片上传,即支持图文评论.需要同时在 H5 和小程序两端实现,该需求处理图 ...
随机推荐
- js捕捉浏览器关闭事件-兼容几乎所有浏览器
很多时候我们都在困扰,如何捕获浏览器关闭事件,网上虽然有很多方法,但都不理想,后来终于找到了一个很好地实现方法,大家可以试试哦,支持几乎所有的浏览器 <script type="tex ...
- JavaWeb项目开发案例精粹-第2章投票系统-003Dao层
1. package com.sanqing.dao; import java.util.List; import com.sanqing.bean.Vote; import com.sanqing. ...
- React使用rAF动画介绍
一. <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF ...
- AE数据加载
1. 数据加载问题: 任何系统都离不开数据的加载,下边就AE中几种常用的数据加载做一个列举.以便查阅: 1.加载个人数据库 个人数据库是保存在Access中的数据库.其加载方式有两种:通过名字和通过属 ...
- VIM Taglist + ctags
Windows下 进入http://ctags.sourceforge.net/ 下载ctags 把ctags58.zip解压,随便放个地方,我放到了Home\Vim\vim72下,在ctags58文 ...
- java导出excel报表
1.java导出excel报表: package cn.jcenterhome.util; import java.io.OutputStream;import java.util.List;impo ...
- 基于Jquery+Ajax+Json+高效分页
摘要 分页我相信大家存储过程分页已经很熟悉了,ajax更是耳熟能详了,更别说我们的json,等等. 如果说您没用过这些东东的话,我相信看完这篇博文会对您有帮助的,,如果有任何问题不懂或者有bug没问题 ...
- toad for sqlserver5.7
toad for sqlserver5.7 虽然SSMS很好很强大,不过有时候使用一些第三方工具可以使MSSQL DBA们更加的方便管理MSSQL toad for sqlserver5.7就是这样一 ...
- tornado中使用torndb,连接数过高的问题
问题背景 最近新的产品开发中,使用了到了Tornado和mysql数据库.但在基本框架完成之后,我在开发时候发现了一个很奇怪的现象,我在测试时,发现数据库返回不了结果,于是我在mysql中输入show ...
- 结构体key
http://www.cnblogs.com/xpchild/p/3770823.html http://blog.sae.sina.com.cn/archives/3968 实例 http://bl ...