[JavaScript] CreateJSでタッチデバイスでダブルタップしたい!

2013/07/13

こんにちはきんくまです。

CreateJSをやってまして。といっても、Flashから何かを書き出すわけではなくて、EaselJS落としてきて使っているだけなんですけど。

使っている感想としては、便利です。

それで、タッチデバイスでダブルタップしたいという件についてです。
まず、dblclickイベントは、タッチデバイスだとうまく動きませんでした。Surface ProのIE10だとちょっと修正すると動いてくれました。
なので、マウスでなくタッチ系のiOS、Androidでも動くように自前で作ってみました。
ひょっとしたらEaselJSにすでに組み込まれてるのかもしれない、、。

はじめに今回の参考ページです。

>> ポインター イベントとジェスチャ イベント
>> タッチ操作向けサイト構築のガイドライン

ブラウザーのデフォルトの動作を無効にする

ダブルタップをするとデフォルトの動作で、ブラウザがズームイン / アウトします。まずはそれを無効にします。

htmlのhead部分

<head>
<meta content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" name="viewport" /> 
</head>

css

body{
	-webkit-user-select: none;
	-ms-touch-action: none;
}

今回はbodyに入れてますけど、必要な部分だけに適用した方がよいと思います。

-webkit-user-selectはiOS向け。文字列を選択させないようにしてます。必要に応じて。
-ms-touch-actionがIE向け。これを入れることで、タッチイベント(IEの場合はポインターイベントというらしい)がブラウザに持っていかれるのを防いで、JSで扱えるようになります。

で、EaselJSでのJSのコード。最近はTypeScriptで書いてるので、そっちで書いてます。

easeljs.d.tsは

borisyankov/DefinitelyTyped

からいただきました。
時々コンパイルが通らないので、中身をちょこちょこ変更しながら使ってマス。


/// <reference path="easeljs.d.ts" />

module kk{

	export class SampleViewController{

//		lastTouchPoint:createjs.Point;
		isTouchMoved:boolean = false;
		lastTapTime:number;
		lastTappedStagePoint:createjs.Point;

		doubleTapThresholdTime:number = 450; //2つのタップの時間のしきい値
		doubleTapThresholdDistanceBetweenTap:number = 50; //2つのタップの距離のしきい値

		viewRect:createjs.Rectangle;
		view:createjs.Container;
		
		constructor(viewRect:createjs.Rectangle){
			this.viewRect = viewRect;
			this.initView();
			this.registerEvents();
		}
		
		initView():void{
			this.view = new createjs.Container();
			this.setupView();
		}

		setupView():void{
			this.view.x = this.viewRect.x;
			this.view.y = this.viewRect.y;

			this.view.hitArea = new createjs.Shape(
				new createjs.Graphics().beginFill('#000').drawRect(0,0,this.viewRect.width, this.viewRect.height)
			);
		}

		resizeView(newViewRect:createjs.Rectangle):void{
			this.viewRect = newViewRect;
			this.setupView();
		}

		registerEvents():void{
			this.lastTouchPoint = new createjs.Point(0,0);
			this.view.addEventListener('mousedown', (e0:any)=>{
				this.viewTouchStartHandler(e0);
			});
		}

		viewTouchStartHandler(e0:any){
//			this.lastTouchPoint.x = e0.stageX;
//			this.lastTouchPoint.y = e0.stageY;
			this.isTouchMoved = false;

			e0.addEventListener('mousemove', (e1:any)=>{
				this.viewTouchMoveHandler(e1);
			});
			e0.addEventListener('mouseup', (e1:any)=>{
				this.viewTouchEndHandler(e1);
                e1.removeAllEventListeners('mousemove');
                e1.removeAllEventListeners('mouseup');
                e1 = null;
			});
		}

		viewTouchMoveHandler(e1:any){
			this.isTouchMoved = true;

//			this.lastTouchPoint.x = e1.stageX;
//			this.lastTouchPoint.y = e1.stageY;
		}

		viewTouchEndHandler(e1:any){
			if(this.isDoubleTap(e1.stageX, e1.stageY)){
			    //ダブルタップ! 何かする
			}

			this.lastTappedStagePoint.x = e1.stageX;
			this.lastTappedStagePoint.y = e1.stageY;
		}

		isDoubleTap(touchPointStageX:number, touchPointStageY:number):boolean{

			// Surface Proだと動いてなくても押してるだけで、
			// viewTouchMoveHandlerが作動するので無視する

			if(!window.navigator.msPointerEnabled && this.isTouchMoved){
				return false;
			}

			// 時間のチェック
			var now:number = (new Date()).getTime();
			var thresholdTime:number = now - this.lastTapTime;
			this.lastTapTime = now;
			
			if(thresholdTime > this.doubleTapThresholdTime){
				return false;
			}

			// 距離のチェック
			var dx:number = touchPointStageX - this.lastTappedStagePoint.x;
			var dy:number = touchPointStageY - this.lastTappedStagePoint.y;
			var distance:number = dx * dx + dy * dy;

			var thresholdDistance:number = this.doubleTapThresholdDistanceBetweenTap;

			if(distance > thresholdDistance * thresholdDistance){
				return false;
			}
			return true;
		}
	}
}

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る