この記事では、スマートフォンやタブレット等によるタッチ操作をJavaScriptで取り扱うことができるtouchイベントについて、できるだけ簡単に解説します。

Web上に丁寧な記事はいくつもあったんだけど、正直、初心者プログラマーの僕には難しかった・・・。

執筆者も初心者で最近悩んだばかりだから、初心者の気持ちになった記事にできているかも・・・??
(簡単にするために、ちょっと大雑把な説明になります)
タッチイベントの種類
ユーザーが、画面をタッチで操作すると、操作の内容によって、以下のようなイベントが発生します。
| イベント | 発生するタイミング |
|---|---|
| touchstart | タッチ面に指が触れた時 |
| touchend | タッチしていた指を離した時 |
| touchmove | タッチしながら指を移動させた時 |
| touchcancel | 何らかの理由でタッチが取り消された時 |
まずは、下記のサンプルで、タッチイベント発生のイメージをつかんでください。
*touch areaに指を触れたり、離したり、動かしたりすると、発生したイベントと時刻がdisplay areaに表示されます。
touch area
display area
このデモのソースコードは下記のとおりです。
<div id="container1">
<p>touch area</p>
<div id="touch-area1"></div>
<p>display area</p>
<div id="display-area1"></div>
</div>
<script>
const displayArea1 = document.getElementById("display-area1")
const touchArea1 = document.getElementById("touch-area1")
// touchstartイベント
touchArea1.addEventListener("touchstart", () => {
displayArea1.innerHTML = getTimeStamp() + " touchstart"
})
// touchendイベント
touchArea1.addEventListener("touchend", () => {
displayArea1.innerHTML = getTimeStamp() + " touchend"
})
// touchmoveイベント
touchArea1.addEventListener("touchmove", () => {
event.preventDefault(); // 画面スクロールを防止
displayArea1.innerHTML = getTimeStamp() + " touchmove"
})
// touchcancelイベント
touchArea1.addEventListener("touchcancel", () => {
displayArea1.innerHTML = getTimeStamp() + " touchcacel"
})
// タイムスタンプ取得
function getTimeStamp(){
const date = new Date()
return ('0' + date.getHours()).slice(-2)
+ ':' + ('0' + date.getMinutes()).slice(-2)
+ ':' + ('0' + date.getSeconds()).slice(-2)
+ ':' + ('0' + date.getMilliseconds()).slice(-3)
}
</script>

あれ? touch area の外に指を移動させたり、touch areaの外で指を離したりしてもイベントが発生するみたいだけど・・・?

それは私もハマったポイントよ。
例えば、touch areaに対して“touchend”のイベントリスナーを追加した場合、「touch area上でタッチを開始した指をスクリーンから離した時」にイベントが発火するわ。
「touch areaから指が離れた時」という条件ではない事に注意してね!“touchmove”も同じ考え方よ。
タッチの情報を取得する
先に説明したとおり、タッチを開始したり、指を動かしたり離したりすると、TouchEventが発生します。
TouchListとTouchオブジェクト
TouchEventオブジェクトは、3種のTouchListをもっており、その中に、タッチの情報(タッチした座標など)をもつTouchオブジェクトがあります。
下図は、この説明を図示したものです。
*指3本でタッチした後、さらにもう一本の指でタッチした時のイメージ



タッチしてる指の情報が3種類のタッチリストで確認できるんだね~
3種のTouchList
TouchEventは、下記3種のTouchListをもっています。
リストごとに、含まれるTouchオブジェクト(≒指の情報)が異なりますので、用途によって使い分けが必要です。
| touches | すべてのTouchオブジェクトを格納 *さっきの例では、合計4本の指でタッチしているので4つ |
| changedTouches | 変更されたTouchオブジェクトを格納 *さっきの例では、追加で③のタッチを行ったので、③の情報 |
| targetTouches | イベントのターゲットと同じ要素でタッチを始めた Touchオブジェクトを格納 *さっきの例では、③のターゲットである#blue-area要素でタッチが始まった3つ(⓪,①,③) |

・・・で、どのリストを使えばいいの・・・?

