このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
ポインターロック API
ポインターロック API (以前はマウスロック API と呼ばれていました)は、ビューポート内のマウスカーソルの絶対位置だけでなく、時間の経過に伴うマウスの動き(すなわち、デルタ)に基づく入力方法を提供します。これにより、マウスの生の移動量を知ることができ、マウスイベントのターゲットをひとつの要素にロックでき、マウスが一方向へどれだけ移動できるかの制限を除去でき、視野からカーソルを取り除くことができます。これらは、本人視点の 3D ゲームなどで理想的です。
さらにこの API は、動きのコントロールやオブジェクトの回転、エントリーの変更にかなりのマウス操作が必要になるアプリケーションで役立ちます。例えばなんらかのボタンをクリックすることなく、マウスを動かすだけで視野角を制御できます。ボタンは他の操作のために使用できます。また、地図や衛星画像を見るアプリでも役に立ちます。
ポインターロックでは、カーソルがブラウザーやスクリーンの境界を通り過ぎるときでもマウスイベントにアクセスできます。例えばユーザーは限りなくマウスを動かすことで、3D モデルの回転や操作を続けることができます。ポインターロックがなければ、ポインターがブラウザーまたはスクリーンの端に達したときに回転や操作が止まります。ゲームのプレイヤーはマウスカーソルがゲームのプレイ領域から外れて、別のアプリケーションを意図せずクリックしてゲームからマウスのフォーカスが外れてしまうことを心配せずに、熱中してボタンをクリックしたり、マウスカーソルをあちこちに動かしたりすることができるようになります。
In this article
基本概念
ポインターロックはマウスキャプチャ と関係があります。マウスキャプチャはマウスのドラッグ中にターゲットの要素へ継続的にイベントを提供しますが、マウスのボタンを離すとイベントが停止します。ポインターロックとマウスキャプチャの違いは以下のとおりです。
- ポインターロックは永続的です。明示的に API が呼び出されるかユーザーが特定の解放ジェスチャを行うまで、マウスを解放しません。
- ポインターロックはブラウザーまたはスクリーンの境界に制限されません。
- ポインターロックはマウスボタンの状態に関係なく、イベントが発生し続けます。
- ポインターロックはカーソルを隠します。
メソッド/プロパティの概要
ここでは、ポインターロック仕様に関係するプロパティやメソッドを簡単に説明します。
requestPointerLock()
ポインターロック API は全画面 API と同様に、 DOM 要素に新たなメソッドrequestPointerLock() を追加することで拡張しています。接頭辞が最近削除されましたので、例えばcanvas 要素で ポインターロックを要求したい場合は、現在は以下のように宣言します。
canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock;canvas.requestPointerLock();メモ:ユーザーが既定のロック解除ジェスチャでポインターロックを解除した場合、またはこの文書に対して以前にポインターロックが入力されていない場合、エンゲージメントジェスチャの結果として生成されるイベントをrequestPointerLock が成功する前に、文書内で受信する必要があります。(https://w3c.github.io/pointerlock/#extensions-to-the-element-interface より)
pointerLockElement と exitPointerLock()
ポインターロック API はDocument インターフェイスも拡張しており、新たなプロパティやメソッドを追加しています。新たなプロパティpointerLockElement は、現在ロックしている要素がある場合に、その要素へアクセスするために使用します。また、Document 新たなメソッドであるexitPointerLock() は、名前が示唆するとおりポインターロックを終えるために使用します。
pointerLockElement プロパティは要素が現在ポインターがロック状態であるかを判断する(例えば論理型でチェックを行う)ため、またはロックされた要素があればその要素への参照を得るために有用です。
pointerLockElement の使用例を示します。
if ( document.pointerLockElement === canvas || document.mozPointerLockElement === canvas) { console.log("The pointer lock status is now locked");} else { console.log("The pointer lock status is now unlocked");}Document.exitPointerLock() メソッドはポインターロックを終えるために使用され、requestPointerLock() と同様にpointerlockchange イベントやpointerlockerror イベントを用いて非同期的に動作します。使用例は以下のとおりです。
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;// ロック解除を試みるdocument.exitPointerLock();pointerlockchange イベント
ポインターロックの状態が変化したとき、例えばrequestPointerLock() やexitPointerLock() を呼び出したときや、ユーザーが ESC キーを押下したときなどに、pointerlockchange イベントがdocument に発生します。これはシンプルなイベントであり、付加的なデータは含まれません。
if ("onpointerlockchange" in document) { document.addEventListener("pointerlockchange", lockChangeAlert, false);} else if ("onmozpointerlockchange" in document) { document.addEventListener("mozpointerlockchange", lockChangeAlert, false);}function lockChangeAlert() { if ( document.pointerLockElement === canvas || document.mozPointerLockElement === canvas ) { console.log("The pointer lock status is now locked"); // 応答として役に立つ処理 } else { console.log("The pointer lock status is now unlocked"); // 応答として役に立つ処理 }}pointerlockerror イベント
requestPointerLock() またはexitPointerLock() の呼び出しによりエラーが発生したときは、pointerlockerror イベントがdocument に発生します。これはシンプルなイベントであり、付加的なデータは含まれません。
document.addEventListener("pointerlockerror", lockError, false);document.addEventListener("mozpointerlockerror", lockError, false);function lockError(e) { alert("Pointer lock failed");}メモ:Firefox 50 まで、上記のイベントはmoz 接頭辞を付加していました。
Mouse イベントの拡張
ポインターロック API は通常のMouseEvent インターフェイスを、movement 属性で拡張します。新たな 2 つの属性movementX およびmovementY が、マウスポインターの位置の変化を提供します。引数の値はMouseEvent のプロパティであるscreenX およびscreenY の値同士の差と同じであり、それらのプロパティは 2 つ続いて発生するmousemove イベントeNow およびePrevious に保存されます。言い換えると、ポインターロックのパラメーターmovementX は、eNow.screenX - ePrevious.screenX になります。
ロックされた状態
ポインターロックが有効であるとき、標準MouseEvent のプロパティであるclientX、clientY、screenX、screenY は、マウスが動いていないかのように値が固定されます。movementX プロパティおよびmovementY プロパティが、マウスの位置の変化を提供し続けます。マウスが一方向へ連続的に移動するとしても、movementX およびmovementY の値に制限はありません。マウスカーソルは存在せず、ウィンドウから外れたりスクリーンの端で止まったりしないという考え方です。
ロックが解除された状態
引数movementX およびmovementY はマウスのロック状態にかかわらず有効であり、ロックされていない状態でも利便性のために使用できます。
マウスのロックが解除されると、システムカーソルが存在するようになり、ブラウザーがウィンドウ表示に戻ります。このとき、movementX およびmovementY は 0 に設定されるかもしれません。
シンプルな例のウォークスルー
ポインターロックの使用方法やシンプルな制御システムの設定方法を示すため、シンプルな ポインターロックのデモ を作成しました (ソースコードを確認する)。このデモでは、JavaScript を使用して<canvas> 要素上にボールを描画します。canvas をクリックすると ポインターロックがマウスポインターを取り除いて、マウスを使用してボールを直接動かすことができます。このデモの仕組みを見ていきましょう。
canvas 内の、x および y の初期位置を設定します。
const x = 50;const y = 50;現在は ポインターロックのメソッドに接頭辞がついていますので、ブラウザー実装ごとに処理を分けています。
canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock;document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;キャンバスがクリックされたときに、キャンバスでrequestPointerLock() メソッドを実行するイベントリスナーを設定します。これは、ポインターロックを開始します。
canvas.onclick = () => { canvas.requestPointerLock();};ポインターロックイベントpointerlockchange のイベントリスナーを設定します。イベントが発生したら、ポインターロックの変更を制御するためにlockChangeAlert() という名前の関数を実行します。
// ポインターロックのイベントリスナー// さまざまなブラウザー向けに、ポインターロックの状態変化イベントをフックするdocument.addEventListener("pointerlockchange", lockChangeAlert, false);document.addEventListener("mozpointerlockchange", lockChangeAlert, false);この関数は、 pointLockElement プロパティがキャンバスを示しているかを確認します。示している場合は、マウスの移動を扱うために、イベントリスナーをupdatePosition() に設定します。示していない場合は、イベントリスナーを再び削除します。
function lockChangeAlert() { if ( document.pointerLockElement === canvas || document.mozPointerLockElement === canvas ) { console.log("The pointer lock status is now locked"); document.addEventListener("mousemove", updatePosition, false); } else { console.log("The pointer lock status is now unlocked"); document.removeEventListener("mousemove", updatePosition, false); }}updatePosition() 関数が、キャンバス内のボールの位置 (x およびy) を更新します。また、ボールがキャンバスの端からはみ出すかをチェックするif() 文が含まれています。ボールがはみ出す場合は、反対側の端にボールを描画します。また、requestAnimationFrame() がすでに呼び出されたかを確認しており、呼び出された場合は必要に応じて再び呼び出して、キャンバスのシーンを更新するためにcanvasDraw() 関数を呼び出します。さらに、参照用に X および Y の位置を表示するための tracker も設定します。
const tracker = document.getElementById("tracker");let animation;function updatePosition(e) { x += e.movementX; y += e.movementY; if (x > canvas.width + RADIUS) { x = -RADIUS; } if (y > canvas.height + RADIUS) { y = -RADIUS; } if (x < -RADIUS) { x = canvas.width + RADIUS; } if (y < -RADIUS) { y = canvas.height + RADIUS; } tracker.textContent = `X position: ${x}, Y position: ${y}`; if (!animation) { animation = requestAnimationFrame(() => { animation = null; canvasDraw(); }); }}canvasDraw() 関数は、現在のx およびy の位置にボールを描画します。
function canvasDraw() { ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#f00"; ctx.beginPath(); ctx.arc(x, y, RADIUS, 0, degToRad(360), true); ctx.fill();}iframe の制限
ポインターロックが一度にロックできる iframe は 1 つだけです。 iframe をひとつロックすると、別の iframe をロックしてターゲットを切り替えようとすることはできません。ポインターロックはエラーになります。この制限を避けるため、始めにロックされた iframe のロックを解除してから別の iframe をロックしてください。
iframe の既定の動作では、「サンドボックス化された」 iframe が ポインターロックをブロックします。この制限を回避するには、<iframe sandbox="allow-pointer-lock"> を使用してください。
仕様書
| Specification |
|---|
| Pointer Lock 2.0> |