[HTML5] Canvas + EaselJSを使ってSDNもどきのUIを作ってみる #2

前回は2つのオブジェクト間に連結線を描画するところまで試しましたが、今回はオブジェクトにマウスオーバーした際の処理とメニューボタンを作ってみたいと思います。

利用した環境

  • EaselJS0.7.0
  • IIS7.5(Web Serverならなんでも可)
  • ブラウザはChrome

マウスオーバー時にオブジェクトの情報を表示できるようにする

EaselJS0.7.0からはマウスイベントにロールオーバーとロールアウトのイベントが追加されていますので、その機能を使ってみます。

前回作成したcreateBitmap関数の中に以下のイベントリスナーを登録します。

  bitmap.on("rollover",rollovr);
  bitmap.on("rollout",rollout);

ロールオーバーの際に情報を表示すると仮定して吹き出し(角丸四角形)を描画してその吹き出しの中にテキストを描画するようにしてみます。

    function rollovr (evt) {
    	var o = evt.target;

    	if (o.name != null && o.x < 730){
		// 角丸四角形を描く
		graphics = new createjs.Graphics();
		graphics.beginStroke("#FDE5BF");
		graphics.beginFill("#FAD2B6");
		graphics.drawRoundRect(o.x, o.y, 250, 150, 10);
		shape = new createjs.Shape(graphics);
		shape.name="TEST";
		sdn_container.addChildAt(shape,sdn_container.getNumChildren());

		//ここはデモ用にハードコーディングで描画(動作イメージをつかむため)
		for( var i=1 ; i<6 ; i++ ) {
			if ( i == 1 ){
				viewtext = new createjs.Text("Instance ID:" + "i-32d16f49","12px Arial Bold","#000000");
			}else if(i == 2){
				viewtext = new createjs.Text("Instance state:" + "stopped","12px Arial Bold","#000000");
			}else if(i == 3){
				viewtext = new createjs.Text("Instance type:" + "t1.micro","12px Arial Bold","#000000");
			}else if(i == 4){
				viewtext = new createjs.Text("Availability zone:" + "ap-northeast-1a","12px Arial Bold","#000000");
			}else if(i == 5){
				viewtext = new createjs.Text("Security groups:" + "roundabout. view rules","12px Arial Bold","#000000");
			}
			viewtext.x = Rect_x + 10;
			viewtext.y = Rect_y + (20 * i);
			viewtext.maxWidth=canvasWidth-40;
			viewtext.lineHeight=20;
			viewtext.textBaseline="bottom";
			viewtext.shadow=shadow;
			viewtext.name = "TEXT_" + i;
			sdn_container.addChild(viewtext);
			}
    	}
    	update = true;
    }

実行イメージは下記のような感じです。表示されているデータはデモ用に直接埋め込んであるので AWS SDK for JavaScript in the Browser がEC2をサポートすればその時点で実際のデータを読み込むようにすることができるのですが、現時点ではサポートされていないです。。。

No6_1

一応ロールオーバーで情報を出すようにしましたが、それとは別にダブルクリックのイベントもこのデモプログラムでは使っているので、今のままではマウスイベントが競合して都合がよくありません。
そこで遅延処理を入れることにしました。setTimeoutメソッドを組み込みます。setTimeoutメソッドでは指定した時間の後に引数で指定した関数を呼び出すのですが、その呼び出しもロールアウトのタイミングで呼び出しを取り消しするロジックも必要となります。取り消しするメソッドはclearTimeoutメソッドなので、それも組み込みます。
clearTimeoutメソッドの引数はsetTimeoutメソッドで得られたIDとなります。ということでrollovr関数を変更します。吹き出し(角丸四角形)を描画する処理はsetTimeoutメソッドの引数で渡しているrectdraw()の中に移動しました。

    var timer_id;
    function rollovr (evt) {
    	var o = evt.target;
	//ロールオーバーされたオブジェクトの名前をlocalStorageに格納しておきます。
    	localStorage.setItem("rollovr_name",o.name);

    	if (o.name != null && o.x < 730){
    		//角丸四角形の左上座標もlocalStorageに格納しておきます。
    		localStorage.setItem("rollovr_x",o.x);
    		localStorage.setItem("rollovr_y",o.y);
    		//setTimeoutで実行される関数の有効フラグをlocalStorageに格納しておきます。
    		localStorage.setItem("check_evt","on");
    		if (localStorage.getItem("check_evt") == "on"){
    			//clearTimeoutに渡す引数
    			timer_id = setTimeout('rectdraw()',1000);
    		}
    	}
    	update = true;
    }