う~ん、大体の場合はchangedTouchesを使えばいいんじゃないかな。
特に、指を離した時に、離した指の情報を取得できるのはchangedTouchesだけよ。
Touchオブジェクト
各タッチの情報は、Touchオブジェクトから取得することができます。
Touchオブジェクトは、触った指ごとに発生しますので、もし4本の指でタッチしたら4つのTouchオブジェクトが発生します。
Touchオブジェクトから取得できる主な情報は下表のとおりです。
| identifier | 各タッチに付与される番号。 指のIDのようなもので、指を離すまではidentifierは変わりません |
| screenX | 端末のスクリーンの左端からの距離(px) |
| screenY | 端末のスクリーンの上端からの距離(px) |
| clientX | ブラウザのビューポートの左端からの距離(px) |
| clientY | ブラウザのビューポートの上端からの距離(px) |
| pageX | ドキュメントの上端からの距離(px) |
| pageY | ドキュメントの上端からの距離(px) |
| target | その指をタッチ開始した位置にあるElement *指を移動しても、targetはタッチ開始時の位置のElementのまま |

いっぱいあるけど、つまりは、指のID と 座標の情報 って感じだね

page、screen、clientの値の違いは、下の図を見ればわかるわよ~

(参考として、HTML要素の座標についても右側に書いてみました。タッチした座標とHTML要素の座標を比較することが、よくあると思うので・・・)
TouchList・Touchオブジェクトを理解するためのサンプル
こちらもお試し用のサンプルを作ってみました。
3つのTouchListの違いや、Touchオブジェクトの中身が理解できると思います。
touch area
このサンプルのソースコードは以下のとおりです。
<div id="container2">
<p>touch area</p>
<div id="touch-area2">
<div id="blue-area">blue</div>
<div id="red-area">red</div>
</div>
<div>
<span>touches</span>
<button onclick="pushBtn('display-touches')">表示・非表示 切替</button>
<div id="display-touches"></div>
</div>
<div>
<span>changedTouches</span>
<button onclick="pushBtn('display-changed-touches')">表示・非表示 切替</button>
<div id="display-changed-touches"></div>
</div>
<div>
<span>targetTouches</span>
<button onclick="pushBtn('display-target-touches')">表示・非表示 切替</button>
<div id="display-target-touches"></div>
</div>
</div>
<script>
// 要素の取得
const touchArea2 = document.getElementById("touch-area2")
const displayTouches = document.getElementById("display-touches")
const displayChangedTouches = document.getElementById("display-changed-touches")
const displayTargetTouches = document.getElementById("display-target-touches")
// 各タッチイベントのイベントリスナー登録
touchArea2.addEventListener("touchstart", function(){ updateDisplay(event) } )
touchArea2.addEventListener("touchend", function(){ updateDisplay(event) } )
touchArea2.addEventListener("touchmove",function(){
event.preventDefault() // 画面スクロールを防止
updateDisplay(event)
} )
touchArea2.addEventListener("touchcancel",function(){ updateDisplay(event) } )
// タッチの情報を画面に表示する
function updateDisplay(event){
displayTouches.innerHTML = getTouchInfo(event.touches)
displayChangedTouches.innerHTML = getTouchInfo(event.changedTouches)
displayTargetTouches.innerHTML = getTouchInfo(event.targetTouches)
}
// 与えられたタッチリストからタッチ情報を取得
function getTouchInfo(touchList){
let displayStr = ""
for ( const touch of touchList ){
displayStr += `
identifier: ${touch.identifier}<br>
screenX: ${touch.screenX}<br>
screenY: ${touch.screenY}<br>
clientX: ${touch.clientX}<br>
clientY: ${touch.clientY}<br>
pageX: ${touch.pageX}<br>
pageY: ${touch.pageY}<br>
target: ${touch.target.id}<br>
--------------------------------------<br>`
}
return displayStr
}
// 表示・非表示ボタン
function pushBtn(targetId){
document.getElementById(targetId).classList.toggle('hide')
}
</script>
勘違いしやすい(?)ポイント
他の人はどうかわかりませんが、私が勘違いしたポイントをメモしておきます。
1.touchmoveとtouchendの発火
誤:イベントリスナーを追加した要素の上で指を動かす・指を離すと発火
正:イベントリスナーを追加した要素の上でタッチを開始した指を動かす・離すと発火
2.TouchListに入っているtouchオブジェクト
誤:イベントリスナーを追加した要素の上でタッチした指の情報
正:スクリーンにタッチした指の情報
先ほどのサンプルで、タッチエリア以外の部分をタッチしながら、他の指でタッチエリアを触ると、この意味がわかると思います。
3.Touchオブジェクトのtarget
誤:現在触れているHTML要素
正:そのタッチを開始した時に触れたHTML要素
参考
touchイベントを初めて学んで作った成果物です
MDNのTouchの解説ページ


コメント