タッチデバイスを指で快適に操作させるために:HTML5アプリのタッチUX(2)(1/2 ページ)
タッチデバイスのUIの特徴とその癖から、HTML5のWebアプリでUXを実現するポイント、Webでのタッチイベント仕様を見てみよう。
前編のタッチUXを実現する7つのポイントでは、タッチデバイスの特徴と、その上でタッチUXを実現する7つのポイントについて説明しました。後編では、そのようなUXを実現するためにWebアプリでのタッチ仕様や、実装のポイント、今後の動向など、より技術的な面から解説します。
W3Cによるタッチイベントの標準化
Webアプリケーション向けのタッチイベント仕様はW3Cによって標準化が進められていて、執筆時(2012/10/20 現在)の段階で、勧告候補となっています(最新のものはW3Cの明示する「Touch Events version 1」を確認してください)。まだ仕様は確定していませんが、最新のiOS、Androidのブラウザでほぼ仕様通りのものが使用できます。タッチイベント仕様は、表1の3つのインターフェイスと表2の4つのイベントが中心になっています。各インターフェイスの関連は図1のクラス図を参照してください。
インターフェイス | 概要 |
---|---|
TouchEvent | タッチを表すイベントオブジェクト |
TouchList | Touchの集合(リスト) |
Touch | 個別のタッチポイントを表し、タッチのIDや座標などを持つ |
表1.インターフェイス一覧 |
要素をタッチすると、表2のイベントタイプに応じたTouchEventが発生します。TouchEventはプロパティに表3のTouchListを持ちます。TouchListはマルチタッチのためのインターフェイスで、複数のTouchオブジェクトが格納されています。なお、どのオブジェクトも不変で、一度作成された後は、属性の追加・変更などはできないと仕様で定義されています。
イベントタイプ | 概要 |
---|---|
touchstart | タッチ開始時に発生 |
touchend | タッチ終了時に発生 |
touchmove | タッチ移動時に発生 |
touchcancel | システムによる割り込み(着信、アラームなど) |
表2.タッチイベントタイプ一覧 |
厳密にいうと、JavaScriptの仕様的には可能ですが、追加変更した属性が保持される保証はないため、しない方が安全です。実際、iOSのSafariでは特定の状況で初期化される場合があります。
属性 | 概要 |
---|---|
touches | 現在タッチしているすべてのTouchList |
targetTouches | 対象要素をタッチしているTouchList |
changedTouches | 変更されたタッチのTouchList |
表3.TouchEventが持つTouchList型のプロパティ |
用途に応じて表3のTouchEventのTouchListを使い分けます。touchendイベントの場合、少し注意が必要です。touchendイベントは指が離れてから発生します。そうすると、すでに指は離れている状態になり、touchesとtargetTouchesには離れたTouchオブジェクトはなくなります。離れたタッチの情報を取りたい場合はchangedTouchを使用します。
イベントタイプ | 概要 |
---|---|
identifier | タッチポイントのID |
clientX/Y | クライアント領域(viewport)に対する座標 |
pageX/Y | ページ全体(html要素)に対する座標 |
screenY/Y | 画面の表示領域に対する座標 |
target | イベントの発生元 |
表4.Touchオブジェクトのプロパティ |
Touchオブジェクトは、表4のようなプロパティを持ちます。identifierはタッチオブジェクトを一意に定めます。touchListの順番は保証されないため、この値を見てタッチのトラッキングを行います。
図2のように、clientX/Yは現在の表示領域の左上基点とした座標を返します。スクロールした場合、見えている範囲の左上が基点になります。pageX/Yは、ページ全体、つまりHTML要素の左上を基点とした座標になります。この座標はclientX/Yと異なり、スクロールしても変わりません。screenX/Yはスクリーン(ディスプレイ)上での座標です。
実は、iOSとAndroidでこれらの解釈が微妙に異なっていて、Androidでは2.3系と4系、Chromeとでも異なります。特にviewportの拡大・縮小したときのscreenX/Y、clientX/Yの挙動が異なります。クロスプラットフォームを実現するために、通常はpageX/Yを使用するのが無難でしょう。
また、マウスイベントのような要素内での相対位置を表すoffsetX/Yはプロパティにありません。そのような値を使用したい場合は要素のオフセットを取得し、pageX/Yと加算することで得られます。
TouchEventのイベントタイプは表2のように4種類あり、これらはマウスイベントのそれと似ています。touchstart, touchend, touchmoveは、それぞれマウスイベントのmousedown, mouseup, mousemoveとおおよそ同じで、図3のように、タッチが開始されたとき、移動したとき、終了した(指が離れた)に発生します。
touchcancelだけはマウスイベントになく、タッチイベント独自のイベントタイプです。これはシステムから強制的にキャンセルされた場合に発生します。着信やアラームなどの他に、iPadのマルチタスク用ジェスチャや、ネイティブアプリに組み込んでいるときにdocumentから出た場合などに発生します。
マウスイベントと大きく異なる点は、マルチタッチがあるということです。マルチタッチの処理は注意深く行う必要があります。2本指でタッチする場合など、タイミングによって発生するイベントの回数が異なるからです。
完全同時にタッチした場合は、touchstartイベントが一度だけ発生し、changedTouchesにTouchオブジェクトが2つ入ります。しかし僅でもずれた場合、touchstartイベントが2回発生し、それぞれchangedTouchesにTouchオブジェクトが1つ入ります。人の指で操作するとこれらの違いを意図して出すことは困難です。ユーザーを混乱させないよう、マルチタッチ処理を行う場合はどちらでも動作するよう実装する必要があるでしょう。
タッチイベントの確認サンプル
それでは、具体的にどのように実装するのか、サンプルを見ながら確認していきましょう。このサンプルでは、タッチエリアをタッチして発生したイベントの情報を表示します。サンプルのコードはGitHubのdsuke/touch-sampleに公開しています。また、実際に動くページは同GitHub Pageから見られます。
タッチイベントを処理するには、対象の要素にイベントリスナーを追加します。次の例では、el要素にtouchstartイベントのリスナーを追加しています。touchstartイベントが発生するとchangedTouchesのTouchオブジェクトを表示します。
// タッチ開始リスナーの追加 el.addEventListener("touchstart", function(event) { stopEvent(event); logger.log("touchstart:"); printTouches(event.changedTouches); }, false);
リスナー関数の最初で呼ばれるstopEvent関数は次のようになっています。これを行うことによって、ブラウザのデフォルトの動作(画面のスクロールなど)を抑止し、イベント伝播を止めます。
// イベントの停止 var stopEvent = function(event) { event.preventDefault(); event.stopPropagation(); }
Touchオブジェクトを表示する関数 printTouches は次の通りです。
// タッチリストを表示する関数 var printTouches = function(touchList) { var i = 0, len = touchList.length; for (; i<len; i++) { var touch = touchList.item(i); logger.log("- " + touch.identifier + ": (" + touch.screenX + ", " + touch.screenY + "), (" + touch.pageX + ", " + touch.pageY + "), (" + touch.clientX + ", " + touch.clientY + ")"); } }
引数で渡されたtouchListをfor文で回し、touchList.item(i)で各Touchオブジェクトを取得します。そして、取得したTouchオブジェクトのidentifier、screenX/Y、pageX/Y、clientX/Yを画面に表示します。
touchstartと同様に、touchmove、touchendイベントにもリスナーを登録してこのサンプルは完成です。iPhoneやAndroidなどタッチ可能なブラウザで動作を確認してください。その際、スクロールや拡大して、各プロパティの変化を見てみてください。
また、このサンプルではchangedTouchesのTouchオブジェクトを表示していますが、touchesやtargetTouchesではどのような違いがあるのか、ぜひご自分で書き換えて確認していただければと思います。
Copyright © ITmedia, Inc. All Rights Reserved.