図形の描画履歴を保存する

(サンプル一覧を表示する)

FlashDevelop を使って、図形の描画履歴を保存するテストをしてみました。
(このサンプルでは、Flash Player 10 以降で追加された機能を使っています。)

図形の描画履歴を保存することで、Photoshop 等のペイントソフトで使われている
元に戻す (Undo) 機能を付けることができます。
他の使い方としては、同じ図形を他の箇所に何度もコピーするというような用途も考えられます。
また、いったん共有オブジェクト等に描画履歴を保存しておき、後で図形を復元するという時にも
この機能が役に立つと思います。

図形の描画履歴の保存機能は、Graphics クラスに対する描画操作を配列にするためだけのもので、
Graphics の描画を高速化するものではありません。
高速化するためには、Graphics に対する描画内容をビットマップ形式に変換する
という方法を取ってください。Graphics への描画内容は、オブジェクトの内部に保存されて
画面のリサイズ時等に再描画処理が入るので、描かれた図形が多いほど Flash 全体の処理が重くなります。
Flash の実行画面
図形の描画履歴を保存する

Flashプレーヤーが入っていないか、JavaScriptが無効になっているようです。

Get Adobe Flash player

図形の描画履歴を保存する
マウスで何か絵を書いた後、元に戻すボタンを押してみてください。

ソースコード

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.CapsStyle;
	import flash.display.Graphics;
	import flash.display.GraphicsPath;
	import flash.display.GraphicsSolidFill;
	import flash.display.GraphicsStroke;
	import flash.display.IGraphicsData;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	
	/**
	 * 図形の描画履歴を保存するサンプル
	 * @author Hikipuro
	 */
	public class Main extends Sprite 
	{
		/**
		 * 図形の描画履歴を入れる配列
		 */
		private var graphicsData:Vector.<IGraphicsData>;
		
		/**
		 * graphicsData 配列の長さの履歴
		 */
		private var lengthHistory:Vector.<int>;
		
		/**
		 * ステージ上でマウスが押されている間 True
		 */
		private var mouseDownFlag:Boolean;
		
		/**
		 * 前回の X 座標
		 */
		private var prevX:Number;
		
		/**
		 * 前回の Y 座標
		 */
		private var prevY:Number;
        
        /**
         * 元に戻すボタン
         */
        private var undoButton:SimpleButton;
        
		
		/**
		 * コンストラクタ
		 */
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		/**
		 * 初期化メソッド
		 * @param	e
		 */
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			
			// 変数の初期化
			graphicsData = new Vector.<IGraphicsData>();
			lengthHistory = new Vector.<int>();
			mouseDownFlag = false;
			prevX = 0;
			prevY = 0;
			
            // 元に戻すボタンの作成
            undoButton = new SimpleButton();
            undoButton.upState = createButton(0xDDDDDD, 100, 20, 10, "元に戻す");
            undoButton.overState = createButton(0xEEEEEE, 100, 20, 10, "元に戻す");
            undoButton.downState = createButton(0xCCCCCC, 100, 20, 10, "元に戻す");
            undoButton.hitTestState = undoButton.upState;
            undoButton.addEventListener(MouseEvent.MOUSE_DOWN, onUndoButtonDown);
            undoButton.x = 5;
            undoButton.y = 5;
            addChild(undoButton);
			
			// マウスイベントの登録
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
		}
		
		/**
		 * ステージ上でマウスが押された時
		 * @param	e
		 */
		private function onMouseDown(e:MouseEvent):void 
		{
			// マウスフラグオン
			mouseDownFlag = true;
			
			// 押された瞬間の座標を記録する
			prevX = mouseX;
			prevY = mouseY;
			
			// 押された瞬間の graphicsData 配列の長さを記録する
			lengthHistory.push(graphicsData.length);
		}
		
		/**
		 * ステージ上でマウスが離された時
		 * @param	e
		 */
		private function onMouseUp(e:MouseEvent):void 
		{
			// マウスフラグオフ
			mouseDownFlag = false;
		}
		
		/**
		 * ステージ上でマウスが動いた時
		 * @param	e
		 */
		private function onMouseMove(e:MouseEvent):void 
		{
			// マウスが押されていない時はそのまま終了
			if (mouseDownFlag == false)
				return;
			
			// 線の描画履歴を 1 つ分保存する
			var myFill:GraphicsSolidFill;
			var myStroke:GraphicsStroke;
			var myPath:GraphicsPath;
			
			myFill = new GraphicsSolidFill(0xFF0000);
			myStroke = new GraphicsStroke(3);
			myStroke.caps = CapsStyle.ROUND;
			myStroke.fill = myFill;
			myPath = new GraphicsPath();
			myPath.moveTo(prevX, prevY);
			myPath.lineTo(mouseX, mouseY);
			graphicsData.push(myStroke, myPath);
			
			// 上で追加した描画履歴と同じ線を画面に描く
			graphics.lineStyle(3, 0xFF0000);
			graphics.moveTo(prevX, prevY);
			graphics.lineTo(mouseX, mouseY);
			
			// 現在の座標を保存する
			prevX = mouseX;
			prevY = mouseY;
		}
		
		/**
		 * 元に戻すボタンが押された時
		 * @param	e
		 */
		private function onUndoButtonDown(e:MouseEvent):void 
		{
			// graphicsData の長さ履歴から、
			// マウスが最後に押された時の配列の長さを取得する
			var prevLength:int = lengthHistory.pop();
			
			// マウスが最後に押された瞬間の長さにデータを戻す
			graphicsData.length = prevLength;
			
			// グラフィックスを描きなおす
			graphics.clear();
			graphics.drawGraphicsData(graphicsData);
			
			// ステージ上でマウスが押されたイベントも
			// このイベントの処理後に発生してしまうため、
			// イベントフローをここで終了する。
			// stopPropagation() を追加することで、
			// onMouseDown() イベントが元に戻すボタン上では発生しなくなる。
			e.stopPropagation();
		}
		
		
        /**
         * ボタンを作って返す
         * @param    color    色
         * @param    width    幅
         * @param    height    高さ
         * @param    round    角丸の大きさ
         * @param    text    ボタンのテキスト
         * @return    ボタン
         */
        private function createButton(color:uint, width:int, height:int, round:int, text:String):Sprite
        {
            var t:TextField = new TextField();
            var s:Sprite = new Sprite();
            s.graphics.lineStyle(2);
            s.graphics.beginFill(color);
            s.graphics.drawRoundRect(0, 0, width, height, round);
            s.graphics.endFill();
            
            t.text = text;
            t.selectable = false;
            t.width = width;
            t.autoSize = TextFieldAutoSize.CENTER;
            s.addChild(t);
            
            return s;
        }
		
	}
	
}
		

参照

外部リンク