CREATEJSの新しいバージョンを利用する

20 12月

以前から、CREATEJS を利用していました。canvas タグの領域に描画する場合、通常ではいったん書いたものは動かすことができません。アニメーションはできないのですが、CREATEJS で書き込めば動かすことが可能です。

下記のサイトのサンプルをコードの下書きにしていました。

参考にしたサンプルはここのコードですが、先日 CREATEJS のサイトを見たら、バージョンがかなりあがっていて、以前 0.4 だったのが現在 1.0 です。それで、新しい方で動くようにコードを書き換えてみました。下記にあげます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"> 
<title>JavaScript GestureEvent sample | kudox.jp</title>
<link rel="stylesheet" type="text/css" href="css/index.css" media="all">

<script type="text/javascript" src="js/easeljs.js"></script>


<script type="text/javascript">

var TouchEventSample = (function(window) {
	var MAX_SCALE = 3;
	var MIN_SCALE = 0.25;
	
	var _instance;
	var _canvas;
	var _stage;
	var _rect;
	var _hitTouches = [];
	var _dragEnabled = true;
	var _startScale;
	var _startRotation;
	
	function TouchEventSample(canvasID) {
		try {
			document.createElement("canvas").getContext("2d");
		} catch (e) {
			return;
		}
		_instance = this;
		_canvas = document.getElementById(canvasID);
		updateCanvasSize();
		_stage = new createjs.Stage(_canvas);
		_rect = new createjs.Shape();
		var g = _rect.graphics;
		var w = _canvas.width * 0.1 >> 0;
		g.beginFill("#0066cc")
		.drawRect(-w * 2, -w, w * 4, w * 2)
		.endFill();
		_rect.x = _canvas.width * 0.5 >> 0;
		_rect.y = _canvas.height * 0.5 >> 0;
		_stage.addChild(_rect);

		createjs.Ticker.addEventListener("tick",handleTick);

		function handleTick(){
			_stage.update();
		}

		if ("onorientationchange" in window) {
			window.addEventListener("orientationchange", updateCanvasSize, false);
		} else {
			window.addEventListener("resize", updateCanvasSize, false);
		}
		if ("ontouchstart" in window) {
			_canvas.addEventListener("touchstart", touchStartHandler, false);
			_canvas.addEventListener("touchmove", touchMoveHandler, false);
			document.addEventListener("touchend", touchEndHandler, false);
			document.addEventListener("touchcancel", touchEndHandler, false);
		}
		if ("ongesturestart" in window) {
			_canvas.addEventListener("gesturestart", gestureStartHandler, false);
			_canvas.addEventListener("gesturechange", gestureChangeHandler, false);
			document.addEventListener("gestureend", gestureEndHandler,false);			
		}
	}
	
	function touchStartHandler(e) {

//alert("touchStartHandler");

		e.preventDefault();
		var touches = e.changedTouches;
		for (var i = 0, l = touches.length; i < l; ++i) {
			var touch = touches[i];
			var target = touch.target;
			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;
			var localPoint = _rect.globalToLocal(stageX, stageY);
			if (_rect.hitTest(localPoint.x, localPoint.y)) {
				var offsetX = _rect.x - stageX;
				var offsetY = _rect.y - stageY;
				var offset = new createjs.Point(offsetX, offsetY);
				_hitTouches.push({touch:touch, offset:offset});
			}
		}
	}
	
	function touchMoveHandler(e) {

//alert("touchMoveHandler");

		e.preventDefault();
		if (!_dragEnabled || _hitTouches.length === 0) {
			return;
		}
		var touches = e.touches;
		for (var i = 0, l = touches.length; i < l; ++i) {
			var touch = touches[i];
			if (_hitTouches[0].touch.identifier !== touch.identifier) {
				continue;
			}
			var target = touch.target;
			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;
			var offset = _hitTouches[0].offset;
			_rect.x = stageX + offset.x;
			_rect.y = stageY + offset.y;
			return;
		}
	}
	
	function touchEndHandler(e) {
		e.preventDefault();
		var touches = e.changedTouches;
		outsideLoop: for (var i = 0, l = touches.length; i < l; ++i) {
			var touch = touches[i];
			for (var j = 0, m = _hitTouches.length; j < m; ++j) {
				if (_hitTouches[j].touch.identifier === touch.identifier) {
					_hitTouches.splice(j, 1);
					continue outsideLoop;
				}
			}
		}
	}
		
	function gestureStartHandler(e) {
		_dragEnabled = false;
		_startScale = _rect.scaleX;
		_startRotation = _rect.rotation;
	}
	
	function gestureChangeHandler(e) {
		if (_hitTouches.length === 0) {
			return;
		}
		var scale = _startScale + e.scale - 1;
		scale = (scale < MIN_SCALE) ? MIN_SCALE : (MAX_SCALE < scale) ? MAX_SCALE : scale;
		_rect.scaleX = _rect.scaleY = scale;
		_rect.rotation = (_startRotation + e.rotation + 360) % 360;
	}
	
	function gestureEndHandler(e) {
		_startScale = null;
		_startRotation = null;
		for (var i = 0, l = _hitTouches.length; i < l; ++i) {
			var touch = _hitTouches[i].touch;
			var target = touch.target;
			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;
			var offsetX = _rect.x - stageX;
			var offsetY = _rect.y - stageY;
			_hitTouches[i].offset = new createjs.Point(offsetX, offsetY);
		}
		_dragEnabled = true;
	}
	
	function updateCanvasSize(e) {
		_canvas.width = document.documentElement.clientWidth;
		_canvas.height = document.documentElement.clientHeight;
		if (_rect) {
			_rect.x = _canvas.width * 0.5 >> 0;
			_rect.y = _canvas.height * 0.5 >> 0;
		}
	}
		
	return TouchEventSample;
}(window));

