Haxe + CreateJS 開発メモ#3 jQuery Pluginを作る

FlashDevelop + Haxe + CreateJS の組み合わせで、ActionScript による Flash 開発のような感覚で canvas を使用したアプリケーション開発が行えることは、前回までで紹介した通りです。しかし FlashDevelop は、HTML や CSS を含めた WEB アプリケーション全体を構築するための機能は備えていません。HTML や CSS を記述することも一応は出来ますが効率は悪いです。
実際の開発では、複雑なロジックを含む機能を Haxe で作成し、それを別のIDEやフレームワークを使ったアプリケーションに組み込むといった作業が発生するはずです。

そこで今回は、Haxe で CreateJS を使用した jQuery Plugin を作成してみます。Haxe で作成した機能を jQuery Plugin 化することで、アプリケーションへの組み込み作業を簡単に出来ます。

jQuery Plugin については、以下の記事を読むとよく分かります。

HTML5 × CSS3 × jQueryを真面目に勉強 ? #8 jQueryプラグインの作り方について詳しく

プロジェクトの準備

プロジェクトを新規作成し、コンパイラー設定でjQueryExternを使用する設定を行います。
jQueryExternのインストールや、コンパイラー設定の細かいやり方に関しては、このシリーズの前々回の記事を参照してください。

project-setting

jQuery.fn の拡張

jQuery Plugin の実装は、jQuery.fn を拡張して行います。jQueryExtern で jQuery オブジェクトにアクセスするには、JQueryStatic クラスを使用します。JQueryStatic クラスは、jQuery\JQuery.hx 内で定義されているインナークラスなので、いきなりタイプしても自動インポートが上手くいきません。ここに限っては、import 文は自力で記述した方が無難です。

import jQuery.JQuery;

また、JQueryStatic に fn プロパティは定義されていないので、とりあえず Dynamic 型に代入してから fn.extend メソッドを呼び出します。

var jq:Dynamic = JQueryStatic;
jq.fn.extend( {
//・・・処理・・・
});

拡張して追加したメソッド内では、this で DOM 要素を保持した JQuery オブジェクトが取得できますが、そのまま this と記述すると、Haxe コンパイラは this を Main クラスのインスタンスと解釈してしまい、コンパイルエラーになってしまいます。そこで、eval() メソッドを使用して、実行時の this をローカル変数に代入して、以降の処理で使用します。また、メソッドチェーンのために、最後に return しておきます。

var elements:JQuery = Lib.eval("this");
//・・・処理・・・
return elements;

以上の三点を踏まえた、jQuery Plugin のテンプレートです。

package ;
import jQuery.JQuery;
import js.Lib;

class Main {
	
	static function main() {
		new Main();
	}
	
	public function new() {
		var jq:Dynamic = JQueryStatic;
		jq.fn.extend( {
			yourPluginMethod: function(?options:Dynamic):JQuery {
				var elements:JQuery = Lib.eval("this");
				//・・・処理・・・
				return elements;
			}
		} );
	}
}

Dynamic や eval() を使用しているために少し無理矢理感がありますが、一応これで上手くいきます。

実装サンプル

以下、CreateJS を使ったプラグインのサンプルです。

Main.hx

package ;

import createjs.easeljs.MouseEvent;
import createjs.easeljs.Stage;
import createjs.easeljs.Ticker;
import jQuery.JQuery;
import js.Lib;

class Main {
	
	//エントリポイント
	static function main() {
		new Main();
	}
	
	//ステージ
	private var stage:Stage;
	
	//オプション
	private var options:Dynamic;
	
	//コンストラクタ
	public function new() {
		//optionsのデフォルト値
		var defaults = {
			radius: 5,
			alphaDecrement: 0.02,
			scaleMagnification: 1.1
		}
		var jq:Dynamic = JQueryStatic;
		jq.fn.extend( {
			//rippleメソッドを追加
			ripple: function(?options:Dynamic):JQuery {
				//デフォルトオプションを引数で上書き
				this.options = JQueryStatic.extend({}, defaults, options);
				var elements:JQuery = Lib.eval("this");
				initStage(elements);
				return elements;
			}
		} );
	}
	
	//ステージの初期処理
	private function initStage(elements:JQuery):Void {
		for (i in 0...elements.length) {
			var element:Dynamic = elements[i];
			stage = new Stage(cast element);
			stage.onMouseUp = stageOnMouseUp;
			Ticker.addListener(stage);
			Ticker.setFPS(60);
			break;
		}
	}
	
	//MouseUpイベントハンドラ
	private function stageOnMouseUp(e:MouseEvent):Void {
		//Circleをステージに追加
		var circle:Circle = new Circle(options);
		circle.x = e.stageX;
		circle.y = e.stageY;
		stage.addChild(circle);
	}
}

Circle.hx

package ; import createjs.easeljs.Container; import createjs.easeljs.Graphics; import createjs.easeljs.Shape;

class Circle extends Shape {

//コンストラクタ public function new(options:Dynamic) { super();

//ランダムな色で円を描く var g:Graphics = graphics; var color:Int = Math.round(16777215 * Math.random()); g.beginFill("#" + StringTools.hex(color)); g.drawCircle(0, 0, options.radius); g.endFill();

onTick = function() { alpha -= options.alphaDecrement; scaleX = scaleY *= options.scaleMagnification; if (alpha <= 0) { cast(parent, Container).removeChild(this); } } } } [/as3]

ripple.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8"/>
	<title>HaxeJQPluginSample</title>
	<meta name="description" content="" />
	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
	<script src="http://code.createjs.com/easeljs-0.5.0.min.js"></script>
	<script src="jquery.ripple.js"></script>
	
	<script type="text/javascript">
		$(function() {
			$('#canvas').ripple({radius: 10});
		});
	</script>
	
</head>
<body>
	<p>キャンバスをクリック!</p>
	<canvas id="canvas" width="400" height="400" style="background-color:#EEE"></canvas>
</body>
</html>

実行結果

別ウィンドウで開く

非常に簡潔な記述で、HTMLへ組み込む事ができました。通常のHTMLとCreateJSを使用する箇所で分業を行う場合など、このようなやり方で進めれば、スムーズに行くと思います。