JavaScript code that works with a mouse does not work with a pen tablet.

This article can be read in about 8 minutes.
PR

The purpose 


JavaScript code that works with a mouse failed to work with a pen tablet.

This article summarizes the changes made by me.

The modified application is a painting app on a Canvas. I will only introduce the sections that were changed to add support for a pen tablet (so that the app works with both a pen tablet and a mouse).

Regarding smartphone/tablet compatibility


Support for smartphones and tablets should be similar to that for pen tablets, but I haven’t tested it yet.

PR

Issues and Fixes

Mouse-related events are not being received

When I used a pen tablet, I did not receive events for mousedown, mousemove, and mouseup. This is because pen tablets send touch events, not mouse events.

Each event needs to be replaced as follows:

Before (mouse)After(touch)
mousedowntouchstart
mousemovetouchmove
mouseuptouchend

In order to make both the mouse and pen tablet operate in the same way, I actually made the following changes. I made it so that the same function is called for both mouse operations and pen tablet operations.

Before:

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

After:

	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);

The click event is also received from a pen tablet, so no fix is needed.

Cannot get offsetX/offsetY from an event


The fix above will allow you to receive events, but you still won’t be able to get event.offsetX and event.offsetY from the event argument in the callback.

This is because touch and mouse events are different, and touch events do not have offsetX or offsetY properties. Therefore, you need to calculate these values yourself, as shown below.

element refers to the base element (e.g., the canvas). You can get it using a method like document.getElementById.

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

I created the following function to work with both a mouse and a pen tablet.

If event.offsetX/Y exists, it returns them as is; otherwise, it calculates and returns them.

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
}

While I’ve mentioned offsetX/Y here, coordinate information such as clientX and clientY is also not available directly on the event object in a touch event. Instead, this information is stored under event.touches[0]. (The touches property is an array because multiple touches can occur simultaneously on smartphones and other devices.) For more details, please refer to the following page.

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

Scrolling during pen movement (drag)


When I moved the pen up and down, the app worked as expected, but the browser also started to scroll.

You can prevent this by stopping the browser’s default behavior during a drag using the following method.

Use preventDefault


You can stop the default behavior by calling event.preventDefault() inside the function that is called by the touchmove event, as shown below.

Notice:

I found an interesting point on the following page: Depending on the browser, preventDefault might not work.

If the app doesn’t work as you expect, the following fix might solve the issue.

Before:

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

After:

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

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

PR

Result


By making the changes mentioned above, the target app now works with a pen tablet as well.

comment

Copied title and URL