window.addEventListener("load", function(e) {
	window.removeEventListener("load", arguments.callee, false);
	var sample = new TouchEventSample("my-canvas");
}, false);

</script>
</head>
<body>
<canvas width="640" height="360" id="my-canvas">
お使いのWebブラウザは、HTML5のcanvasに対応していません。
</canvas>
</body>
</html>

だいたいは、createjs.Stage だとか、createjs.Shape、createjs.Point などのオブジェクト指向的な書き方に変更しました。Ticker も createjs.Ticker に変更しました。メソッド名が変わっていて addListener から addEventListener へと変わり、引数も変更されていました。ただこのような書き方は以前のバージョンでも同じ記述をする場合があって動かなかった理由が良く分からない。

(追記:20181222)
Edge でタッチイベントを有効にするには,アドレスバーに about:flags と打ち込んで設定画面を呼び出します。

windows 版の chrome では,アドレスバーに chrome://flags と打ち込むことで設定を呼び出せます。Touch Events API の所を有効にします。

上記の設定をすると,Edge と chrome でタッチイベントが有効になります。上記のコードを書きかえてみました。

Edge,chrome(windows),iOS の safari,FireFox(windows) で動作します。 gesture イベントの検出を止めました。設定変更によって,Edge,chrome は touch イベントには対応するようになるのですが,ジェスチャーには反応しません。その代わり,指が2本タッチしたらジェスチャーの動きを開始します。1番目の指と2番目の指でジェスチャーをするものと仮定しています。下記にコードをあげます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"> 
<title>sample</title>
<link rel="stylesheet" type="text/css" href="css/index.css" media="all">

<script type="text/javascript" src="js/easeljs.js"></script>


<script type="text/javascript">



