Pointer Events再入門 第1回 Pointer Eventsの基本的な使い方

Pointer Eventsは、Mouse EventsとTouch Eventsを統一的に扱うことができる仕様です。この記事では、Pointer Eventsの基本的な使い方について解説します。

発行

著者 國仲 義則 フロントエンド・エンジニア
Pointer Events再入門 シリーズの記事一覧

はじめに

マウスやタッチの状況といったポインティングデバイスの動きを検知するためのイベントは、Mouse EventsやTouch Eventsが古くからあります。これらのイベントは、ポインティングデバイスの種類、つまり、マウスなのか指なのかによって異なるイベントを発生させるため、開発者はそれぞれのイベントに対して処理を書く必要がありました。

しかし現在ではPointer Eventsという仕様が登場し、これによってMouse EventsとTouch Eventsを統合することができるようになりました。この記事では、Pointer Eventsの基本的な使い方について解説します。

Mouse EventsとTouch Eventsについて

CodeGridでは、過去の記事でMouse EventsとTouch Eventsについて、それぞれのイベントに対して処理を書く方法が解説されています。Mouse EventsとTouch Eventsについて詳しく知りたい場合は、このシリーズが参考になるでしょう。

このシリーズの後編で「現在策定中」(執筆当時)として、Pointer Eventsを紹介しています。そのPointer Eventsを詳しく取り上げるのが本記事となります。

Pointer Eventsとは

Pointer Eventsは、マウス、タッチ、ペンなどのポインティングデバイスのイベントを統一的に扱うための仕様です。

まずPointer Eventsがもつイベントと、それに対応するMouse EventsとTouch Eventsを以下に示します。

Pointer Events Mouse Events Touch Events
pointerdown mousedown touchstart
pointermove mousemove touchmove
pointerup mouseup touchend
pointercancel - touchcancel
pointerenter mouseenter -
pointerleave mouseleave -
pointerover mouseover -
pointerout mouseout -

このように、Pointer EventsではMouse EventsとTouch Eventsを合わせて扱えます。

Pointer Eventsの使い方

ここからは、Pointer Eventsの基本的な使い方を見てみます。

基本的にはMouse EventsやTouch Eventsでやっていたことを、Pointer Eventsのイベントに置き換えるだけです。

ターゲット領域内のポインティングデバイスの座標を取得・表示するデモを作成してみましょう。まずHTMLでは、対象をappというidがついたdiv要素に設定します。

ポインティングデバイスの座標を取得・表示する基本デモのHTML

<div id="app" class="stage"></div>
<ul>
  <li>pointerdown: <span id="pointerdown">0, 0</span></li>
  <li>pointermove: <span id="pointermove">0, 0</span></li>
  <li>pointerup: <span id="pointerup">0, 0</span></li>
</ul>
<p>
  <button id="reset">リセット</button>
</p>

HTMLでは、対象となるdiv#app.stageと、pointerdownpointermovepointerupのイベントが発生した際に、その座標を表示するためのspan要素、座標表示をリセットするbutton要素を用意しました。

次にCSSを設定します。

ポインティングデバイスの座標を取得・表示する基本デモのCSS

body {
  margin: 0;
  background-color: white;
}

.stage {
  border: 1px solid silver;
  margin: 0.5em;
  height: 50vh;
  background-color: ivory;
  touch-action: none; /* <= 重要 */
}

ul, p {
  padding-inline-start: 3em;
}

CSSは基本的に見た目だけの設定を行っていますが、.stageに設定したtouch-action: none;が重要になります。

touch-actionプロパティは、タッチ操作に対してどのような挙動をするかを指定するプロパティです。ここではnoneを指定し、ブラウザのデフォルトのタッチ動作(たとえば、指ドラッグによる画面スクロールやピンチイン拡大など)をすべて無効にしています。

用途に応じたふるまいを設定したい場合は、それぞれふさわしい値を指定してください。

