diff options
| author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
|---|---|---|
| committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
| commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
| tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/web/api/pointer_events | |
| parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
| download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip | |
initial commit
Diffstat (limited to 'files/ja/web/api/pointer_events')
4 files changed, 1198 insertions, 0 deletions
diff --git a/files/ja/web/api/pointer_events/index.html b/files/ja/web/api/pointer_events/index.html new file mode 100644 index 0000000000..9d4e69e53a --- /dev/null +++ b/files/ja/web/api/pointer_events/index.html @@ -0,0 +1,445 @@ +--- +title: Pointer events +slug: Web/API/Pointer_events +tags: + - API + - Landing + - Overview + - Pointer Events +translation_of: Web/API/Pointer_events +--- +<p>{{DefaultAPISidebar("Pointer Events")}}</p> + +<p><span class="seoSummary">今日のウェブコンテンツの多くは、ユーザーのポインティングデバイスがマウスであることを前提としています。 しかしながら、多くのデバイスがペン/スタイラスおよびタッチ面のような他のタイプのポインティング入力デバイスをサポートしているので、既存のポインティングデバイスのイベントモデルへの拡張が必要であり、そして<em><a href="#term_pointer_event">ポインタイベント</a></em>はその必要性に対処します。</span></p> + +<p>ポインタイベントは、ポインティングデバイスに対して発生する DOM イベントです。 これらは、マウス、ペン/スタイラス、(1本以上の指でなどの)タッチなどのポインティング入力デバイスを処理する単一の DOM イベントモデルを作成するように設計されています。 <em><a href="#term_pointer">ポインタ</a></em>は、特定の画面座標セットをターゲットにできるハードウェアにとらわれないデバイスです。 ポインタに単一のイベントモデルを使用すると、ウェブサイトやウェブアプリの作成が簡単になり、ユーザーのハードウェアに関係なく優れたユーザーエクスペリエンスを提供できます。 しかしながら、デバイス固有の処理が必要なシナリオのために、ポインタイベントはイベントを生成したデバイスタイプを調べるための {{domxref("PointerEvent.pointerType","pointerType")}} プロパティを定義しています。</p> + +<p>一般的なポインタ入力を処理するために必要なイベントは、{{domxref("MouseEvent","マウスイベント")}}に似ています(<code>mousedown/pointerdown</code>、<code>mousemove/pointermove</code> など)。 したがって、ポインタイベントタイプは意図的にマウスイベントタイプと似せています。 さらに、ポインタイベントには、マウスイベントに存在する通常のプロパティ(クライアント座標、ターゲット要素、ボタンの状態など)、およびその他の入力形式のための新しいプロパティ(圧力、接触ジオメトリ、傾きなど)が含まれています。 実際、{{domxref("PointerEvent")}} インターフェイスはすべての {{domxref("MouseEvent")}} のプロパティを継承するため、マウスイベントからポインタイベントへのコンテンツの移行が容易になります。</p> + +<h2 id="Terminology" name="Terminology">用語</h2> + +<dl> + <dt>アクティブボタン状態(active buttons state)</dt> + <dd><em><a href="#term_pointer">ポインタ</a></em>が <code>buttons</code> プロパティに対してゼロ以外の値を持つ場合の条件。 例えば、ペンの場合は、ペンがデジタイザと物理的に接触しているか、ホバー中に少なくとも1つのボタンが押されているときです。</dd> + <dt>アクティブポインタ(active pointer)</dt> + <dd>イベントを生成できる任意の<em><a href="#term_pointer">ポインタ</a></em>入力デバイス。 ポインタがそれ以上のイベントを生成する可能性がある場合、ポインタはアクティブと見なされます。 例えば、ペンが持ち上げられたり動かされたりすると追加のイベントが発生する可能性があるため、ペンがダウン状態であるとアクティブであると見なされます。</dd> + <dt id="term_digitizer">デジタイザ(digitizer)</dt> + <dd>接触を検出できる表面を備えた検知デバイス。 最も一般的な検知デバイスは、ペン、スタイラス、または指などの入力デバイスからの入力を検知することができるタッチ対応画面です。 検知デバイスの中には、入力デバイスの近接を検出できるものもあり、その状態をマウスにならってホバーと表現します。</dd> + <dt id="term_hit_test">ヒットテスト(hit test)</dt> + <dd>ブラウザーがポインタイベントのターゲット要素を決定するために使用するプロセス。 通常、これはポインタの位置と、画面媒体上のドキュメント内の要素の視覚的なレイアウトを考慮して決定されます。</dd> + <dt id="term_pointer">ポインタ(pointer)</dt> + <dd>画面上の特定の座標(または座標のセット)をターゲットにできる、入力デバイスのハードウェアにとらわれない表現。 <em>ポインタ</em>入力デバイスの例は、マウス、ペン/スタイラス、およびタッチ接触です。</dd> + <dt>ポインタキャプチャ(pointer capture)</dt> + <dd>ポインタキャプチャでは、ポインタイベントをポインタの位置による通常のヒットテストの結果以外の特定の要素にターゲットしなおすことができます。</dd> + <dt id="term_pointer_event">ポインタイベント(pointer event)</dt> + <dd><em><a href="#term_pointer">ポインタ</a></em>に対して発生した DOM {{domxref("PointerEvent","イベント")}}。</dd> +</dl> + +<h2 id="Interfaces" name="Interfaces">インターフェイス</h2> + +<p>主なインターフェイスは、{{domxref("PointerEvent.PointerEvent","コンストラクタ")}}といくつかのイベントタイプおよび関連するグローバルイベントハンドラを持つ {{domxref("PointerEvent")}} インターフェイスです。 この標準には、{{domxref("Element")}} インターフェイスと {{domxref("Navigator")}} インターフェイスの拡張も含まれています。 以下のサブセクションでは、各インターフェイスとプロパティについて簡単に説明します。</p> + +<h3 id="PointerEvent_interface" name="PointerEvent_interface">PointerEvent インターフェイス</h3> + +<p>{{domxref("PointerEvent")}} インターフェイスは、{{domxref("MouseEvent")}} インターフェイスを拡張したもので、次のプロパティがあります(それらはすべて{{readonlyInline}}です)。</p> + +<ul> + <li>{{ domxref('PointerEvent.pointerId','pointerId')}} - イベントの原因となっているポインタの一意の識別子。</li> + <li>{{ domxref('PointerEvent.width','width')}} - ポインタの接触ジオメトリの幅(X 軸上の大きさ、CSS ピクセル単位)。</li> + <li>{{ domxref('PointerEvent.height','height')}} - ポインタの接触ジオメトリの高さ(Y 軸上の大きさ、CSS ピクセル単位)。</li> + <li>{{ domxref('PointerEvent.pressure','pressure')}} - 0 から 1 までの範囲のポインタ入力の正規化された圧力。 ここで、0 と 1 は、それぞれハードウェアが検出できる最小圧力と最大圧力を表します。</li> + <li>{{ domxref('PointerEvent.tangentialPressure','tangentialPressure')}} - ポインタ入力の正規化された接線圧力(バレル圧力またはシリンダー応力(cylinder stress)とも呼ばれます)は -1 から 1 の範囲で、0 はコントロールの中立位置です。</li> + <li>{{ domxref('PointerEvent.tiltX','tiltX')}} - Y-Z 平面と、ポインタ(ペン/スタイラスなど)の軸と Y 軸の両方を含む平面との間の平面角度(度単位で、-90 から 90 の範囲)。</li> + <li>{{ domxref('PointerEvent.tiltY','tiltY')}} - X-Z 平面と、ポインタ(ペン/スタイラスなど)の軸と X 軸の両方を含む平面との間の平面角度(度単位で、-90 から 90 の範囲)。</li> + <li>{{ domxref('PointerEvent.twist','twist')}} - ポインタ(ペン/スタイラスなど)の長軸を中心とした時計回りの回転の度数(0 から 359の範囲の値)。</li> + <li>{{ domxref('PointerEvent.pointerType','pointerType')}} - イベントの原因となったデバイスタイプ(マウス、ペン、タッチなど)を示します。</li> + <li>{{ domxref('PointerEvent.isPrimary','isPrimary')}} - ポインタがこのポインタタイプのプライマリポインタを表すかどうかを示します。</li> +</ul> + +<h3 id="Event_types_and_Global_Event_Handlers" name="Event_types_and_Global_Event_Handlers">イベントタイプとグローバルイベントハンドラ</h3> + +<p>ポインタイベントには10のイベントタイプがあり、そのうち7つはマウスイベントと同等の意味を持ちます(ダウン(<code>down</code>)、アップ(<code>up</code>)、移動(<code>move</code>)、オーバー(<code>over</code>)、アウト(<code>out</code>)、進入(<code>enter</code>)、離脱(<code>leave</code>))。 以下は、各イベントタイプとそれに関連する{{domxref("GlobalEventHandlers","グローバルイベントハンドラ")}}の簡単な説明です。</p> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">イベント</th> + <th scope="col">イベントハンドラ</th> + <th scope="col">説明</th> + </tr> + <tr> + <td>{{event('pointerover')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerover','onpointerover')}}</td> + <td>ポインタが要素の<a href="#term_hit_test">ヒットテスト</a>境界内に移動したときに発生します。</td> + </tr> + <tr> + <td>{{event('pointerenter')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerenter','onpointerenter')}}</td> + <td>ポインタが要素またはその子孫の1つの<a href="#term_hit_test">ヒットテスト</a>境界内に移動したときに発生します。 これには、ホバーをサポートしていないデバイスからの <code>pointerdown</code> イベントの結果も含まれます(<code>pointerdown</code> を参照)。</td> + </tr> + <tr> + <td>{{event('pointerdown')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerdown','onpointerdown')}}</td> + <td>ポインタが<em>アクティブボタン状態</em>になったときに発生します。</td> + </tr> + <tr> + <td>{{event('pointermove')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointermove','onpointermove')}}</td> + <td>ポインタが座標を変更したときに発生します。 また、ポインタの状態の変化がこれ以外のイベントで報告できない場合もこのイベントが使われます。</td> + </tr> + <tr> + <td>{{event('pointerup')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerup','onpointerup')}}</td> + <td>ポインタが<em>アクティブボタン状態</em>でなくなったときに発生します。</td> + </tr> + <tr> + <td>{{event('pointercancel')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointercancel','onpointercancel')}}</td> + <td>ブラウザーは、ポインタがイベントを生成できなくなったと判断した場合(例えば、関連デバイスが無効になった場合)、このイベントを発生させます。</td> + </tr> + <tr> + <td>{{event('pointerout')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerout','onpointerout')}}</td> + <td>次のようないくつかの理由で発生します。 ポインタが要素の<a href="#term_hit_test">ヒットテスト</a>境界外に移動した。 ホバーをサポートしていないデバイスの <code>pointerup</code> イベントが発生した(<code>pointerup</code> を参照)。 <code>pointercancel</code> イベントの発生後(<code>pointercancel</code> を参照)。 ペン/スタイラスがデジタイザで検出可能なホバー範囲を離脱したとき。</td> + </tr> + <tr> + <td>{{event('pointerleave')}}</td> + <td>{{domxref('GlobalEventHandlers.onpointerleave','onpointerleave')}}</td> + <td>ポインタが要素の<a href="#term_hit_test">ヒットテスト</a>境界外に移動したときに発生します。 ペンデバイスの場合、このイベントは、スタイラスがデジタイザで検出可能なホバー範囲を離脱したときに発生します。</td> + </tr> + <tr> + <td>{{event('gotpointercapture')}}</td> + <td>{{domxref('GlobalEventHandlers.ongotpointercapture','ongotpointercapture')}}</td> + <td>要素がポインタキャプチャを受け取ったときに発生します。</td> + </tr> + <tr> + <td>{{event('lostpointercapture')}}</td> + <td>{{domxref('GlobalEventHandlers.onlostpointercapture','onlostpointercapture')}}</td> + <td>ポインタに対するポインタキャプチャが解放された後に発生します。</td> + </tr> + </tbody> +</table> + +<h3 id="Element_extensions" name="Element_extensions">Element の拡張</h3> + +<p>{{domxref("Element")}} インターフェイスには次の3つの拡張機能があります。</p> + +<ul> + <li>{{domxref("Element.setPointerCapture()","setPointerCapture()")}} - このメソッドは、将来のポインタイベントの<em>キャプチャターゲット</em>として特定の要素を指定します。</li> + <li>{{domxref("Element.releasePointerCapture()","releasePointerCapture()")}} - このメソッドは、特定のポインタイベントに対して以前に設定された<em>ポインタキャプチャ</em>を解放(停止)します。</li> +</ul> + +<h3 id="Navigator_extension" name="Navigator_extension">Navigator の拡張</h3> + +<p>{{domxref("Navigator.maxTouchPoints")}} プロパティは、任意の時点でサポートしている同時タッチポイントの最大数を決定するために使用します。</p> + +<h2 id="Examples" name="Examples">例</h2> + +<p>このセクションでは、ポインタイベントのインターフェイスを使用した基本的な使い方の例を紹介します。</p> + +<h3 id="Registering_event_handlers" name="Registering_event_handlers">イベントハンドラの登録</h3> + +<p>この例では、特定の要素のすべてのイベントタイプに対してハンドラを登録します。</p> + +<pre class="brush: html"><html> + <script> + function over_handler(event) { } + function enter_handler(event) { } + function down_handler(event) { } + function move_handler(event) { } + function up_handler(event) { } + function cancel_handler(event) { } + function out_handler(event) { } + function leave_handler(event) { } + function gotcapture_handler(event) { } + function lostcapture_handler(event) { } + + function init() { + var el=document.getElementById("target"); + // ポインタイベントハンドラの登録 + el.onpointerover = over_handler; + el.onpointerenter = enter_handler; + el.onpointerdown = down_handler; + el.onpointermove = move_handler; + el.onpointerup = up_handler; + el.onpointercancel = cancel_handler; + el.onpointerout = out_handler; + el.onpointerleave = leave_handler; + el.gotpointercapture = gotcapture_handler; + el.lostpointercapture = lostcapture_handler; + } + </script> + <body onload="init();"> + <div id="target"> Touch me ... </div> + </body> +</html> +</pre> + +<h3 id="Event_properties" name="Event_properties">イベントのプロパティ</h3> + +<p>この例では、タッチイベントのすべてのプロパティにアクセスする方法を示します。</p> + +<pre class="brush: html"><html> + <script> + var id = -1; + + function process_id(event) { + // イベントの識別子に基づいて、このイベントを処理する + } + function process_mouse(event) { + // マウスポインタイベントを処理する + } + function process_pen(event) { + // ペンポインタイベントを処理する + } + function process_touch(event) { + // タッチポインタイベントを処理する + } + function process_tilt(tiltX, tiltY) { + // 傾斜データハンドラ + } + function process_pressure(pressure) { + // 圧力ハンドラ + } + function process_non_primary(event) { + // 非プライマリハンドラ + } + + function down_handler(ev) { + // タッチポイントの接触面積を計算する + var area = ev.width * ev.height; + + // キャッシュされた id とこのイベントの id を比較し、それに応じて処理する + if (id == ev.identifier) process_id(ev); + + // 適切なポインタタイプのハンドラを呼び出す + switch (ev.pointerType) { + case "mouse": + process_mouse(ev); + break; + case "pen": + process_pen(ev); + break; + case "touch": + process_touch(ev); + break; + default: + console.log("pointerType " + ev.pointerType + " はサポートしていません"); + } + + // 傾斜ハンドラを呼び出す + if (ev.tiltX != 0 && ev.tiltY != 0) process_tilt(ev.tiltX, ev.tiltY); + + // 圧力ハンドラを呼び出す + process_pressure(ev.pressure); + + // このイベントがプライマリではない場合は、非プライマリハンドラを呼び出す + if (!ev.isPrimary) process_non_primary(ev); + } + + function init() { + var el=document.getElementById("target"); + // pointerdown ハンドラの登録 + el.onpointerdown = down_handler; + } + </script> + <body onload="init();"> + <div id="target"> Touch me ... </div> + </body> +</html> +</pre> + +<h2 id="Determining_the_Primary_Pointer" name="Determining_the_Primary_Pointer">プライマリポインタの決定</h2> + +<p>シナリオによっては、複数のポインタ(例えば、タッチ画面とマウスの両方を備えたデバイス)やポインタが複数の接触点をサポートする(例えば、複数の指でのタッチをサポートするタッチ画面)ことがあります。 アプリは、{{domxref("PointerEvent.isPrimary","isPrimary")}} プロパティを使用して、各ポインタタイプの<em>アクティブポインタ</em>のセットの中からマスターポインタを識別できます。 アプリがプライマリポインタのみをサポートしたい場合は、プライマリではないすべてのポインタイベントを無視できます。</p> + +<p>マウスの場合、ポインタは1つだけなので、常にプライマリポインタになります。 タッチ入力の場合、他にアクティブなタッチがなかったときにユーザーが画面にタッチした場合、ポインタはプライマリと見なされます。 ペンとスタイラスの入力では、他のアクティブなペンが画面に接触していないときにユーザーのペンが最初に画面に接触した場合、ポインタはプライマリと見なされます。</p> + +<h2 id="Determining_button_states" name="Determining_button_states">ボタンの状態の判断</h2> + +<p>マウスやペンなどの一部のポインタデバイスは複数のボタンをサポートしており、ボタンの押下で<em>和音を弾く</em>ことができます。 すなわち、ポインタデバイス上の別のボタンが既に押されている間に、追加のボタンを押すことができます。 ボタンが押された状態を判断するために、ポインタイベントは({{domxref("PointerEvent")}} の継承元の){{domxref("MouseEvent")}} インターフェイスの {{domxref("MouseEvent.button","button")}} プロパティおよび {{domxref("MouseEvent.buttons","buttons")}} プロパティを使用します。 次の表は、さまざまなデバイスボタンの状態に対応する <code>button</code> および <code>buttons</code> の値を示しています。</p> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">デバイスボタンの状態</th> + <th scope="col">button</th> + <th scope="col">buttons</th> + </tr> + <tr> + <td>最後のイベント以降、ボタンもタッチ/ペンの接触も変更されませんでした</td> + <td>-1</td> + <td>—</td> + </tr> + <tr> + <td>ボタンを押さずにマウスを動かした、ボタンを押さずにホバー中にペンを動かした</td> + <td>—</td> + <td>0</td> + </tr> + <tr> + <td>左マウス、タッチ接触、ペン接触</td> + <td>0</td> + <td>1</td> + </tr> + <tr> + <td>中マウス</td> + <td>1</td> + <td>4</td> + </tr> + <tr> + <td>右マウス、ペンのバレルボタン</td> + <td>2</td> + <td>2</td> + </tr> + <tr> + <td>X1(戻る)マウス</td> + <td>3</td> + <td>8</td> + </tr> + <tr> + <td>X2(進む)マウス</td> + <td>4</td> + <td>16</td> + </tr> + <tr> + <td>ペンの消しゴムボタン</td> + <td>5</td> + <td>32</td> + </tr> + </tbody> +</table> + +<div class="blockIndicator note"> +<p><code>button</code> プロパティは、ボタンの状態の変化を示していることに注意してください。 ただし、タッチの場合のように、1つのイベントに伴って複数のイベントが発生する場合は、それらはすべて同じ値になります。</p> +</div> + +<h2 id="Pointer_capture" name="Pointer_capture">ポインタキャプチャ</h2> + +<p>ポインタキャプチャでは、ポインタの位置での通常の<a href="#term_hit_test">ヒットテスト</a>ではなく、特定の{{domxref("PointerEvent","ポインタイベント")}}のイベントを特定の要素にターゲットしなおすことができます。 これは、ポインタデバイスの接触が要素から外れた場合でも、要素がポインタイベントを受信し続けるようにするために使用できます(例えば、スクロールで)。</p> + +<p>次の例では、要素にポインタキャプチャを設定しています。</p> + +<pre class="brush: html"><html> +<script> + function downHandler(ev) { + var el=document.getElementById("target"); + // 要素 'target' はそれ以上のイベントを受信/キャプチャします + el.setPointerCapture(ev.pointerId); + } + + function init() { + var el=document.getElementById("target"); + el.onpointerdown = downHandler; + } +</script> +<body onload="init();"> + <div id="target"> Touch me ... </div> +</body> +</html> +</pre> + +<p>次の例は、({{event("pointercancel")}} イベントが発生したときに)ポインタキャプチャを解放しています。 {{event("pointerup")}} イベントや {{event("pointercancel")}} イベントが発生すると、ブラウザーはこれを自動的に行います。</p> + +<pre class="brush: html"><html> + <script> + function downHandler(ev) { + var el=document.getElementById("target"); + // 要素 "target" はそれ以上のイベントを受信/キャプチャします + el.setPointerCapture(ev.pointerId); + } + + function cancelHandler(ev) { + var el=document.getElementById("target"); + // ポインタキャプチャを解放する + el.releasePointerCapture(ev.pointerId); + } + + function init() { + var el=document.getElementById("target"); + // pointerdown と pointercancel のハンドラの登録 + el.onpointerdown = downHandler; + el.onpointercancel = cancelHandler; + } + </script> + <body onload="init();"> + <div id="target"> Touch me ... </div> + </body> +</html> +</pre> + +<h2 id="touch-action_property" name="touch-action_property">touch-action プロパティ</h2> + +<p>{{cssxref("touch-action")}} CSS プロパティは、ブラウザーがデフォルトの(<em>ネイティブな</em>)タッチの振る舞い(ズームやパンなど)を領域に適用するかどうかを指定するために使用します。 このプロパティは、置換されていないインライン要素、テーブル行、行グループ、テーブル列、および列グループを除くすべての要素に適用できます。</p> + +<p><code>auto</code> の値は、ブラウザーがそのデフォルトのタッチの振る舞いを(指定された領域に)自由に適用できることを意味し、<code>none</code> の値はブラウザーのその領域に対するデフォルトのタッチの振る舞いを無効にします。 値 <code>pan-x</code> および <code>pan-y</code> は、指定された領域で始まるタッチがそれぞれ水平スクロールおよび垂直スクロール専用であることを意味します。 値 <code>manipulation</code> は、ブラウザーがその要素から始まるタッチをスクロールとズームのみを考慮していることを意味します。</p> + +<p>次の例では、ブラウザーのデフォルトのタッチの振る舞いは <code>div</code> 要素に対して無効になります。</p> + +<pre class="brush: html"><html> + <body> + <div style="touch-action:none;">Can't touch this ... </div> + </body> +</html> +</pre> + +<p>次の例では、一部の <code>button</code> 要素ではデフォルトのタッチの振る舞いが無効になります。</p> + +<pre class="brush: css">button#tiny { + touch-action: none; +} +</pre> + +<p>次の例では、<code>target</code> 要素にタッチすると、水平方向にのみパンします。</p> + +<pre class="brush: css">#target { + touch-action: pan-x; +} +</pre> + +<h2 id="Compatibility_with_mouse_events" name="Compatibility_with_mouse_events">マウスイベントとの互換性</h2> + +<p>ポインタイベントのインターフェイスを使用すると、アプリはポインタ対応デバイスで高度なユーザーエクスペリエンスを作成できますが、現実での今日のウェブコンテンツの大部分はマウス入力でのみ機能するように設計されています。 その結果、ブラウザーがポインタイベントをサポートしていても、マウスのみの入力が直接変更せずにそのまま機能することを前提として、ブラウザーはマウスイベントを処理する必要があります。 理想的には、ポインタ対応アプリはマウス入力を明示的に処理する必要はありません。 ただし、ブラウザーはマウスイベントを処理する必要があるため、対処する必要がある互換性の問題がいくつかあるかもしれません。 このセクションでは、ポインタイベントとマウスイベントの相互作用、およびアプリ開発者への影響について説明します。</p> + +<p>ブラウザーは、<em>マウスベースのコンテンツとの互換性のために、汎用ポインタ入力をマウスイベントにマッピングすることができます</em>。 このイベントのマッピングは、<em>互換性マウスイベント</em>と呼ばれます。 作成者は <code>pointerdown</code> イベントをキャンセルすることで特定の互換性マウスイベントの生成を防ぐことができますが、次の点に注意してください。</p> + +<ul> + <li>マウスイベントは、ポインタがダウンしているときにのみ防ぐことができます。</li> + <li>ホバーしているポインタ(例えばボタンが押されていないマウス)は、それらのマウスイベントを防ぐことができません。</li> + <li><code>mouseover</code>、<code>mouseout</code>、<code>mouseenter</code>、<code>mouseleave</code> の各イベントが防止されることはありません(ポインタがダウンしている場合でも)。</li> +</ul> + +<h2 id="Best_practices" name="Best_practices">ベストプラクティス</h2> + +<p>ポインタイベントを使用する際に考慮すべき、いくつかの<em>ベストプラクティス</em>は次のとおりです。</p> + +<ul> + <li>イベントハンドラで行われる作業量を最小限に抑えます。</li> + <li>イベントハンドラを特定のターゲット要素に追加します(ドキュメント全体またはドキュメントツリーの上位のノードではなく)。</li> + <li>ターゲット要素(ノード)は、(通常は指で触れた)最大接触表面積を収容するのに十分な大きさであるべきです。 ターゲット領域が小さすぎる場合、それに触れると隣接する要素に対して他のイベントが発生する可能性があります。</li> +</ul> + +<h2 id="Implementation_and_deployment_status" name="Implementation_and_deployment_status">実装と展開の状態</h2> + +<p><a href="https://caniuse.com/#feat=pointer">ポインタイベントのブラウザーの互換性のデータ</a>(英語)は、デスクトップブラウザーとモバイルブラウザーの間のポインタイベントのサポートが、Safari を除くほぼすべてで利用可能であることを示しています。</p> + +<p><a href="https://w3c.github.io/pointerevents/">Pointer Events Level 2</a> 仕様の一部として、CSS の {{cssxref("touch-action")}} プロパティに新しい値が提案されていますが、現在これらの新しい値には実装サポートがありません。</p> + +<h2 id="Demos_and_examples" name="Demos_and_examples">デモと例</h2> + +<ul> + <li><a href="http://patrickhlauke.github.io/touch/">タッチ/ポインタのテストとデモ</a>(Patrick H. Lauke 著、英語)</li> +</ul> + +<h2 id="Community" name="Community">コミュニティ</h2> + +<ul> + <li><a href="https://github.com/w3c/pointerevents">ポインタイベントのワーキンググループ</a>(英語)</li> + <li><a href="http://lists.w3.org/Archives/Public/public-pointer-events/">メールリスト</a>(英語)</li> + <li><a href="irc://irc.w3.org:6667/">W3C の #pointerevents IRC チャンネル</a>(英語)</li> +</ul> + +<h2 id="Related_topics_and_resources" name="Related_topics_and_resources">関連トピックとリソース</h2> + +<ul> + <li><a href="http://www.w3.org/TR/touch-events/">タッチイベント標準</a>(英語)</li> +</ul> diff --git a/files/ja/web/api/pointer_events/multi-touch_interaction/index.html b/files/ja/web/api/pointer_events/multi-touch_interaction/index.html new file mode 100644 index 0000000000..dcd3193dd0 --- /dev/null +++ b/files/ja/web/api/pointer_events/multi-touch_interaction/index.html @@ -0,0 +1,273 @@ +--- +title: マルチタッチ操作 +slug: Web/API/Pointer_events/Multi-touch_interaction +tags: + - Guide + - Pointer Events + - touch +translation_of: Web/API/Pointer_events/Multi-touch_interaction +--- +<p>{{DefaultAPISidebar("Pointer Events")}}</p> + +<p>ポインタイベントは DOM 入力イベントを拡張して、マウスだけでなくペン/スタイラスやタッチ画面などのさまざまなポインティング入力デバイスをサポートします。 <em>ポインタ</em>は、特定の画面座標セットをターゲットにできるハードウェアにとらわれないデバイスです。 ポインタに単一のイベントモデルを使用すると、ウェブサイト、ウェブアプリの作成が簡単になり、ユーザーのハードウェアに関係なく優れたユーザーエクスペリエンスを提供できます。</p> + +<p>ポインタイベントはマウスイベントと多くの類似点がありますが、タッチ画面上の複数の指など、複数同時のポインタをサポートしています。 この追加機能は、より豊富なユーザー操作モデルを提供するために使用できますが、マルチタッチ操作(multi-touch interaction)の処理がさらに複雑になります。 このドキュメントは、異なるマルチタッチ操作を持つポインタイベントを使用して、コード例を介して説明します。</p> + +<p>このアプリの<em>ライブ</em>版は <a href="https://mdn.github.io/dom-examples/pointerevents/Multi-touch_interaction.html">Github</a> で利用できます。 <a href="https://github.com/mdn/dom-examples/blob/master/pointerevents/Multi-touch_interaction.html">ソースコードは Github で入手できます</a>。 プルリクエストや<a href="https://github.com/mdn/dom-examples/issues">バグレポート</a>は大歓迎です。</p> + +<h2 id="Example" name="Example">例</h2> + +<p>この例では、さまざまなマルチタッチ操作にポインタイベントのさまざまなイベントタイプ({{event("pointerdown")}}、{{event("pointermove")}}、{{event("pointerup")}}、{{event("pointercancel")}} など)を使用する方法を示します。</p> + +<h3 id="Define_touch_targets" name="Define_touch_targets">タッチターゲットの定義</h3> + +<p>アプリは {{HTMLElement("div")}} を使用して3つの異なるタッチターゲット領域を定義します。</p> + +<pre class="brush: html"><style> + div { + margin: 0em; + padding: 2em; + } + #target1 { + background: white; + border: 1px solid black; + } + #target2 { + background: white; + border: 1px solid black; + } + #target3 { + background: white; + border: 1px solid black; + } +</style> +</pre> + +<h3 id="Global_state" name="Global_state">グローバルな状態</h3> + +<p>マルチタッチ操作をサポートするには、さまざまなイベントフェーズの間にポインタのイベント状態を維持することが必要です。 このアプリは、イベント状態をキャッシュするために、ターゲット要素ごとに1つのキャッシュで、3つの配列を使用します。</p> + +<pre class="brush: js">// Log events flag +// イベントログフラグ +var logEvents = false; + +// Event caches, one per touch target +// タッチターゲットごとに1つのイベントキャッシュ +var evCache1 = new Array(); +var evCache2 = new Array(); +var evCache3 = new Array(); +</pre> + +<h3 id="Register_event_handlers" name="Register_event_handlers">イベントハンドラの登録</h3> + +<p>イベントハンドラは {{event("pointerdown")}}、{{event("pointermove")}}、{{event("pointerup")}} のポインタイベントに登録します。 {{event("pointerup")}} ハンドラは {{event("pointercancel")}}、{{event("pointerout")}}、{{event("pointerleave")}} のイベントにも使用します。 これら4つのイベントは、このアプリでは同じ意味を持っているからです。</p> + +<pre class="brush: js">function set_handlers(name) { + // Install event handlers for the given element + // 与えられた要素にイベントハンドラをインストールする + var el=document.getElementById(name); + el.onpointerdown = pointerdown_handler; + el.onpointermove = pointermove_handler; + + // Use same handler for pointer{up,cancel,out,leave} events since + // the semantics for these events - in this app - are the same. + // pointer{up,cancel,out,leave} イベントの意味は - このアプリでは - + // 同じであるため、これらのイベントに同じハンドラを使用する。 + el.onpointerup = pointerup_handler; + el.onpointercancel = pointerup_handler; + el.onpointerout = pointerup_handler; + el.onpointerleave = pointerup_handler; +} + +function init() { + set_handlers("target1"); + set_handlers("target2"); + set_handlers("target3"); +} +</pre> + +<h3 id="Pointer_down" name="Pointer_down">ポインタダウン</h3> + +<p>{{event("pointerdown")}} イベントは、ポインタ(マウス、ペン/スタイラス、タッチ画面上のタッチポイント)が<em>接触面</em>に接触したときに発生します。 このダウンイベントがマルチタッチ操作の一部である場合、イベントの状態をキャッシュしなければなりません。</p> + +<p>このアプリでは、要素の上にポインタを置いてダウンすると、その要素が持つアクティブなタッチポイントの数に応じて、要素の背景色が変わります。 色の変更に関する詳細は <code><a href="#Update_background_color">update_background</a></code> 関数を参照してください。</p> + +<pre class="brush: js">function pointerdown_handler(ev) { + // The pointerdown event signals the start of a touch interaction. + // Save this event for later processing (this could be part of a + // multi-touch interaction) and update the background color + // pointerdown イベントは、タッチ操作の開始を知らせます。 + // このイベントを後で処理するために保存し(これはマルチタッチ + // 操作の一部になる可能性があります)、背景色を更新します + push_event(ev); + if (logEvents) log("pointerDown: name = " + ev.target.id, ev); + update_background(ev); +} +</pre> + +<h3 id="Pointer_move" name="Pointer_move">ポインタ移動</h3> + +<p>{{event("pointermove")}} ハンドラは、ポインタが移動したときに呼び出されます。 別のイベントタイプが発生する前に(例えば、ユーザーがポインタを移動した場合など)複数回呼び出されることがあります。</p> + +<p>このアプリでは、ポインタの移動は、要素がこのイベントを受け取ったことを明確に視覚的に示すために、ターゲットの境界線(<code>border</code>)を破線(<code>dashed</code>)にすることで表します。</p> + +<pre class="brush: js">function pointermove_handler(ev) { + // Note: if the user makes more than one "simultaneous" touch, most browsers + // fire at least one pointermove event and some will fire several pointermoves. + // 注: ユーザーが複数の「同時」タッチを行うと、ほとんどのブラウザーは少なくとも1つの + // pointermove イベントを発生させ、一部はいくつかの pointermove イベントを発生させます。 + // + // This function sets the target element's border to "dashed" to visually + // indicate the target received a move event. + // この関数は、ターゲットが移動イベントを受け取ったことを視覚的に示すために、 + // ターゲット要素の border を "dashed" に設定します。 + if (logEvents) log("pointerMove", ev); + update_background(ev); + ev.target.style.border = "dashed"; +} +</pre> + +<h3 id="Pointer_up" name="Pointer_up">ポインタアップ</h3> + +<p>{{event("pointerup")}} イベントは、ポインタが<em>接触面</em>から上がると発生します。 これが発生すると、そのイベントは関連付けられているイベントキャッシュから削除されます。</p> + +<p>このアプリでは、このハンドラは {{event("pointercancel")}}、{{event("pointerleave")}}、{{event("pointerout")}} のイベントにも使用します。</p> + +<pre class="brush: js">function pointerup_handler(ev) { + if (logEvents) log(ev.type, ev); + // Remove this touch point from the cache and reset the target's + // background and border + // このタッチポイントをキャッシュから削除し、 + // ターゲットの背景色と境界線をリセットします + remove_event(ev); + update_background(ev); + ev.target.style.border = "1px solid black"; +} +</pre> + +<h3 id="Application_UI" name="Application_UI">アプリの UI</h3> + +<p>アプリは、タッチ領域に {{HTMLElement("div")}} 要素を使用し、ログ記録を有効にするボタンとログを消去するためのボタンを提供します。</p> + +<p class="note">ブラウザーのデフォルトのタッチの振る舞いが、このアプリのポインタ処理をオーバーライドしないようにするために、{{cssxref("touch-action")}} プロパティを {{HTMLElement("body")}} 要素に適用しています。</p> + +<pre class="brush: html"><body onload="init();" style="touch-action:none"> + <div id="target1"> Tap, Hold or Swipe me 1</div> + <div id="target2"> Tap, Hold or Swipe me 2</div> + <div id="target3"> Tap, Hold or Swipe me 3</div> + + <!-- UI for logging/debugging --> + <button id="log" onclick="enableLog(event);">Start/Stop event logging</button> + <button id="clearlog" onclick="clearLog(event);">Clear the log</button> + <p></p> + <output></output> +</body> +</pre> + +<h3 id="Miscellaneous_functions" name="Miscellaneous_functions">その他の関数</h3> + +<p>これらの関数はアプリをサポートしますが、イベントの流れに直接は関係しません。</p> + +<h4 id="Cache_management" name="Cache_management">キャッシュ管理</h4> + +<p>これらの関数は、グローバルイベントキャッシュの <code>evCache1</code>、<code>evCache2</code>、<code>evCache3</code> を管理します。</p> + +<pre class="brush: js">function get_cache(ev) { + // Return the cache for this event's target element + // このイベントのターゲット要素のキャッシュを返す + switch(ev.target.id) { + case "target1": return evCache1; + case "target2": return evCache2; + case "target3": return evCache3; + default: log("Error with cache handling",ev); + } +} + +function push_event(ev) { + // Save this event in the target's cache + // このイベントをターゲットのキャッシュに保存する + var cache = get_cache(ev); + cache.push(ev); +} + +function remove_event(ev) { + // Remove this event from the target's cache + // このイベントをターゲットのキャッシュから削除する + var cache = get_cache(ev); + for (var i = 0; i < cache.length; i++) { + if (cache[i].pointerId == ev.pointerId) { + cache.splice(i, 1); + break; + } + } +} +</pre> + +<h4 id="Update_background_color" name="Update_background_color">背景色の更新</h4> + +<p>タッチ領域の背景色は次のように変わります。 アクティブなタッチがない場合は白(<code>white</code>)です。 1つのアクティブなタッチは黄色(<code>yellow</code>)です。 2つ同時のタッチはピンク(<code>pink</code>)で、3つ以上同時のタッチは水色(<code>lightblue</code>)です。</p> + +<pre class="brush: js">function update_background(ev) { + // Change background color based on the number of simultaneous touches/pointers + // currently down: + // 現在ダウンしている同時タッチ/ポインタの数に基づいて + // 次のように背景色を変更します + // white - target element has no touch points i.e. no pointers down + // white - ターゲット要素にタッチポイントがない。 つまり、ポインタのダウンがない。 + // yellow - one pointer down + // yellow - 1つのポインタのダウン + // pink - two pointers down + // pink - 2つのポインタのダウン + // lightblue - three or more pointers down + // lightblue - 3つ以上のポインタのダウン + var evCache = get_cache(ev); + switch (evCache.length) { + case 0: + // Target element has no touch points + // ターゲット要素にタッチポイントがない + ev.target.style.background = "white"; + break; + case 1: + // Single touch point + // 単独のタッチポイント + ev.target.style.background = "yellow"; + break; + case 2: + // Two simultaneous touch points + // 2つ同時のタッチポイント + ev.target.style.background = "pink"; + break; + default: + // Three or more simultaneous touches + // 3つ以上同時のタッチ + ev.target.style.background = "lightblue"; + } +} +</pre> + +<h4 id="Event_logging" name="Event_logging">イベントログ</h4> + +<p>これらの関数は、アプリのウィンドウへのイベント活動の送信に使用されます(デバッグとイベントの流れに関する学習をサポートするため)。</p> + +<pre class="brush: js">// Log events flag +// イベントログフラグ +var logEvents = false; + +function enableLog(ev) { + logEvents = logEvents ? false : true; +} + +function log(name, ev) { + var o = document.getElementsByTagName('output')[0]; + var s = name + ": pointerID = " + ev.pointerId + + " ; pointerType = " + ev.pointerType + + " ; isPrimary = " + ev.isPrimary; + o.innerHTML += s + " +"; +} + +function clearLog(event) { + var o = document.getElementsByTagName('output')[0]; + o.innerHTML = ""; +} +</pre> diff --git a/files/ja/web/api/pointer_events/pinch_zoom_gestures/index.html b/files/ja/web/api/pointer_events/pinch_zoom_gestures/index.html new file mode 100644 index 0000000000..6b24e21ee2 --- /dev/null +++ b/files/ja/web/api/pointer_events/pinch_zoom_gestures/index.html @@ -0,0 +1,219 @@ +--- +title: ピンチズームのジェスチャー +slug: Web/API/Pointer_events/Pinch_zoom_gestures +tags: + - Guide + - PointerEvent + - touch +translation_of: Web/API/Pointer_events/Pinch_zoom_gestures +--- +<div>{{DefaultAPISidebar("Pointer Events")}}</div> + +<p><span class="seoSummary">アプリに<em>ジェスチャー</em>を追加すると、使い勝手が大幅に向上します。</span>単純なシングルタッチの<em>スワイプ</em>ジェスチャーから、タッチポイント(別名<em>ポインター</em>)が異なる方向に移動する、より複雑なマルチタッチの<em>ツイスト</em>ジェスチャーまで、さまざまな種類のジェスチャーがあります。</p> + +<p>この例では、<em>ピンチ/ズーム</em>ジェスチャーを検出する方法を示します。 これは、{{domxref("Pointer_events","ポインターイベント")}}を使用して、ユーザーが2つのポインターを互いに近づけるか遠ざけるかを検出します。</p> + +<p>このアプリの<em>ライブ</em>版は <a href="https://mdn.github.io/dom-examples/pointerevents/Pinch_zoom_gestures.html">Github</a> で利用できます。 <a href="https://github.com/mdn/dom-examples/blob/master/pointerevents/Pinch_zoom_gestures.html">ソースコードは GitHub で入手できます</a>。 プルリクエストや<a href="https://github.com/mdn/dom-examples/issues">バグレポート</a>は大歓迎です。</p> + +<h2 id="Example" name="Example">例</h2> + +<p>この例では、{{domxref("Pointer_events","ポインターイベント")}}を使用して、指、マウス、ペンなど、あらゆる種類の2つのポインティングデバイスを同時に検出します。 2つのポインターを互いに近づけるピンチイン(ズームアウト、縮小)ジェスチャーでは、ターゲット要素の背景色が水色(<code>lightblue</code>)に変わります。 2つのポインターを互いに遠ざけるピンチアウト(ズームイン、拡大)ジェスチャーでは、ターゲット要素の背景色がピンク(<code>pink</code>)に変わります。</p> + +<h3 id="Define_touch_target" name="Define_touch_target">タッチターゲットの定義</h3> + +<p>アプリは {{HTMLElement("div")}} を使用してポインターのターゲット領域を定義します。</p> + +<pre class="brush: html"><style> + div { + margin: 0em; + padding: 2em; + } + #target { + background: white; + border: 1px solid black; + } +</style> +</pre> + +<h3 id="Global_state" name="Global_state">グローバルな状態</h3> + +<p>2ポインターのジェスチャーをサポートするには、さまざまなイベントフェーズでポインターのイベント状態を保存する必要があります。このアプリは、イベント状態をキャッシュするために2つのグローバル変数を使用します。</p> + +<pre class="brush: js">// イベント状態をキャッシュするグローバル変数 +var evCache = new Array(); +var prevDiff = -1; +</pre> + +<h3 id="Register_event_handlers" name="Register_event_handlers">イベントハンドラーの登録</h3> + +<p>イベントハンドラーは {{event("pointerdown")}}, {{event("pointermove")}}, {{event("pointerup")}} のポインターイベントに登録します。 {{event("pointerup")}} ハンドラーは {{event("pointercancel")}}, {{event("pointerout")}}, {{event("pointerleave")}} のイベントにも使用します。 これら4つのイベントは、このアプリでは同じ意味を持っているからです。</p> + +<pre class="brush: js">function init() { + // ポインターターゲット用のイベントハンドラーをインストールする + var el=document.getElementById("target"); + el.onpointerdown = pointerdown_handler; + el.onpointermove = pointermove_handler; + + // pointer{up,cancel,out,leave} イベントの意味は - このアプリでは - + // 同じであるため、これらのイベントに同じハンドラーを使用する。 + el.onpointerup = pointerup_handler; + el.onpointercancel = pointerup_handler; + el.onpointerout = pointerup_handler; + el.onpointerleave = pointerup_handler; +} +</pre> + +<h3 id="Pointer_down" name="Pointer_down">ポインターダウン</h3> + +<p>{{event("pointerdown")}} イベントは、ポインター (マウス、ペン/スタイラス、タッチ画面上のタッチポイント) が<em>接触面</em>に接触したときに発生します。 このアプリでは、このダウンイベントが2ポインターのピンチ/ズームジェスチャーの一部である場合に備えて、イベントの状態をキャッシュする必要があります。</p> + +<pre class="brush: js">function pointerdown_handler(ev) { + // pointerdown イベントは、タッチ操作の開始を知らせます。 + // このイベントは2本指ジェスチャーをサポートするためにキャッシュされます + evCache.push(ev); + log("pointerDown", ev); +} +</pre> + +<h3 id="Pointer_move" name="Pointer_move">ポインター移動</h3> + +<p>{{event("pointermove")}} イベントハンドラーは、ユーザーが2ポインターのピンチ/ズームジェスチャーを呼び出しているかどうかを検出します。 2つのポインターが下がっていてポインター間の距離が増加している場合(ピンチアウトまたはズームイン)、要素の背景色がピンク(<code>pink</code>)に変わり、ポインター間の距離が減少している場合(ピンチインまたはズームアウト) 背景色が水色(<code>lightblue</code>)に変わります。 より洗練されたアプリでは、ピンチインまたはピンチアウトの決定を使用してアプリ固有の意味論を適用できます。</p> + +<p>このイベントが処理されると、ターゲットの境界線が破線(<code>dashed</code>)に設定され、要素が移動イベントを受け取ったことを明確に視覚的に示します。</p> + +<pre class="brush: js">function pointermove_handler(ev) { + // この関数は、2ポインターの水平ピンチ/ズームジェスチャーを実装しています。 + // + // 2つのポインター間の距離が広がると(ズームイン)、 + // ターゲット要素の背景色は "pink" に変わり、 + // 縮まると(ズームアウト)、色は "lightblue" に変わります。 + // + // この関数は、ポインターのターゲットが移動イベントを受け取ったことを + // 視覚的に示すために、ターゲット要素の境界線を "dashed" に設定します。 + log("pointerMove", ev); + ev.target.style.border = "dashed"; + + // キャッシュ内でこのイベントを見つけ、このイベントの記録を更新します + for (var i = 0; i < evCache.length; i++) { + if (ev.pointerId == evCache[i].pointerId) { + evCache[i] = ev; + break; + } + } + + // ポインターが2つダウンしている場合は、ピンチジェスチャーを確認します + if (evCache.length == 2) { + // 2つのポインター間の距離を計算 + var curDiff = Math.abs(evCache[0].clientX - evCache[1].clientX); + + if (prevDiff > 0) { + if (curDiff > prevDiff) { + // 2つのポインター間の距離が増えた + log("Pinch moving OUT -> Zoom in", ev); + ev.target.style.background = "pink"; + } + if (curDiff < prevDiff) { + // 2つのポインター間の距離が減った + log("Pinch moving IN -> Zoom out",ev); + ev.target.style.background = "lightblue"; + } + } + + // 次の移動イベントのために距離をキャッシュします + prevDiff = curDiff; + } +} +</pre> + +<h3 id="Pointer_up" name="Pointer_up">ポインターアップ</h3> + +<p>{{event("pointerup")}} イベントは、ポインターが<em>接触面</em>から上がると発生します。 これが発生すると、イベントはイベントキャッシュから削除され、ターゲット要素の背景色と境界線は元の値に戻ります。</p> + +<p>このアプリでは、このハンドラーは {{event("pointercancel")}}, {{event("pointerleave")}}, {{event("pointerout")}} のイベントにも使用します。</p> + +<pre class="brush: js">function pointerup_handler(ev) { + log(ev.type, ev); + // このポインターをキャッシュから削除し、 + // ターゲットの背景色と境界線をリセットします + remove_event(ev); + ev.target.style.background = "white"; + ev.target.style.border = "1px solid black"; + + // ポインター数が2未満の場合は、以前の距離をリセットします + if (evCache.length < 2) { + prevDiff = -1; + } +}</pre> + +<h3 id="Application_UI" name="Application_UI">アプリの UI</h3> + +<p>アプリは、タッチ領域に {{HTMLElement("div")}} 要素を使用し、ログ記録を有効にするボタンとログを消去するためのボタンを提供します。</p> + +<p class="note">ブラウザーのデフォルトのタッチの振る舞いが、このアプリのポインター処理をオーバーライドしないようにするために、{{cssxref("touch-action")}} プロパティを {{HTMLElement("body")}} 要素に適用しています。</p> + +<pre class="brush: html"><body onload="init();" style="touch-action:none"> + <div id="target">2点に触れたままにして、ピンチインまたはピンチアウトしてください。<br/> + ピンチが開いている場合(ズームイン)は背景色がピンクに変わり、 + ピンチが閉じている場合(ズームアウト)は背景色が水色に変わります。 + <!-- UI for logging/debugging --> + <button id="log" onclick="enableLog(event);">Start/Stop event logging</button> + <button id="clearlog" onclick="clearLog(event);">Clear the log</button> + <p></p> + <output></output> +</body> +</pre> + +<h3 id="Miscellaneous_functions" name="Miscellaneous_functions">その他の関数</h3> + +<p>これらの関数はアプリをサポートしますが、イベントの流れに直接は関係しません。</p> + +<h4 id="Cache_management" name="Cache_management">キャッシュ管理</h4> + +<p>この関数はグローバルイベントキャッシュの <code>evCache</code> の管理に役立ちます。</p> + +<pre class="brush: js">function remove_event(ev) { + // このイベントをターゲットのキャッシュから削除する + for (var i = 0; i < evCache.length; i++) { + if (evCache[i].pointerId == ev.pointerId) { + evCache.splice(i, 1); + break; + } + } +} +</pre> + +<h4 id="Event_logging" name="Event_logging">イベントログ</h4> + +<p>これらの関数は、イベント活動をアプリのウィンドウに送信するために使用します(デバッグとイベントの流れに関する学習をサポートするため)。</p> + +<pre class="brush: js">// イベントをログ出力するフラグ +var logEvents = false; + +// ログ/デバッグ関数 +function enableLog(ev) { + logEvents = logEvents ? false : true; +} + +function log(prefix, ev) { + if (!logEvents) return; + var o = document.getElementsByTagName('output')[0]; + var s = prefix + ": pointerID = " + ev.pointerId + + " ; pointerType = " + ev.pointerType + + " ; isPrimary = " + ev.isPrimary; + o.innerHTML += s + " +"; +} + +function clearLog(event) { + var o = document.getElementsByTagName('output')[0]; + o.innerHTML = ""; +} +</pre> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="https://hacks.mozilla.org/2015/08/pointer-events-now-in-firefox-nightly/">Firefox Nightly にポインターイベントが追加されました</a>。 Mozilla Hacks より、Matt Brubeck とJason Weathersby 著、2015年8月4日(英語)</li> + <li><a href="https://github.com/jquery/PEP">jQuery によるポインターイベントのポリフィル</a>(英語)</li> + <li><a href="http://www.google.com/design/spec/patterns/gestures.html">ジェスチャー</a>。 Google のデザインパターン(英語)</li> +</ul> diff --git a/files/ja/web/api/pointer_events/using_pointer_events/index.html b/files/ja/web/api/pointer_events/using_pointer_events/index.html new file mode 100644 index 0000000000..e45f9e7efa --- /dev/null +++ b/files/ja/web/api/pointer_events/using_pointer_events/index.html @@ -0,0 +1,261 @@ +--- +title: Pointer Events の使用 +slug: Web/API/Pointer_events/Using_Pointer_Events +tags: + - Guide + - Input + - Pointer Events + - PointerEvent + - events + - touch +translation_of: Web/API/Pointer_events/Using_Pointer_Events +--- +<p>{{DefaultAPISidebar("Pointer Events")}}</p> + +<p><span class="seoSummary">このガイドでは、<a href="/ja/docs/Web/API/Pointer_events">ポインタイベント</a>と HTML の {{HTMLElement("canvas")}} 要素を使用してマルチタッチ対応の描画アプリを作成する方法について説明します。</span> この例は、{{domxref("PointerEvent","ポインタイベント", "", 1)}}の入力イベントモデルを使用する点を除いて、<a href="/ja/docs/Web/API/Touch_events">Touch events の概要</a>の例に基づいています。 もう1つの違いは、ポインタイベントはポインタデバイスに依存しないため、アプリは同じコードを使用してマウス、ペン、または指先からの座標ベースの入力を受け入れることです。</p> + +<p class="note">このアプリは、ポインタイベントをサポートしているブラウザーでのみ動作します。</p> + +<p>このアプリのライブ版は <a href="https://mdn.github.io/dom-examples/pointerevents/Using_Pointer_Events.html">GitHub</a> で利用できます。 <a href="https://github.com/mdn/dom-examples/blob/master/pointerevents/Using_Pointer_Events.html">ソースコードは Github で入手でき</a>、プルリクエストやバグレポートは大歓迎です。</p> + +<h2 id="Definitions" name="Definitions">定義</h2> + +<dl> + <dt>表面(Surface)</dt> + <dd>タッチを感知できる表面。 これは、トラックパッド、タッチ画面、あるいは物理的な画面とユーザーの机の表面(またはマウスパッド)の仮想的なマッピングかもしれません。</dd> +</dl> + +<dl> + <dt>タッチポイント(Touch point)</dt> + <dd>表面との接点。 これは、指(または肘、耳、鼻など何でも、しかし通常は指)、スタイラス、マウス、または表面上の単一の点を指定するための他の任意の方法かもしれません。</dd> +</dl> + +<h2 id="Example" name="Example">例</h2> + +<div class="note">以下のテキストでは、表面との接触を説明するときに「指」という用語を使用していますが、もちろんスタイラス、マウス、その他の場所を指す方法でもかまいません。</div> + +<h3 id="Create_a_canvas" name="Create_a_canvas">キャンバスの作成</h3> + +<p>ブラウザーがデフォルトのタッチの振る舞いをアプリに適用しないようにするには、{{cssxref("touch-action")}} プロパティを <code>none</code> に設定します。</p> + +<pre class="brush: html"><canvas id="canvas" width="600" height="600" style="border:solid black 1px; touch-action:none"> + Your browser does not support canvas element. + 訳: お使いのブラウザーはキャンバス要素をサポートしていません。 +</canvas> +<br> +<button onclick="startup()">Initialize</button> +<br> +Log: <pre id="log" style="border: 1px solid #ccc;"></pre> +</pre> + +<h3 id="Setting_up_the_event_handlers" name="Setting_up_the_event_handlers">イベントハンドラの設定</h3> + +<p>ページが読み込まれると、{{HTMLElement("body")}} 要素の <code>onload</code> 属性によって以下に示す <code>startup()</code> 関数が呼び出されます(ただし、MDN ライブサンプルシステムの制限により、この例ではボタンを使用してトリガーします)。</p> + +<pre class="brush: js">function startup() { + var el = document.getElementsByTagName("canvas")[0]; + el.addEventListener("pointerdown", handleStart, false); + el.addEventListener("pointerup", handleEnd, false); + el.addEventListener("pointercancel", handleCancel, false); + el.addEventListener("pointermove", handleMove, false); + log("initialized."); +} +</pre> + +<p>これは単に {{HTMLElement("canvas")}} 要素のすべてのイベントリスナーを設定するので、タッチイベントが発生したときに処理できます。</p> + +<h4 id="Tracking_new_touches" name="Tracking_new_touches">新しいタッチの追跡</h4> + +<p>進行中のタッチを追跡します。</p> + +<pre class="brush: js">var ongoingTouches = new Array(); +</pre> + +<p>{{event("pointerdown")}} イベントが発生すると、表面上で新しいタッチが発生したことを示し、次の <code>handleStart()</code> 関数が呼び出されます。</p> + +<pre class="brush: js">function handleStart(evt) { + log("pointerdown."); + var el = document.getElementsByTagName("canvas")[0]; + var ctx = el.getContext("2d"); + + log("pointerdown: id = " + evt.pointerId); + ongoingTouches.push(copyTouch(evt)); + var color = colorForTouch(evt); + ctx.beginPath(); + ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 * Math.PI, false); // a circle at the start 訳注: エラーで中断するので、この行を削除すべき + ctx.arc(evt.clientX, evt.clientY, 4, 0, 2 * Math.PI, false); // a circle at the start + ctx.fillStyle = color; + ctx.fill(); +} +</pre> + +<p>イベントの処理の一部を後で処理するために <code>ongoingTouches</code> に格納した後、開始点を小さな円として描画します。 4ピクセル幅の線を使用しているので、4ピクセルの半径の円が見栄えよく表示されます。</p> + +<h4 id="Drawing_as_the_pointers_move" name="Drawing_as_the_pointers_move">ポインタの動きに合わせて描画</h4> + +<p>1つ以上のポインタが移動するたびに、{{event("pointermove")}} イベントが配信され、その結果、次の <code>handleMove()</code> 関数が呼び出されます。 この例におけるその役割は、キャッシュされたタッチ情報を更新し、各タッチの前の位置から現在の位置まで線を引くことです。</p> + +<pre class="brush: js">function handleMove(evt) { + var el = document.getElementsByTagName("canvas")[0]; + var ctx = el.getContext("2d"); + var color = colorForTouch(evt); + var idx = ongoingTouchIndexById(evt.pointerId); + + log("continuing touch: idx = " + idx); + if (idx >= 0) { + ctx.beginPath(); + log("ctx.moveTo(" + ongoingTouches[idx].pageX + ", " + ongoingTouches[idx].pageY + ");"); + ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY); + log("ctx.lineTo(" + evt.clientX + ", " + evt.clientY + ");"); + ctx.lineTo(evt.clientX, evt.clientY); + ctx.lineWidth = 4; + ctx.strokeStyle = color; + ctx.stroke(); + + ongoingTouches.splice(idx, 1, copyTouch(evt)); // swap in the new touch record + log("."); + } else { + log("can't figure out which touch to continue: idx = " + idx); + } +} +</pre> + +<p>この関数はキャッシュされたタッチ情報配列で各タッチに関する以前の情報を探して、描画する各タッチの新しい線分の開始点を決定します。 これは各タッチの {{domxref("PointerEvent.pointerId")}} プロパティを見ることによって行われます。 このプロパティは、各ポインタイベントに対して一意の整数であり、各指が表面と接触している間、各イベントに対して一貫性を保ちます。</p> + +<p>これにより、各タッチの前の位置の座標を取得し、適切なコンテキストメソッドを使用して2つの位置を結ぶ線分を描画できます。</p> + +<p>線を描画した後、<a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice"><code>Array.splice()</code></a> を呼び出して、<code>ongoingTouches</code> 配列内のタッチポイントに関する以前の情報を現在の情報に置き換えます。</p> + +<h4 id="Handling_the_end_of_a_touch" name="Handling_the_end_of_a_touch">タッチの終わりの処理</h4> + +<p>ユーザーが表面から指を離すと、{{event("pointerup")}} イベントが送信されます。 次の <code>handleEnd()</code> 関数を呼び出すことによってこのイベントを処理します。 その仕事は終わったタッチのための最後の線分を引き、進行中のタッチリストからタッチポイントを取り除くことです。</p> + +<pre class="brush: js">function handleEnd(evt) { + log("pointerup"); + var el = document.getElementsByTagName("canvas")[0]; + var ctx = el.getContext("2d"); + var color = colorForTouch(evt); + var idx = ongoingTouchIndexById(evt.pointerId); + + if (idx >= 0) { + ctx.lineWidth = 4; + ctx.fillStyle = color; + ctx.beginPath(); + ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY); + ctx.lineTo(evt.clientX, evt.clientY); + ctx.fillRect(evt.clientX - 4, evt.clientY - 4, 8, 8); // and a square at the end + ongoingTouches.splice(idx, 1); // remove it; we're done + } else { + log("can't figure out which touch to end"); + } +} +</pre> + +<p>これは前の関数と非常によく似ています。 唯一の大きな違いは、終わりを示すために小さな正方形を描くことと、<a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice"><code>Array.splice()</code></a> を呼び出すときに、更新された情報を追加せずに、進行中のタッチリストから古いエントリを削除することです。 その結果、そのタッチポイントの追跡をやめます。</p> + +<h4 id="Handling_canceled_touches" name="Handling_canceled_touches">キャンセルされたタッチの処理</h4> + +<p>ユーザーの指がブラウザーの UI にぶつかったり、あるいはタッチをキャンセルする必要がある場合は、{{event("pointercancel")}} イベントが送信され、次の <code>handleCancel()</code> 関数を呼び出します。</p> + +<pre class="brush: js">function handleCancel(evt) { + log("pointercancel: id = " + evt.pointerId); + var idx = ongoingTouchIndexById(evt.pointerId); + ongoingTouches.splice(idx, 1); // remove it; we're done +} +</pre> + +<p>アイデアはすぐにタッチを中止することなので、最後の線分を描かずに進行中のタッチリストから削除します。</p> + +<h3 id="Convenience_functions" name="Convenience_functions">便利な関数</h3> + +<p>この例では、コードの残りの部分をより明確にするために簡単に説明する必要がある、いくつかの便利な関数を使用しています。</p> + +<h4 id="Selecting_a_color_for_each_touch" name="Selecting_a_color_for_each_touch">タッチごとの色の選択</h4> + +<p>各タッチの描画を異なるように見せるために、<code>colorForTouch()</code> 関数を使用して、タッチの一意の識別子に基づいて色を選びます。 この識別子は不透明な数字ですが、少なくとも現在アクティブなタッチ間で異なることを頼れます。</p> + +<pre class="brush: js">function colorForTouch(touch) { + var r = touch.pointerId % 16; + var g = Math.floor(touch.pointerId / 3) % 16; + var b = Math.floor(touch.pointerId / 7) % 16; + r = r.toString(16); // make it a hex digit + g = g.toString(16); // make it a hex digit + b = b.toString(16); // make it a hex digit + var color = "#" + r + g + b; + log("color for touch with identifier " + touch.pointerId + " = " + color); + return color; +} +</pre> + +<p>この関数の結果は、描画色を設定するために {{HTMLElement("canvas")}} の関数を呼び出すときに使用できる文字列です。 例えば、{{domxref("PointerEvent.pointerId")}} の値が <code>10</code> の場合、結果の文字列は <code>"#aaa"</code> です。</p> + +<h4 id="Copying_a_touch_object" name="Copying_a_touch_object">タッチオブジェクトのコピー</h4> + +<p>ブラウザーによっては、イベント間でタッチオブジェクトを再利用することがあるので、オブジェクト全体を参照するのではなく、気になる部分をコピーするのが最善です。</p> + +<pre class="brush: js">function copyTouch(touch) { + return { identifier: touch.pointerId, pageX: touch.clientX, pageY: touch.clientY }; +} +</pre> + +<h4 id="Finding_an_ongoing_touch" name="Finding_an_ongoing_touch">進行中のタッチの検索</h4> + +<p>次の <code>ongoingTouchIndexById()</code> 関数は、<code>ongoingTouches</code> 配列をスキャンして、指定された識別子と一致するタッチを見つけ、そのタッチの配列におけるインデックスを返します。</p> + +<pre class="brush: js">function ongoingTouchIndexById(idToFind) { + for (var i = 0; i < ongoingTouches.length; i++) { + var id = ongoingTouches[i].identifier; + + if (id == idToFind) { + return i; + } + } + return -1; // not found +} +</pre> + +<h4 id="Showing_what's_going_on" name="Showing_what's_going_on">何が起こっているのかを示す</h4> + +<pre class="brush: js">function log(msg) { + var p = document.getElementById('log'); + p.innerHTML = msg + "\n" + p.innerHTML; +}</pre> + +<h2 id="Specifications" name="Specifications">仕様</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">仕様</th> + <th scope="col">状態</th> + <th scope="col">コメント</th> + </tr> + <tr> + <td>{{SpecName('Pointer Events 2','#pointerevent-interface', 'PointerEvent')}}</td> + <td>{{Spec2('Pointer Events 2')}}</td> + <td>不安定版</td> + </tr> + <tr> + <td>{{SpecName('Pointer Events', '#pointerevent-interface', 'PointerEvent')}}</td> + <td>{{Spec2('Pointer Events')}}</td> + <td>初期定義</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2> + +<h3 id="PointerEvent_interface" name="PointerEvent_interface"><code>PointerEvent</code> インターフェイス</h3> + +<div> + + +<p>{{Compat("api.PointerEvent", 0)}}</p> +</div> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="/ja/docs/Web/API/Pointer_events">Pointer events</a></li> + <li><a href="/ja/docs/Web/API/Touch_events">Touch events</a></li> +</ul> |
