Paint Tool + Spline
TwitPaintが納得いかないので自分で作ってみる。
線の描画をカーブにしてみた。まだがくがくする。
取得する座標が近すぎるのかな。
/**
* TwitPaintが納得いかないので自分で作ってみる。
*
* 線の描画をカーブにしてみた。まだがくがくする。
* 取得する座標が近すぎるのかな。
*
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
addChild( new PaintTool() );
}
}
}
import com.bit101.components.Label;
import com.bit101.components.PushButton;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
/**
* ペイントツール本体
*/
internal class PaintTool extends Sprite
{
private var _data : ToolData;
private var _canvas : Canvas;
private var _backgroud : Shape;
private var _cursor : Cursor;
private var _colorButtons : Array;
private var _brushButtons : Array;
public function PaintTool()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// ツールデータの作成
_data = new ToolData();
// 背景の作成
_backgroud = new Shape();
_backgroud.graphics.beginFill( 0xEEEEEE, 1 );
_backgroud.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
_backgroud.graphics.endFill();
addChild( _backgroud );
// キャンバスの作成
_canvas = new Canvas( this, _data );
addChild( _canvas );
stage.addEventListener( MouseEvent.MOUSE_MOVE, stageMouseMoveHandler );
_canvas.addEventListener( MouseEvent.MOUSE_MOVE, mouseMoveHandler );
_canvas.addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
_canvas.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
_canvas.addEventListener( MouseEvent.MOUSE_OVER, mouseOverHandler );
_canvas.addEventListener( MouseEvent.MOUSE_OUT, mouseOutHandler );
// カラーボタンの作成
var posY : int = _canvas.height + 15;
var posX : int = 115;
var colorLabel : Label = new Label( this, 32, posY-8, "COLOR" );
_colorButtons = new Array();
var colors : Array = [
0xA40000, 0xE95505, 0xFFF100, 0x8FC31F,
0x007130, 0x00A0E9, 0x00479B, 0xEB6877,
0x601986, 0x6A3906, 0xF8B551, 0x1B1B1B,
0x898989, 0xB5B5B5, 0xFFFFFF
];
for each( var c:uint in colors )
{
var colorButton : ColorButton = new ColorButton( c );
colorButton.addEventListener( MouseEvent.CLICK, changeColor );
colorButton.x = posX;
colorButton.y = posY;
posX += 22;
colorButton.addEventListener( MouseEvent.MOUSE_OVER, palletMouseOverHandler );
colorButton.addEventListener( MouseEvent.MOUSE_OUT, palletMouseOutHandler );
_colorButtons.push( colorButton );
addChild( colorButton );
}
// ブラシサイズ変更ボタンの作成
posY = _canvas.height + 45;
posX = 115;
var radiusLabel : Label = new Label( this, 32, posY-8, "BRUSH SIZE" );
_brushButtons = new Array();
var brushs : Array = [ 1, 2, 3, 5, 7, 9, 12, 15 ];
for each( var b:uint in brushs )
{
var brushButton : RadiusButton = new RadiusButton( b );
brushButton.addEventListener( MouseEvent.CLICK, changeRadius );
brushButton.x = posX;
brushButton.y = posY;
posX += 22;
brushButton.addEventListener( MouseEvent.MOUSE_OVER, palletMouseOverHandler );
brushButton.addEventListener( MouseEvent.MOUSE_OUT, palletMouseOutHandler );
_brushButtons.push( brushButton );
addChild( brushButton );
}
posY = _canvas.height + 70;
posX = 105;
// すべて消去ボタン
new PushButton( this, posX, posY, "undo", undo );
// アンドゥ
new PushButton( this, posX + 110, posY, "All clear", fillAll );
// カーソルの作成
_cursor = new Cursor( _data );
addChild( _cursor );
}
/**
* キャンバス内でのマウスイベント
*/
private var _mouseDown : Boolean = false;
private function mouseDownHandler(e:MouseEvent):void
{
_mouseDown = true;
_canvas.startStroke( mouseX, mouseY );
}
private function mouseUpHandler(e:MouseEvent):void
{
_mouseDown = false;
_canvas.endStroke();
}
private function mouseOverHandler(e:MouseEvent):void
{
_cursor.change( Cursor.PAINT );
}
private function mouseOutHandler(e:MouseEvent):void
{
_cursor.change( "normal" );
if ( _mouseDown )
{
_mouseDown = false;
_canvas.endStroke();
}
}
private function mouseMoveHandler(e:MouseEvent):void
{
if( _mouseDown )
{
_canvas.drawStroke( mouseX , mouseY );
}
}
/**
* パレットエリアのマウスイベント
* @param e
*/
private function palletMouseOverHandler(e:MouseEvent):void
{
_cursor.change( Cursor.SPOIT );
}
private function palletMouseOutHandler(e:MouseEvent):void
{
_cursor.change( "normal" );
}
/**
* ステージ内でのマウスイベント
* @param e
*/
private function stageMouseMoveHandler(e:MouseEvent):void
{
_cursor.x = this.mouseX;
_cursor.y = this.mouseY;
}
/**
* ペンの太さを変更する。
* @param e
*/
private function changeRadius( e:Event ):void
{
_data.radius = e.target.radius;
_cursor.change( Cursor.SPOIT );
}
/**
* 色を変更する。
* @param e
*/
private function changeColor( e:Event ):void
{
_data.color = e.target.color;
_cursor.change( Cursor.SPOIT );
}
/**
* 全部消す
* @param e
*/
private function fillAll( e:Event ):void
{
_canvas.fillAll( 0xFFFFFF );
_data.lines = new Vector.<Stroke>();
}
/**
* 一筆もどる
* @param e
*/
private function undo( e:Event ):void
{
_data.lines.pop();
_canvas.reDraw();
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
/**
* 描画領域
*/
internal class Canvas extends Sprite
{
private var _bitmapData : BitmapData;
private var _container : Sprite;
private var _data : ToolData;
private var _posX : int = 0;
private var _posY : int = 0;
private var _stroke : Stroke;
private var _canvasX : int = 32;
private var _canvasY : int = 32;
private var _canvasW : int = 400;
private var _canvasH : int = 300;
public function Canvas( container:Sprite, data:ToolData ):void
{
_container = container;
_data = data;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_bitmapData = new BitmapData( _canvasW, _canvasH, true, 0xFFFFFFFF );
var bitmap : Bitmap = new Bitmap( _bitmapData );
bitmap.x = _canvasX;
bitmap.y = _canvasY;
addChild( bitmap );
// キャンバス有効面の作成
graphics.beginFill( 0xDDDDDD, 1 );
graphics.drawRect( 0, 0, stage.stageWidth, _canvasH + _canvasY*2 );
graphics.endFill();
}
/**
* 描き始めのポイントをセットする。
* @param posX
* @param posY
*/
public function startStroke( posX:Number, posY:Number ):void
{
_posX = posX;
_posY = posY;
_stroke = new Stroke( _data.color, _data.radius );
_container.addChild( _stroke.shape );
_stroke.shape.x = this.x;
_stroke.shape.y = this.y;
_stroke.stroke.push( posX, posY );
drawLine();
}
/**
* 線を追加する
* @param posX
* @param posY
*/
public function drawStroke( posX:Number, posY:Number ):void
{
_stroke.stroke.push( posX, posY );
drawLine();
}
/**
* 描きおわり
*/
public function endStroke():void
{
if ( _stroke )
{
_container.removeChild( _stroke.shape );
_data.lines.push( _stroke );
bake();
_stroke = null;
}
}
/**
* ストロークをbitmapDataに焼きこむ
*/
public function bake():void
{
_bitmapData.lock();
_bitmapData.draw( _stroke.shape, new Matrix( 1, 0, 0, 1, -_canvasX, -_canvasY ) );
_bitmapData.unlock();
}
/**
* キャンバスに書き込む
* @param posX
* @param posY
*/
public function draw( posX:int, posY:int ):void
{
var line : Shape = new Shape();
var g : Graphics = line.graphics;
var xc:Number = ( _posX + posX ) / 2;
var yc:Number = ( _posY + posY ) / 2;
g.lineStyle( _data.radius, _data.color, 1 );
g.moveTo( _posX, _posY );
g.curveTo( posX, posY, xc, yc );
_stroke.stroke.push( posX, posY );
_posX = posX;
_posY = posY;
_bitmapData.lock();
_bitmapData.draw( line );
_bitmapData.unlock();
}
/**
* 一筆の描画
*/
private function drawLine():void
{
var stroke : Vector.<int> = _stroke.stroke;
var leng : int = stroke.length;
var g : Graphics = _stroke.shape.graphics;
_stroke.shape.graphics.clear();
g.moveTo( stroke[0], stroke[1] );
for ( var i :int = 0; i < leng-2; i+=2 )
{
var xc:Number = ( stroke[i ] + stroke[i + 2] ) / 2;
var yc:Number = ( stroke[i+1] + stroke[i + 3] ) / 2;
g.lineStyle( _stroke.radius, _stroke.color, 1 );
g.curveTo( stroke[i], stroke[i+1], xc, yc );
}
}
/**
* 描画記録から描画をしなおす。
*/
public function reDraw():void
{
fillAll( 0xFFFFFF );
if ( _data.lines.length == 0 ) return;
var lines : Vector.<Stroke> = _data.lines;
var l : int = lines.length;
for ( var j:int = 0; j < l; j++ )
{
_stroke = lines[j];
bake();
}
}
/**
* すべてを消す
*/
public function fillAll( color:uint ):void
{
_bitmapData.fillRect( _bitmapData.rect, color + 0xFF000000 );
}
}
/**
* キャンバス上で扱うデータ
*/
internal class ToolData
{
// position, color, radius
public var lines : Vector.<Stroke> = new Vector.<Stroke>();
public var color : uint = 0x00479B;
public var radius : Number = 4;
}
import flash.display.Shape;
/**
* 一筆のデータ
*/
internal class Stroke
{
public var stroke : Vector.<int> = new Vector.<int>;
public var color : uint;
public var radius : int;
public var shape : Shape;
public function Stroke( color:uint, radius:int ):void
{
this.radius = radius;
this.color = color;
this.stroke = new Vector.<int>;
this.shape = new Shape();
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* パレットで使うボタンのスーパークラス
*/
class PalletButton extends Sprite
{
public function PalletButton():void
{
addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
addEventListener( MouseEvent.MOUSE_OVER, mouseOverHandler );
addEventListener( MouseEvent.MOUSE_OUT, mouseOutHandler );
}
private function mouseDownHandler(e:MouseEvent):void
{
}
private function mouseUpHandler(e:MouseEvent):void
{
}
private function mouseOverHandler(e:MouseEvent):void
{
scaleX = 1.2;
scaleY = 1.2;
}
private function mouseOutHandler(e:MouseEvent):void
{
scaleX = 1;
scaleY = 1;
}
}
import flash.display.Sprite;
/**
* カラー変更ボタン
*/
internal class ColorButton extends PalletButton
{
public var color :uint;
private var _size : int = 20;
public function ColorButton( color:uint ):void
{
super();
this.color = color;
graphics.beginFill( color, 1 );
graphics.drawRect( -_size/2, -_size/2, _size, _size );
graphics.endFill();
graphics.lineStyle( 0.5, 0x888888, 1 );
graphics.drawRect( -_size/2, -_size/2, _size, _size );
buttonMode = true;
}
}
import flash.display.Sprite;
/**
* ペンの太さ変更ボタン
*/
internal class RadiusButton extends PalletButton
{
public var radius :uint = 1;
private var _size : int = 20;
public function RadiusButton( radius:uint ):void
{
super();
this.radius = radius;
graphics.beginFill( 0xFFFFFF, 1 );
graphics.drawRect( -_size/2, -_size/2, _size, _size );
graphics.endFill();
graphics.beginFill( 0x000000, 1 );
graphics.drawCircle( 0, 0, radius/2 );
graphics.endFill();
graphics.lineStyle( 0.5, 0x888888, 1 );
graphics.drawRect( -_size/2, -_size/2, _size, _size );
buttonMode = true;
}
}
import flash.display.Sprite;
import flash.ui.Mouse;
/**
* カーソル
*/
internal class Cursor extends Sprite
{
private var _toolData : ToolData;
public static const PAINT : String = "paint";
public static const SPOIT : String = "spoit";
public function Cursor( data:ToolData ):void
{
this._toolData = data;
mouseEnabled = false;
mouseChildren = false;
}
/**
* 再描画する。
*/
public function change( mode:String ):void
{
if ( PAINT == mode )
{
paintMode();
}
else if ( SPOIT == mode )
{
spoitMode();
}
else
{
normal();
}
}
private function normal():void
{
graphics.clear();
Mouse.show();
}
/**
* キャンバス上でのカーソル
*/
private function paintMode():void
{
graphics.clear();
Mouse.hide();
if ( _toolData.radius < 3 )
{
graphics.beginFill( _toolData.color, 1 );
graphics.drawCircle( 0, 0, _toolData.radius/2 );
graphics.endFill();
graphics.lineStyle( 0.5, 0x555555, 0.5 );
graphics.moveTo( -15, 0.5 );
graphics.lineTo( -10, 0.5 );
graphics.moveTo( 15, 0.5 );
graphics.lineTo( 10, 0.5 );
graphics.moveTo( 0.5, -15 );
graphics.lineTo( 0.5, -10 );
graphics.moveTo( 0.5, 15 );
graphics.lineTo( 0.5, 10 );
}
else
{
graphics.lineStyle( 0.5, 0x555555, 0.5 );
graphics.beginFill( _toolData.color, 1 );
graphics.drawCircle( 0, 0, _toolData.radius/2 );
graphics.endFill();
}
}
/**
* カラー、ブラシ上でのカーソル
*/
private function spoitMode():void
{
graphics.clear();
Mouse.hide();
graphics.beginFill( 0x555555, 1 );
graphics.moveTo( 0, 0 );
graphics.lineTo( 20, 10 );
graphics.lineTo( 10, 20 );
graphics.lineTo( 0, 0 );
graphics.beginFill( 0xFFFFFF, 1 );
graphics.drawCircle( 20, 20, 10 );
graphics.endFill();
graphics.beginFill( _toolData.color, 1 );
graphics.drawCircle( 20, 20, _toolData.radius/2 );
graphics.endFill();
graphics.lineStyle( 0.5, 0x555555, 1 );
graphics.drawCircle( 20, 20, 10 );
}
}