マウスで動作するJavaScriptのコードがペンタブレットで動作しない

この記事は約6分で読めます。
スポンサーリンク

やりたいこと

マウスで動作するJavaScriptのコードがペンタブレットで動作しませんでした。

この記事では著者の修正した箇所をまとめておきます。

修正したアプリはCanvasに絵を描くアプリです。アプリをペンタブレットに対応するにあたって修正した箇所のみの紹介です。(ペンタブレット/マウス両方で動作するように修正します。)

スマホ/タブレット対応に関して

スマホ/タブレット対応は基本的にペンタブレットの対応と同様のはずですが、動作確認を行っていません。

スポンサーリンク

問題点と修正

マウス関係のイベントが来ない

ペンタブレットで操作した場合にmousedown、mousemove、mouseupのイベントが来ませんでした。

ペンタブレットではmouseのイベントではなくtouchのイベントが来ます。

各イベントは以下のように置き換える必要があります。

置き換え前(mouse)置き換え後(touch)
mousedowntouchstart
mousemovetouchmove
mouseuptouchend

ここではマウスとペンタブレットを同様に動作させるために実際には以下のように修正しました。(マウス操作時/ペンタブレット操作時に同じ関数を呼ぶようにしました。)

修正前:

	canvas.addEventListener('mousedown', startDrag, false);
	canvas.addEventListener('mousemove', whileDrag, false);
	canvas.addEventListener('mouseup', endDrag, false);

修正後:

	canvas.addEventListener('mousedown', startDrag, false);
	canvas.addEventListener('touchstart', startDrag, false);
	canvas.addEventListener('mousemove', whileDrag, false);
	canvas.addEventListener('touchmove', whileDrag, false);
	canvas.addEventListener('mouseup', endDrag, false);
	canvas.addEventListener('touchend', endDrag, false);

clickイベントはペンタブレットでも来ます。修正不要です。

EventからoffsetX/offsetYが取得できない

上記の修正でeventは来るようになりますが、コールバックの引数であるeventからevent.offsetX/offsetYが取得できません。

touchのイベントとmouseのイベントが異なるためです。またtouchのイベントにはoffsetX/offsetYがありません。そのため以下のように計算する必要があります。

elementは基準とするelementです。document.getElementByIdなどで取得してください。

const offsetX = event.touches[0].clientX - element.getBoundingClientRect().left
const offsetY = event.touches[0].clientY - element.getBoundingClientRect().top

マウスとペンタブレットでどちらでも動作するように以下のような関数を作りました。

event.offsetX/Yがあればそのまま返し、なければ計算して返します。

function getOffesetX(event,id) {
	if (event.offsetX != undefined) return event.offsetX;
	return event.touches[0].clientX - document.getElementById(id).getBoundingClientRect().left
}
function getOffesetY(event,id) {
	if (event.offsetY != undefined) return event.offsetY;
	return event.touches[0].clientY - document.getElementById(id).getBoundingClientRect().top
}

ここではoffsetX/Yに触れていますが、clientX /Yなどの座標情報も event.clientXも存在しません。event.touches[0]下に保存されています。(touchesが配列なのはスマホなどで同時に複数タッチされる可能性があるため)詳細は以下のページをご参照ください。

Touch - Web API | MDN
Touch インターフェイスは、タッチ感応面へのひとつの接触点を表します。接触点とは一般的に指やスタイラスと、タッチ画面やトラックパッドのような機器が触れた位置です。

ペン移動(ドラッグ)中にスクロールする

ペンを上下させたときにアプリが想定通りに動くと同時にブラウザがスクロールするようになってしまいました。

以下の方法でドラッグ中にブラウザの初期動作を止めることでスクロールしないようにすることが可能です。

preventDefaultの使用

以下のようにtouchmoveイベントで呼ばれる関数の中でevent.preventDefault()を呼ぶことで初期動作を止めることができます。

注意

以下のページに気になることが書いてありました。ブラウザによりpreventDefaultが効かない可能性があります。

想定通りに動作しない場合は以下の修正で治るかもしれません。

修正前:

canvas.addEventListener('mousemove', whileDrag, false);

修正後:

canvas.addEventListener('mousemove', whileDrag, {passive:false});

EventTarget: addEventListener() メソッド - Web API | MDN
addEventListener() は EventTarget インターフェイスのメソッドで、ターゲットに特定のイベントが配信されるたびに呼び出される関数を設定します。
canvas.addEventListener('touchmove', whileDrag, false);
function whileDrag(event) {
	event.preventDefault()

スポンサーリンク

結果

対象としたアプリは上記の点を修正することでペンタブレットでも動作するようになりました。

コメント

タイトルとURLをコピーしました