HEART-MAKER
----------------------------------
昨晩つくった線分上のドラッグ試作プログラム「線分AB上のアリア」
(cf: http://wonderfl.net/code/553e5fb0b2dbc9b6b088bf8fae5f8d5fcff0a50c )
のハート形アイコンがあまりにもカッコ悪かったので、
応用としてハート形をデザインするツールを仕立ててみました
制御点をドラッグして、あなた好みのハート形を作ってください
----------------------------------
/**
* Copyright tenasaku ( http://wonderfl.net/user/tenasaku )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wNnB
*/
/* ----------------------------------
昨晩つくった線分上のドラッグ試作プログラム「線分AB上のアリア」
(cf: http://wonderfl.net/code/553e5fb0b2dbc9b6b088bf8fae5f8d5fcff0a50c )
のハート形アイコンがあまりにもカッコ悪かったので、
応用としてハート形をデザインするツールを仕立ててみました
制御点をドラッグして、あなた好みのハート形を作ってください
---------------------------------- */
package {
import flash.display.*;
import flash.events.*;
public class Main extends Sprite {
private var cp:Array; // 制御点 [0..7] の配列 (表示オブジェクト)
private var fp:Array; // 通過点 [0..7] の配列 (表示オブジェクトまたはnull)
private var tt:Array; // 通過点の重心座標の配列 (Number)
private var frame:Sprite; // 制御点を結ぶガイド線分のレイヤー
private var dragFP:int; // ドラッグ中の通過点の添字
private function draw():void {
var i:int;
// 背景の消去と再着色
this.graphics.clear();
this.graphics.lineStyle(NaN);
this.graphics.beginFill(0x99ffcc);
this.graphics.drawRect(0,0,465,465);
this.graphics.endFill();
// ガイド線分の描画
frame.graphics.clear();
frame.graphics.lineStyle(0,0x669966);
frame.graphics.moveTo(cp[0].x,cp[0].y);
for ( i = 7 ; i >= 0 ; --i ) {
frame.graphics.lineTo(cp[i].x, cp[i].y);
}
// 通過点の位置の算出
for each ( i in [ 1, 2, 5, 6 ] ) {
fp[i].x = (1-tt[i])*cp[i].x + tt[i]*cp[(i+1)%8].x;
fp[i].y = (1-tt[i])*cp[i].y + tt[i]*cp[(i+1)%8].y;
}
// ハート型領域の再描画
this.graphics.lineStyle(NaN);
this.graphics.beginFill(0xff99cc);
this.graphics.moveTo(cp[0].x, cp[0].y);
this.graphics.curveTo(cp[1].x, cp[1].y, fp[1].x, fp[1].y);
this.graphics.curveTo(cp[2].x, cp[2].y, fp[2].x, fp[2].y);
this.graphics.curveTo(cp[3].x, cp[3].y, cp[4].x, cp[4].y);
this.graphics.curveTo(cp[5].x, cp[5].y, fp[5].x, fp[5].y);
this.graphics.curveTo(cp[6].x, cp[6].y, fp[6].x, fp[6].y);
this.graphics.curveTo(cp[7].x, cp[7].y, cp[0].x, cp[0].y);
this.graphics.endFill();
}
//
private function onMouseDownAtCP(e:MouseEvent):void {
var i:int;
for ( i = 0 ; i < 8 ; ++i ) {
if ( cp[i].isPointedBy(e) ) {
cp[i].startDrag();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAtCP);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpAtCP);
break;
}
}
}
private function onMouseDownAtFP(e:MouseEvent):void {
var i:int;
for each ( i in [ 1, 2, 5, 6 ] ) {
if ( fp[i].isPointedBy(e) ) {
if ((cp[i].x == cp[(i+1)%8].x)&&(cp[i].y == cp[(i+1)%8].y)) {
// 線分の両端が一致している(=線分がない)ときは一方の端点をドラッグする
cp[i].startDrag();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAtCP);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpAtCP);
} else { // 線分がちゃんとあるときは
// 線分上に束縛されたドラッグを開始する
dragFP = i;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAtFP);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpAtFP);
}
break;
}
}
}
// 制御点オブジェクトのドラッグは通常のドラッグ処理
private function onMouseMoveAtCP(e:MouseEvent):void {
e.updateAfterEvent();
this.draw();
}
// 通過点オブジェクトのドラッグは線分上に束縛される
private function onMouseMoveAtFP(e:MouseEvent):void {
var ax:Number = cp[(dragFP+1)%8].x - cp[dragFP].x;
var ay:Number = cp[(dragFP+1)%8].y - cp[dragFP].y;
var bx:Number = e.stageX - cp[dragFP].x;
var by:Number = e.stageY - cp[dragFP].y;
var t:Number = (ax*bx+ay*by)/(ax*ax+ay*ay);
if ( t < 0 ) {
tt[dragFP] = 0;
} else if ( t > 1 ) {
tt[dragFP] = 1;
} else {
tt[dragFP] = t;
}
e.updateAfterEvent();
this.draw();
}
// 制御点オブジェクトのドラッグ終了処理
private function onMouseUpAtCP(e:MouseEvent):void {
var i:int;
for ( i = 0 ; i < 8 ; ++i ) {
cp[i].stopDrag();
}
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAtCP);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpAtCP);
}
// 通過点オブジェクトのドラッグ終了処理
private function onMouseUpAtFP(e:MouseEvent):void {
dragFP = -1;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveAtFP);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpAtFP);
}
private function initialize(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
dragFP = -1;
cp = new Array;
fp = new Array;
tt = new Array;
frame = new Sprite();
var i:int;
for ( i = 0 ; i < 8 ; ++i ) {
cp[i] = new BullsEye(0xff0000);
if ( ( i == 1 )||( i == 2 )||( i == 5 )||( i == 6 ) ) {
fp[i] = new BullsEye(0x0000ff);
tt[i] = new Number(0);
} else { // 使わない配列要素に(念のため)nullを入れる
fp[i] = null;
tt[i] = null;
}
}
// 制御点 cp[i] の初期位置を設定
cp[0].x = 232.5; cp[0].y = 100;
cp[1].x = 232.5+100; cp[1].y = 50;
cp[2].x = 232.5+200; cp[2].y = 100;
cp[3].x = 232.5+200; cp[3].y = 250;
cp[4].x = 232.5; cp[4].y = 400;
cp[5].x = 232.5-200; cp[5].y = 250;
cp[6].x = 232.5-200; cp[6].y = 100;
cp[7].x = 232.5-100; cp[7].y = 50;
// fp[i] の位置は直接指定せず 数値 tt[i] による重心座標で与える
tt[1] = 0.5;
tt[2] = 0.6;
tt[5] = 0.4;
tt[6] = 0.5;
// ガイド線レイヤーオブジェクトを登録
this.addChild(frame);
// 制御点オブジェクトを登録
for ( i = 0 ; i < 8 ; ++i ) {
this.addChild(cp[i]);
}
// 通過点オブジェクトのほうが前面にくるように、あとで登録する
for each ( i in [ 1, 2, 5, 6 ] ) {
this.addChild(fp[i]);
}
// ドラッグへの反応のためのイベントリスナーを設定
for ( i = 0 ; i < 8 ; ++i ) {
cp[i].addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownAtCP);
}
for each ( i in [ 1, 2, 5, 6 ] ) {
fp[i].addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownAtFP);
}
// 再描画
draw();
}
public function Main():void {
if ( stage != null ) {
initialize(null);
} else {
this.addEventListener(Event.ADDED_TO_STAGE, initialize);
}
}
} // end of class Main
} // end of package
import flash.display.*;
import flash.events.*;
import flash.geom.*;
// 点の標識として表示されるスプライトのクラス
// flash20100325b からの 使い回し
class BullsEye extends Sprite {
public static const RADIUS:Number = 6;
public static const DEFAULT_COLOR:uint = 0x000000;
private var color:uint;
public function draw():void {
this.graphics.clear();
this.graphics.beginFill(0xffffff);
this.graphics.lineStyle(0,this.color);
this.graphics.drawCircle(0,0,RADIUS);
this.graphics.endFill();
this.graphics.beginFill(this.color);
this.graphics.drawCircle(0,0,RADIUS/5*3);
this.graphics.endFill();
}
// MouseEventオブジェクトの座標を調べ, 自分がポイントされていたら true を返す
public function isPointedBy(e:MouseEvent):Boolean {
var mp:Point = new Point(e.stageX,e.stageY);
var cp:Point = new Point(this.x,this.y);
return ( Point.distance(cp,mp) <= RADIUS );
}
public function BullsEye(c:uint):void {
this.color = c;
this.draw();
}
}