7. マウス操作とキー操作
本章では、マウスイベントとキーイベントの実装方法を紹介します。
7.1 マウスイベントの実装
本節では、マウスイベントの実装方法を紹介します。
7.1.1 マウスイベントの種類
マウスイベントは、対象とするオブジェクトに対して addEventListener()
を呼び出すことで実装できます。
ここで type
にはイベントの種類、kansuu
にはイベント発生時に呼び出す関数(イベントハンドラ)を指定します。
本演習で使う主なマウスイベントは、以下のとおりです。
イベント名 | イベント発生タイミング |
---|---|
click | マウスをクリックしたとき |
mousedown | マウスボタンを押下したとき |
mouseup | マウスボタンを離したとき |
mousemove | マウスを動かしたとき |
mouseenter | マウスが要素の中に入ったとき |
mouseleave | マウスが要素から外に出たとき |
マウスイベント発生時に呼び出す関数は、マウス情報を保持する引数(引数名は慣例的に e
や event
)を受け取ります。
例えば、マウスのグローバル座標を取得したい場合は、clientX
、clientY
メンバを参照します。
しかし、これはブラウザ上でのマウス座標であるため、canvas
などの左上を原点とした相対座標を取得したい場合は、
以下のように offsetX
、offsetY
メンバを参照します。
描画に際して座標変換をしている場合は、それを考慮することを忘れないよう注意してください。
また、イベント発生時に呼び出す関数は上記のように定義することもできますが、 イベント発生時にしか呼び出さないということがわかっている場合は、 名前をつけずに関数を定義する「無名関数」を使うことができます。 無名関数は以下のように addEventListener() の引数内に記述します。
以下では、無名関数を利用したマウスイベントの実装例を紹介します。
7.1.2 マウスクリック機能の実装
「4.2 ボールの運動」にある、簡単なボールの運動シミュレーションシステムに対して、 Cnavas 上でマウスクリックされたとき、ボール座標をクリック位置に移動させるという実装を考えます。
Canvas に対してマウスクリックのイベント処理を実装する場合、以下のコードを挿入します。
あとは、マウスの座標情報を取得し、ボール座標を更新するだけとなります。 コードの実装例は以下のとおりです。
7.1.3 マウスドラッグ機能の実装
ドラッグ機能の実装には、少し工夫が必要です。
ここでは、mousedown
, mouseup
, mousemove
を組み合わせる方法を紹介します。
まず、ドラッグ中であることを表すフラグ変数 drag
を用意し、
mousedown
でマウスが押下されたときにこのフラグを ON にします。
また、mouseup
でマウスが離されたときには、このフラグを OFF にします。
そして、mousemove
での座標更新処理を drag
フラグが ON のときのみ実行するようにします。
こうすることで、マウスドラッグ処理の実装が可能となります。
実際のコード例は以下のとおりです。
キャンバス上でマウスドラッグ操作をすると、ボールが追従することが確認できます。 しかし、このままではマウスカーソルがキャンバス上のどの位置にあってもボールのドラッグが可能となります。 以下の練習問題に挑戦してみましょう。
演習
演習
マウスカーソルがボール上にあるときのみドラッグ可能にしなさい。 また、マウスカーソルがボール上にあるとき、ボールに視覚的な変化を与えなさい。
ヒント
マウスカーソルの座標を \((x_{\rm mouse}, y_{\rm mouse})\)、ボールの中心座標を \((x_{\rm ball}, y_{\rm ball})\)、ボールの半径を \(r\) とすると、 マウスカーソルがボール上にあるかどうかは、マウスカーソルとボールの中心との距離がボールの半径以下かどうかを調べればよいので、 以下の数式を考えればよいことになります。
\[ \sqrt{\left( x_{\rm ball} - x_{\rm mouse} \right)^2 + \left( y_{\rm ball} - y_{\rm mouse} \right)^2} \le r\tag{1}\]
平方根の計算には、Math.sqrt()
関数を利用することができます。
また、累乗の計算には Math.pow()
関数を利用することができます。
さらに、ここでは二乗和の平方根 \(\sqrt{x^2 + y^2}\) を返す Math.hypot(x, y)
関数を使うと便利です。
なお、今回は Math.hypot()
を利用していきますが、式(1) は単純な四則演算記号のみで書き直すことができ、
そのようにしてから計算したほうが、処理数・処理時間の大幅な削減に繋がります。
演習 解答例 1
マウスカーソルがボール上にあるかどうかを表すフラグ用変数 over
を導入し、実装した例を以下に示します。
マウスカーソルの位置判定を行うコードは、マウス移動時 (mousemove
) に呼び出す mouseMove(e)
関数内で行っています。
また、over
/drag
フラグが ON のとき、それが視覚的にわかるようボールの色に変化を与えています。
演習 解答例 2
「演習 解答例 1」のコードには、まだ幾つかの問題があります。 例えば、ボール上のどの位置から(ボールの中心以外から)ドラッグを開始しても、 ドラッグ中はボールの中心座標がマウスカーソルの座標と一致する点です。 このままだと、ドラッグ開始時にボールが僅かに瞬間移動したように見えてしまいます。
この問題を解決する方法として、マウス押下時のボール座標 (mouseDownX
, mouseDownY
)、カーソル座標 (xPrev
, yPrev
)、およびドラッグ中のカーソル座標 (mouseX
, mouseY
) を別々に記憶し、
カーソル座標の変化量分だけボールを移動させるというものが考えられます。
実際に上記の考えを実装したコード例を以下に示します。
おまけ: 速度ベクトルの可視化
ボールをマウスドラッグすると、ドラッグ終了位置から開始位置までを線で結び、 そのベクトルをボールの初速度とする例を以下に紹介します(パチンコでボールを飛ばすイメージです)。
実装はとても単純で、「演習 解答例 2」で計算したドラッグ距離を
そのまま速度を表す変数 vx
, vy
に代入するだけとなります。
ここでは、現在の速度ベクトルを赤線で可視化しています。
7.2 キーイベントの実装
本節では、キーイベント(キーボードイベント)の実装方法を紹介します。
7.2.1 キーイベントの種類
キーイベントはマウスイベントと同様、対象とするオブジェクトに対して addEventListener()
を呼び出すことで実装できます。
ここで type
にはイベントの種類、kansuu
にはイベント発生時に呼び出す関数や、無名関数を指定します。
キーイベントの種類は、以下のとおりです。
イベント名 | イベント発生タイミング |
---|---|
keydown | キーを押下したとき |
keypress | 修飾キー以外を押下したとき |
keyup | キーを離したとき |
修飾キーとは、[Shift] や [Ctrl]、[Alt]、[Command] キーのことです。
何らかのキーが押されたとき、keydown
イベントが発生し、
そのキーが修飾キーでなかった場合は更に keypress
イベントが発生します。
また、キーを押し続けると keydown
と keypress
(修飾キーの場合は keydown
のみ) が繰り返し発生します。
7.2.2 キーボード操作機能の実装
イベントリスナの追加は、通常以下のように document
に対して行われます。
また、押下されたキーの情報 (String) を取得するには、key
メンバを参照します。
// キーが押下されたとき
document.addEventListener('keydown', function(e) {
// 押されたキーの取得
let nowKey = e.key;
)};
以下のコード例では、switch
文を使い、カーソルキーが押されたときに
その方向にボールを移動させるような分岐を作っています。
124 行目では、preventDefault()
を呼び出すことで、キー操作によるページスクロールを禁止しています。
preventDefault()
は、キー操作などのイベント発生時に、ブラウザに設定されているデフォルトの動作を禁止する関数です。
7.2.3 修飾キーイベントの実装
修飾キーが押されているかどうかは、shiftKey
, ctrlKey
, altKey
メンバ(Boolean 型)を
参照することで確認できます。
先ほどのカーソルキーでボールの位置を移動させるコードに対し、 修飾キーに応じて移動量を変化させるように変更した例を以下に示します。