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); }}
轉載于:https://www.cnblogs.com/youngKen/p/3430821.html
總結
以上是生活随笔為你收集整理的flex 图片旋转(解决公转和自转问题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【最新】docker 安装elastic
- 下一篇: [bzoj2743]采花