var TouchEventSample = (function(window) {


	var p = {MAX_SCALE:3, MIN_SCALE:0.25, _instance:null, _canvas:null, _stage:null, _rect:null, _hitTouches:[], _dragEnabled:true, _startScale:null, _startRotation:null, _startGesture:false, lastDX:null, lastDY:null, lastR:null};

	function TouchEventSample(canvasID) {
		try {
			document.createElement("canvas").getContext("2d");
		} catch (e) {
			return;
		}
		p._instance = this;
		p._canvas = document.getElementById(canvasID);


		//updateCanvasSize();

		p._canvas.width = document.documentElement.clientWidth;
		p._canvas.height = document.documentElement.clientHeight;
		if (p._rect) {
			p._rect.x = p._canvas.width * 0.5 >> 0;
			p._rect.y = p._canvas.height * 0.5 >> 0;
		}


		p._stage = new createjs.Stage(p._canvas);
		p._rect = new createjs.Shape();
		var g = p._rect.graphics;
		var w = p._canvas.width * 0.1 >> 0;
		g.beginFill("#0066cc")
		.drawRect(-w * 2, -w, w * 4, w * 2)
		.endFill();
		p._rect.x = p._canvas.width * 0.5 >> 0;
		p._rect.y = p._canvas.height * 0.5 >> 0;
		p._stage.addChild(p._rect);

		createjs.Ticker.addEventListener("tick",handleTick);

		function handleTick(){

			p._stage.update();
		}

		if ("ontouchstart" in window) {
			p._canvas.addEventListener("touchstart", function (e) {touchStartHandler(e, p);}, false);
			p._canvas.addEventListener("touchmove", function(e) {touchMoveHandler(e, p);}, false);
			document.addEventListener("touchend", function (e) {touchEndHandler(e, p);}, false);
			document.addEventListener("touchcancel", function (e) {touchEndHandler(e, p);}, false);
		}
	}
	
	return TouchEventSample;
}(window));



	function touchStartHandler(e, p) {

		e.preventDefault();
		console.log("touch start");

		var touches = e.changedTouches;

		for (var i = 0, l = touches.length; i < l; ++i) {

			var touch = touches[i];

			console.log(touch.identifier + " start");

			var target = touch.target;
			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;
			var localPoint = p._rect.globalToLocal(stageX, stageY);
			if (p._rect.hitTest(localPoint.x, localPoint.y)) {
				var offsetX = p._rect.x - stageX;
				var offsetY = p._rect.y - stageY;
				var offset = new createjs.Point(offsetX, offsetY);
				p._hitTouches.push({touch:touch, offset:offset});
			}
		}

		console.log("_hitTouches.length : " + p._hitTouches.length);

		if (p._hitTouches.length == 2) {

			if (p._startGesture) {

				// 何もしない

			} else {

				p._startGesture = true;

				myGestureStartHandler(e, p);
			}
		}
	}

	
	function touchMoveHandler(e, p) {

		e.preventDefault();
		console.log("touch move");

		var hitTouchesLength = p._hitTouches.length;
		var touches = e.touches;

		if (p._startGesture) {

			MyGestureChangeHandler(e,p);

			return;
		}

		if (!(p._dragEnabled) || hitTouchesLength === 0) {
			return;
		}


		for (var i = 0, l = touches.length; i < l; ++i) {
			var touch = touches[i];
			if (p._hitTouches[0].touch.identifier !== touch.identifier) {
				continue;
			}

			var target = touch.target;

			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;

			var offset = p._hitTouches[0].offset;

			p._rect.x = stageX + offset.x;
			p._rect.y = stageY + offset.y;

			return;
		}
	}
	
	function touchEndHandler(e, p) {

		console.log("touch end");
		e.preventDefault();
		var touches = e.changedTouches;

		outsideLoop: for (var i = 0, l = touches.length; i < l; ++i) {
			var touch = touches[i];
			for (var j = 0, m = p._hitTouches.length; j < m; ++j) {
				if (p._hitTouches[j].touch.identifier === touch.identifier) {

					console.log(touch.identifier + " end");

					p._hitTouches.splice(j, 1);
					continue outsideLoop;
				}
			}
		}

		console.log("_hitTouches.length : " + p._hitTouches.length);

		if (p._hitTouches.length == 1) {

			if (p._startGesture) {

				p._startGesture = false;

				p.lastDX = null;
				p.lastDY = null;
				p.lastR  = null;

				myGestureEndHandler(e, p);

			} else {
				// 何もしない
			}

		}
	}


	function myGestureStartHandler(e, p) {

		console.log("start myGesture");
		var touches = e.touches;

		p._dragEnabled = false;
		p._startScale = p._rect.scaleX;
		p._startRotation = p._rect.rotation;

		p.lastDX = touches[0].pageX - touches[1].pageX;
		p.lastDY = touches[0].pageY - touches[1].pageY;

		p.lastR  =  Math.sqrt(p.lastDX * p.lastDX + p.lastDY * p.lastDY);
	}
	
	function MyGestureChangeHandler(e, p) {

		console.log("change myGesture");
		var touches = e.touches;

		if (p._hitTouches.length === 0) {
			return;
		}

		if (p.lastDX == null) {
			return;// 何もしない
		}

		var presentDX = touches[0].pageX - touches[1].pageX;
		var presentDY = touches[0].pageY - touches[1].pageY;

		var presentR  = Math.sqrt(presentDX * presentDX + presentDY * presentDY);

		var scale = p._startScale + presentR/p.lastR - 1;
	
		scale = (scale < p.MIN_SCALE) ? p.MIN_SCALE : (p.MAX_SCALE < scale) ? p.MAX_SCALE : scale;

		p._rect.scaleX = p._rect.scaleY = scale;

		var rot1 = 0;

		if (p.lastDX != 0) {
			rot1 = Math.atan(p.lastDY/p.lastDX);
		}

		var rot2 = 0;

		if (presentDX != 0) {
			rot2 = Math.atan(presentDY/presentDX);
		}

		var addRotation = (rot2 - rot1) * 360 /(2 * Math.PI);

		p._rect.rotation = (p._startRotation + addRotation + 360) % 360;
	}
	
	function myGestureEndHandler(e, p) {

		console.log("end myGesture");

		p._startScale = null;
		p._startRotation = null;


		var touches = e.touches;

		for (var i = 0, l = touches.length; i < l; ++i) {

			var touch = touches[i];
			var target = touch.target;
			var stageX = touch.pageX - target.offsetLeft;
			var stageY = touch.pageY - target.offsetTop;
			var offsetX = p._rect.x - stageX;
			var offsetY = p._rect.y - stageY;

			p._hitTouches[i].offset = new createjs.Point(offsetX, offsetY);
		}

		p._dragEnabled = true;

		console.log("p._dragEnabled : " + p._dragEnabled);
	}



window.addEventListener("load", function(e) {
	window.removeEventListener("load", arguments.callee, false);
	var sample = new TouchEventSample("my-canvas");
}, false);

</script>
</head>
<body>
<canvas width="640" height="360" id="my-canvas">
お使いのWebブラウザは、HTML5のcanvasに対応していません。
</canvas>
</body>
</html>