글
MS PowerPoint를 보면 화살표를 만들어 배치하고 화살표를 이동, 회전, 크기 등을 자유롭게 조정하는 기능이 있다. 나는 Flex로 간단하게 이러한 기능을 구현하는 것을 만들어 보았다. 일
단 아래 실행화면을 보면 알 수 있듯이 두께조정, 색선택을 한 후 Create Arrow 버튼을 누르면 화면에 한개의 화살표가
생성된다. 이 생성된 화살표를 선택하면 이동이 가능하고 화살표의 양 끝단을 선택하여 움직이면 회전 및 크기 조정이 가능하다. 기능의 개선여지는 충분히 많다.
1. 선택시에만 양끝단 원이 보이도록하고 다른 화살표는 원을 없애준다. 2. 선택후 색과 두께를 자유롭게 선택할 수 있게 3. 화살표 모양을 선택할 수 있게 4. Thumbnail이 있고 그것을 드래그 해서 화면에 배치해서 화살표를 생성시킬 수 있도록 5. 선택후 화살표를 삭제할 수 있도록
화살표를 회전할 때는 고등학교 수학시간때 배운 회전행렬(http://blog.naver.com/elsacred/50008430063 )을 이용했다. 코드를 보시면 아시겠지만 그리 효율적이지 못하다. 이 글을 보시고 기능 개선 및 추가해주셔서 공개해주면 고맙겠다. 또 필요한 곳에서 유용하게 쓰길 바란다.
실행화면
")
실행코드
ArrowTest.mxml (Language : xml)
<?xml version ="1.0" encoding ="utf-8" ?> <mx:Application xmlns:mx ="http://www.adobe.com/2006/mxml" layout ="absolute" > <mx:Script> <![CDATA[ private var arrow:Arrow; //화살표 생성 private function createArrow( thickness:Number, color:uint ):void { arrow = new Arrow( 100, 100, thickness, color ); arrow.x = 200; arrow.y = 300; this.addChild( arrow ); } ]]> </mx:Script> <mx:NumericStepper id ="lineThickness" x ="10" y ="10" value ="3" maximum ="5" minimum ="1" /> <mx:ColorPicker id ="lineColor" x ="76" y ="10" selectedColor ="#ff0000" /> <mx:Button x ="106" y ="10" label ="Create Arrow" click ="createArrow( lineThickness.value, lineColor.selectedColor )" /> </mx:Application>
Arrow.as (Language : java)
package { import mx.core.UIComponent; import mx.events.ResizeEvent; import flash.display.Sprite; import flash.display.SpreadMethod; import mx.events.FlexEvent; import flash.events.MouseEvent; import flash.ui.Mouse; public class Arrow extends UIComponent { private var header:Sprite; //화살표 머리 부분 Selecter private var footer:Sprite; //화살표 발부분 Selecter private var arrow:Sprite; //화살표 그림 private var thickness:Number ; //화살표 두께 private var color:uint; //화살표 색 //생성자 public function Arrow( width:Number , height:Number , thickness:Number =1.0 , color:uint=0x000000 ) { super ( ) ; this .thickness = thickness; this .color = color; //화살표 머리 생성 header = new Sprite( ) ; header.addEventListener ( MouseEvent .MOUSE_DOWN , onMouseDown ) ; header.graphics .clear ( ) ; header.graphics .lineStyle ( 1.0 , 0x000000, 0.5 ) ; header.graphics .beginFill ( 0xffffff,0.5 ) ; header.graphics .drawCircle ( 0 , 0 , 5 ) ; header.graphics .endFill ( ) ; header.x = width; header.y = height; //화살표 발 생성 footer = new Sprite( ) ; footer.graphics .clear ( ) ; footer.graphics .lineStyle ( 1.0 , 0x000000, 0.5 ) ; footer.graphics .beginFill ( 0xffffff, 0.5 ) ; footer.graphics .drawCircle ( 0 , 0 , 5 ) ; footer.graphics .endFill ( ) ; footer.x = 0 ; footer.y = 0 ; footer.addEventListener ( MouseEvent .MOUSE_DOWN , onMouseDown ) ; //화살표 생성 arrow = new Sprite; arrow.addEventListener ( MouseEvent .MOUSE_DOWN , onMouseDown ) ; draw( ) ; //addChild의 순서는 중요하다. 이는 Event target과 관련된다. this .addChild ( arrow ) ; this .addChild ( header ) ; this .addChild ( footer ) ; } //화살표를 그려준다. (회전행렬 사용 ) private function draw( ) :void { var x1:Number = header.x ; //화살표 앞쪽 x축값 var y1:Number = header.y ; //화살표 앞쪽 y축값 var x2:Number = footer.x ; //화살표 뒤쪽 x축값 var y2:Number = footer.y ; //화살표 뒤쪽 y축값 var angle:Number = Math .atan2 ( y1-y2, x1-x2 ) ; //화살표의 회전각도 var headSize:Number = this .thickness* 3 ; //화살표의 헤더부분 길이 var Degree2Radian:Number = Math .PI /180 ; //Degree -> Radian을 바꿔줄때 이 값을 곱함 var cos1:Number = Math .cos ( Degree2Radian * 45 ) ; //화살표 촉의 x축값은 cos(45도 ) 임 var sin1:Number = Math .sin ( Degree2Radian * 45 ) ; //화살표 촉의 y축값은 sin(45도) 임 var cos2:Number = Math .cos ( angle ) ; //화살표 회전에 대한 cos 값 var sin2:Number = Math .sin ( angle ) ; //화살표 회전에 대한 sin 값 var length:Number = Math .sqrt ( Math .abs ( x1-x2) *Math .abs ( x1-x2) + Math .abs ( y1-y2) *Math .abs ( y1-y2) ) ; //화살표 길이 var dx:Number = length - headSize * cos1; //화살표 촉 양 끝단 x축 값 var dy1:Number = headSize * sin1; //화살표 촉 양 끝단 y축 값 1 var dy2:Number = -headSize * sin1; //화살표 촉 양 끝단 y축 값 2 //회전에 의한 화살표 양 끝단의 위치 (2차 회전행렬 공식 이용 ) var newX1:Number = x2 + ( dx * cos2 - dy1 * sin2) ; var newY1:Number = y2 + ( dx * ( +sin2) + dy1 * cos2) ; var newX2:Number = x2 + ( dx * cos2 - dy2 * sin2) ; var newY2:Number = y2 + ( dx * ( +sin2) + dy2 * cos2) ; //계산된 좌표값을 이용해 화살표를 다시 그림 arrow.graphics .clear ( ) ; arrow.graphics .lineStyle ( this .thickness , this .color , 1.0 ) ; arrow.graphics .moveTo ( x1, y1 ) ; arrow.graphics .lineTo ( x2, y2 ) ; arrow.graphics .moveTo ( x1, y1 ) ; arrow.graphics .lineTo ( newX1, newY1 ) ; arrow.graphics .moveTo ( x1, y1 ) ; arrow.graphics .lineTo ( newX2, newY2 ) ; } //마우스 Down private function onMouseDown( e:MouseEvent ) :void { var sprite:Sprite = e.target as Sprite; if ( null != sprite ) { if ( sprite == header ) { sprite.addEventListener ( MouseEvent .MOUSE_MOVE , onMouseMove ) ; sprite.addEventListener ( MouseEvent .MOUSE_UP , onMouseUp ) ; sprite.startDrag ( ) ; trace( "화살표 앞쪽 선택함" ) ; } else if ( sprite == footer ) { sprite.addEventListener ( MouseEvent .MOUSE_MOVE , onMouseMove ) ; sprite.addEventListener ( MouseEvent .MOUSE_UP , onMouseUp ) ; sprite.startDrag ( ) ; trace( "화살표 뒷쪽 선택함" ) ; } else { this .startDrag ( ) ; this .addEventListener ( MouseEvent .MOUSE_MOVE , onMouseMove ) ; this .addEventListener ( MouseEvent .MOUSE_UP , onMouseUp ) ; trace( "화살표 중간 선택함" ) ; } } } //마우스 Move private function onMouseMove( e:MouseEvent ) :void { draw( ) ; e.updateAfterEvent ( ) ; } //마우스 Up private function onMouseUp( e:MouseEvent ) :void { var sprite:Sprite = e.target as Sprite; if ( null != sprite ) { sprite.removeEventListener ( MouseEvent .MOUSE_MOVE , onMouseMove ) ; sprite.removeEventListener ( MouseEvent .MOUSE_UP , onMouseUp ) ; sprite.stopDrag ( ) ; } else { this .removeEventListener ( MouseEvent .MOUSE_MOVE , onMouseMove ) ; this .removeEventListener ( MouseEvent .MOUSE_UP , onMouseUp ) ; this .stopDrag ( ) ; } draw( ) ; } } }
참고사이트회전행렬 : http://blog.naver.com/elsacred/50008430063
글쓴이 : 지돌스타 (http://blog.jidolstar.com/188
by <!--r'i"z&i\n+#]]x juree23
2008/06/14 11:04
트랙백
Trackback : http://eguru.co.kr/trackback/79
RECENT COMMENT