touch-actionプロパティ

次は、JavaScriptの処理を見ていきます。

ポインティングデバイスの座標を取得・表示する基本デモのJavaScript

const app = document.getElementById("app");
const pointerdown = document.getElementById("pointerdown");
const pointermove = document.getElementById("pointermove");
const pointerup = document.getElementById("pointerup");
const reset = document.getElementById("reset");

function toFixedValue(value) {
  return value.toFixed(5);
}

app.addEventListener("pointerdown", (event) => {
  pointerdown.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
});

app.addEventListener("pointermove", (event) => {
  pointermove.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
});

app.addEventListener("pointerup", (event) => {
  pointerup.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
});

reset.addEventListener("click", () => {
  pointerdown.textContent = "0, 0";
  pointermove.textContent = "0, 0";
  pointerup.textContent = "0, 0";
});

JavaScriptはとてもシンプルです。

pointerdownpointermovepointerupのイベントが発生した際に、それぞれの座標を取得して表示しています。また、リセットボタンをクリックした際には、座標表示をリセットしています。

これでポインターの座標を取得して表示するデモが完成しました。マウスで操作しても、タッチで操作しても、座標を取得できる様子がわかります。

JavaScriptの内容は、Mouse EventsやTouch Eventsでやっていたことと、ほとんど変わりませんが、1つにまとめて処理できるようになったという部分が違います。

ポインティングデバイスを判別する

Pointer Eventsでは、pointerTypeプロパティを使って、ポインティングデバイスの種類を判別できます。

先ほどのデモに、ポインティングデバイスの種類を表示する機能を追加してみましょう。

ポインティングデバイスの座標と種類を取得して表示するデモのHTML

<div id="app" class="stage"></div>
<ul>
  <!-- ... -->
  <li>pointer type: <span id="pointerType" style="...">unknown</span></li>
</ul>
<!-- ... -->

座標表示リストの最後に、ポインティングデバイスの種類を表示する部分を作りました。初期状態ではunknownとしています。

ハイライトのために少しCSSを指定していますが、動作とは無関係なのでCSSの中身は省略します。

JavaScriptの処理を見てみましょう。

ポインティングデバイスの座標と種類を取得して表示するデモのJavaScript

// ...各変数の定義
const pointerType = document.getElementById("pointerType");

// ...

app.addEventListener("pointerdown", (event) => {
  pointerdown.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
  pointerType.textContent = event.pointerType;
});

app.addEventListener("pointermove", (event) => {
  pointermove.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
  pointerType.textContent = event.pointerType;
});

app.addEventListener("pointerup", (event) => {
  pointerup.textContent = `${toFixedValue(event.clientX)}, ${toFixedValue(event.clientY)}`;
  pointerType.textContent = event.pointerType;
});

reset.addEventListener("click", () => {
  // ...
  pointerType.textContent = "unknown";
});

各イベントハンドラ内で、event.pointerTypeを取得して、#pointerTypeに値を追加するようにしました。

イベントが発生した際に、ポインティングデバイスの種類を取得し、「pointer type」に表示するようにしました。マウスでは「mouse」、タッチデバイスでは「touch」が表示されているはずです。

実践では、デバイスによって処理を変えたりする場合に使われます。

以前はMouse EventsとTouch Eventsでイベントリスナーを書く必要がありましたが、Pointer Eventsではイベントリスナーは1つで、要件に応じてイベントハンドラ内で処理を分岐することになります。

ここまでのまとめ

Pointer Eventsでポインティングデバイスの座標を取得・表示する方法を見てみました。

次回は、マウスとタッチで挙動が異なる場合に、タッチ特有のスワイプ動作をマウスでも同じようにするなど、マウスとタッチでは挙動が異なる場合でも、Pointer Eventsで統一的に処理する方法を見ていきます。また、タッチ利用時に、主要なポインターかどうかを判定する方法についても解説します。