rollout関数でclearTimeoutの処理を入れます。

    function rollout (evt) {
    	var o = evt.target;
    	if( o.name != null){
    		o.scaleX = o.scaleY = o.scale = 0.8;
    	}
    	//setTimeoutの実行フラグをoffにする
    	localStorage.setItem("check_evt","off");
       	//setTimeoutを削除する
    	if(typeof timer_id !== "undefined" ){
    		clearTimeout( timer_id );
    	}

    	//なぜか消えないときがあるので、1回分多くループして削除
   		for( var i=0 ; i<2 ; i++ ) {
	    	var rect_object = sdn_container.getChildByName("TEST");
	    	if(rect_object != null){
		    	sdn_container.removeChild(rect_object);
		    }
		}

    	//TEXTを作成した分削除する(適当に10回回してるだけ)
   		for( var i=1 ; i<10 ; i++ ) {
			var txtObj = sdn_container.getChildByName("TEXT_" + i);
	    	if(txtObj != null){
		    	sdn_container.removeChild(txtObj);
	    	}
	    }
    	update = true;
    }

mousedownイベント、dblclickイベント、clickイベントが発生したタイミングでもlocalStorage.setItem("check_evt","off");を入れておきます。
これでロールアウトの際にその他マウスイベント時にフラグをオフにしているので吹き出し(角丸四角形)を描画する処理をキャンセルすることができます。
次はstage上にボタンを作ってみたいと思います。

一応それっぽく見えるように『デプロイ』、『保存』、『クリア』のボタンを作成してみます。固定画像の描画の下あたりに下記コードを追加しました。

		var MenuButton=[];
		//ボタンを作る
		for (var i=0; i < 3; i++) {
			//ラベル文字生成
			// var label="BUTTON"+(i+1);
			if(i == 0){
				label="デプロイ";
			}else if(i == 1){
				label="保存";
			}else if(i == 2){
				label="クリア";
			}
			MenuButton[i]=createbutton(0,5,100,20,5,"#FFFFFF",label,"#333333","#DB85C2","#FFFFFF");
			MenuButton[i].cursor="pointer";
			//ボタン間隔
			MenuButton[i].x=(i*120)+10;
			//クリックアクション
			MenuButton[i].addEventListener("click",menuclick);
			//MenuButton addChild
			stage.addChild(MenuButton[i]);
		}

createbuttonの中でボタン用コンテナ、Shapeインスタンスを作成してlineToquadraticCurveToで角丸四角形っぽく描画します。あとは作成したボタンコンテナに対してrolloverとrolloutのイベントリスナーを定義しておきます。見栄えは下記のような感じになりました。

No7

動作できる機能は

  • 右エリア画像のドラッグ&ドロップ
  • 1つ目画像のダブルクリック、2つ目画像のダブルクリックで連結線の描画
  • 配置後の画像オブジェクトのドラッグ&ドロップ(連結線も連動)
  • 画像オブジェクトのロールオーバー(1秒)で情報を表示(全部固定の情報が出ます)

デモはこちら(完成度はまだ低いです)

シビアなイベントハンドリングをしていないので、やさしくゆっくりと動作させてくださいw

まとめ

今回は遅延処理とボタンを作成してStageに配置するところまでを行いました。UIだけのサンプルデモなので、この後の処理であるデプロイ、保存についてはサーバ側と連携する必要があります。時間があればサーバ連携まで試してみたいと思います。