• 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,所以没有体现在图片上。

    matrix rotate - cruelchen - 请重启您的计算........

     

    场景2影片剪辑的注册点在左上角,影片剪辑在场景中的初始位置为(70,70)

    结果:影片剪辑自转的同时绕着(0,0)公转,公转的半径为70

    matrix rotate - cruelchen - 请重启您的计算........

     

    场景3影片剪辑的注册点在中心,影片剪辑在场景中的初始位置为(0,0)

    结果:影片剪辑自转的同时绕着(0,0)公转,因为公转的半径为0,所以没体现在图上。

    matrix rotate - cruelchen - 请重启您的计算........

    场景4影片剪辑的注册点在中心,影片剪辑在场景中的初始位置为(125,30)

    结果:影片剪辑自转的同时绕着(0,0)公转,因为公转的半径为125

    matrix rotate - cruelchen - 请重启您的计算........

     

    在上面的这些场景中,第三个场景的影片剪辑是绕中心旋转的。也就是说,影片剪辑在满足以下两个条件时,才能使用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.rotateAroundInternalPointMatrixTransformer.rotateAroundExternalPoint。这两个静态方法用起来可比matrix.rotate方便多了。不需要考虑注册点的问题,也不需要把目标影片剪辑放到空的影片剪辑中。只可惜在Flex中没有这个类。

     

    如何在Flex中实现旋转

    Flex环境中没有影片剪辑,它使用自己的一套组件,注册点默认在左上角,不能调整注册点的位置。我们如何实现组件的旋转呢?

    1)  使用rotation属性。但是因不能调整组件的注册点,所以只能让组件绕左上角旋转。

    2)  使用spark.effects.Rotate类。可以通过设置autoCenterTransformtruefalse来控制组件是绕中心点旋转还是绕左上角旋转。

    3)  使用matrix.rotate方法。通过控制组件的“自转”和“公转”来实现我们需要的旋转。

    调用matrix.rotate方法,会使目标对象同时进行“自转”和“公转”,这可以从上面的场景2和场景4中明显看出。其实在场景1中和场景3中,目标对象也是同时进行了“自转”和“公转”,只是因为公转的半径为0,所以看不出来而已。

    如果目标对象的初始位置不是(0,0)的话,如何实现目标对象的绕点旋转呢?首先,对于旋转目标的自转,我们不需要做什么。因为自转是必须的。而对于旋转目标的公转,我就需要做一些额外的操作了。因为公转改变了旋转目标的位置,这也是影响旋转目标是否绕点旋转的因素。调用matrix.rotate方法时,我们不能阻止旋转目标的公转,所以,解决办法只能是:在调用matrix.rotate之前,取得旋转中心点的位置,然后在旋转后,再取得旋转中心点的位置,然后计算点的位移,最后用matrix.translate方法将旋转目标调整到“正确位置”。

    下面两组图是两个不同旋转中心下的旋转,旋转之后,我们再通过matrix.translate方法把旋转后的粉色的原点移动到它原始的状态及可。见图。

    matrix rotate - cruelchen - 请重启您的计算........

    注册点在左上角,绕中心旋转。

    matrix rotate - cruelchen - 请重启您的计算........ 

    注册点在左上角,绕左上角旋转。这种情况下,使用matrix.rotate方法显然是多余的,因为简单地使用displayObject.rotation属性就可以实现想要的旋转了。在这里我们使用matrix.rotate方法是为了更好地说明matrix.rotate方法的实现细节。

     

    matrix rotate - cruelchen - 请重启您的计算........

    注册点在中心,绕中心点旋转。如果需要在Flash中用matrix.rotate方法实现旋转,且不依赖父影片剪辑,则使用该方法。

     

    matrix rotate - cruelchen - 请重启您的计算........

    注册点在中心,绕左上角旋转。

     

    最后提供一段代码,此代码实现让一个注册点在左上角的对象绕它的中心点旋转。代码如下:

    //旋转之前获取旋转对象的中心点

    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对象带来变形效果。因此,matrixtransformPoint方法能把本地坐标转换成父容器坐标。

    左上角的图形是变形前的,右边的图形是变形之后的。中心点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);
    }
    
    }
    

      

  • 相关阅读:
    09-13练习
    IDEA设置项目文件自动Add到Svn/Git
    虚拟机启动项目时报错
    微服务调用时报错
    查询每个月每一天的访问量
    在IDEA中关于项目java版本问题
    复习宝典之设计模式
    复习宝典之Maven项目管理
    复习宝典之Mysql数据库
    复习宝典之Redis
  • 原文地址:https://www.cnblogs.com/youngKen/p/3430821.html
Copyright © 2020-2023  润新知