スマホ、タブレット、あるいはタッチ式のPCでは、HTMLエレメント(div, p, canvas等)に対してタッチイベントが発生します。
JavaScriptを使って特定タグの枠内でタッチしたxy座標を取得するサンプルを紹介します。
パソコンのブラウザでタッチ操作をチェックしたい場合は、以下を参考にしてください。
TouchEventの種類
タッチイベントの種類は、touchstart, touchend, touchmoveの3つです。
これはマウスイベントでいうmousedown, mouseup, mousemoveに近いものです。
touchstart | タッチしたとき(指が触れたとき) |
touchend | タッチを終了したとき(指が離れたとき) |
touchmove | タッチしたまま操作しているとき(指を触れたまま動かしたとき) |
タッチイベントには、touchcancelというイベントもありますが、ここでは割愛します。詳しくはMDNのドキュメントを参照してください。
参考
タッチイベントでxy座標を取得する大まかな説明
touchstartイベント
HTMLエレメントをelementとした場合、以下のコードでタッチ開始時(touchstartイベント)のxy座標を取得できます。
element.addEventListener("touchstart", function(e){ // 端末のデフォルト動作をキャンセル e.preventDefault(); // タッチ開始位置を取得 const x = e.touches[0].pageX; const y = e.touches[0].pageY; // 処理 // : });
スマートフォンなどの端末ではタッチ操作が端末特有の操作イベントに対応している場合が多い為、処理の最初に
e.preventDefault();
を実行して端末特有の操作イベントを無効化する必要があります。
e.touchesは可変長の配列で、タッチしている指の数に応じて配列要素数が変化します。
複数のタッチに対応していることから、e.touchesは、タッチした順にe.touches[0], e.touches[1], e.touches[2]… となっていきます。
プロパティpageX, pageYは、読み取り専用で、ページ左上からのHTMLエレメント上の座標を返します。
上記プログラムで、実際に返される変数x, yの値は、
x = 188.33334350585938 y = 248.33334350585938
などと実数値をとるため、利用する際は Math.floor(e.touches[0].pageX) などと整数化することが多いかもしれません。
touchendとtouchmoveイベント
touchendとtouchmoveでは、e.touchesではなくe.changedTouchesを使ってxy座標を取得します。
その他は、touchstartと同じです。
touchmoveでの例
element.addEventListener("touchmove", function(e){ // 端末のデフォルト動作をキャンセル e.preventDefault(); // タッチ中の位置を取得 const x = e.changedTouches[0].pageX; const y = e.changedTouches[0].pageY; // 処理 // : });
【重要】タッチ座標の起点を考慮しないとならない場合がある
もし、タッチイベント対象のHTMLエレメントがページの左上に位置していれば問題ないのですが、他のHTML要素の上下などに配置されていたりするとpageX, pageYで取得されるxy座標はページ左上を(x,y) = (0, 0)の起点とした座標となります。
これはイメージで見た方が分かりやすいです。
例)HTML内にcanvasタグを配置したときのイメージ
もし、上記の例でcanvasの左上座標を(0, 0)としたい場合は、canvasのタッチイベントで取得したpageXとpageYから、実際のページ左上からのオフセット値x=50, y=100をそれぞれ引いてあげる必要があります。
このオフセット値は、対象エレメントのgetBoundingClientRect()のleft, topプロパティがそれぞれ対応します。
実際には以下のようなイメージでcanvasの左上を(0, 0)とすることができます。
element.addEventListener("touchstart", function(e){ // 端末のデフォルト動作をキャンセル e.preventDefault(); // ページ上のオフセット位置取得 const offset = this.getBoundingClientRect(); // タッチ開始位置を取得 const x = e.touches[0].pageX - offset.left; const y = e.touches[0].pageY - offset.top; // 処理 // : });
参考
サンプルのコード
サンプルコードでは、オフセット値を考慮し、全てgetBoundingClientRect()を使って、HTMLエレメントの左上を起点(0, 0)とした座標を返すようにしています。
touchstartを使ったサンプル
touchstartは、タッチした時にイベントが発生します。
枠内のタッチしたxy座標を返します。
複数タッチに対応して表示させるためにe.touchesの要素数分for文を使ってループさせています。iPhoneでは5本指まで表示できました。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<title>タッチイベント: touchstart</title>
</head>
<body>
<h1>touchstart</h1>
<main></main>
</body>
</html>
style.css
/* style.css */
@charset "utf-8";
*{
margin: 0;
padding: 0;
}
main{
border: 1px solid #555;
width: 300px;
height: 300px;
}
main.js
// main.js
// 起動時の処理
window.addEventListener("load", ()=>{
const main = document.querySelector("main");
main.addEventListener("touchstart", function(e){
// 端末のデフォルト動作をキャンセル
e.preventDefault();
// タッチ開始情報を取得
const touches = e.touches;
// ページ上のオフセット位置取得
const offset = this.getBoundingClientRect();
let touchValue = "";
for(let i=0; i<touches.length; i++){
const x = Math.floor(touches[i].pageX - offset.left); // x座標
const y = Math.floor(touches[i].pageY - offset.top); // y座標
touchValue += `touches[${i}] x: ${x}, y: ${y}<br>`;
}
this.innerHTML = touchValue;
});
});
touchendのサンプル
基本的にはtouchstartと同じですが、touchendは指を離したときにイベントが発生します。
また、座標の取得はe.touchesではなくe.changedTouchesを利用します。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<title>タッチイベント: touchend</title>
</head>
<body>
<h1>touchend</h1>
<main></main>
</body>
</html>
style.css
/* style.css */
@charset "utf-8";
*{
margin: 0;
padding: 0;
}
main{
border: 1px solid #555;
width: 300px;
height: 300px;
}
main.js
// main.js
// 起動時の処理
window.addEventListener("load", ()=>{
const main = document.querySelector("main");
main.addEventListener("touchend", function(e){
// 端末のデフォルト動作をキャンセル
e.preventDefault();
// タッチ終了情報を取得
const touches = e.changedTouches;
// ページ上のオフセット位置取得
const offset = this.getBoundingClientRect();
let touchValue = "";
for(let i=0; i<touches.length; i++){
const x = Math.floor(touches[i].pageX - offset.left); // x座標
const y = Math.floor(touches[i].pageY - offset.top); // y座標
touchValue += `touches[${i}] x: ${x}, y: ${y}<br>`;
}
this.innerHTML = touchValue;
});
});
touchmoveのサンプル
touchmoveはタッチした指を動かしているときにイベントが発生します。
座標の取得はe.changedTouchesを利用します。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<title>タッチイベント: touchmove</title>
</head>
<body>
<h1>touchmove</h1>
<main></main>
</body>
</html>
style.css
/* style.css */
@charset "utf-8";
*{
margin: 0;
padding: 0;
}
main{
border: 1px solid #555;
width: 300px;
height: 300px;
}
main.js
// main.js
// 起動時の処理
window.addEventListener("load", ()=>{
const main = document.querySelector("main");
main.addEventListener("touchmove", function(e){
// 端末のデフォルト動作をキャンセル
e.preventDefault();
// タッチ移動中情報を取得
const touches = e.changedTouches;
// ページ上のオフセット位置取得
const offset = this.getBoundingClientRect();
// タッチ移動中の座標を全て表示
let touchValue = "";
for(let i=0; i<touches.length; i++){
const x = Math.floor(touches[i].pageX - offset.left); // x座標
const y = Math.floor(touches[i].pageY - offset.top); // y座標
touchValue += `touches[${i}] x: ${x}, y: ${y}<br>`;
}
this.innerHTML = touchValue;
});
});
コメント