🎨

Canvasでタッチでお絵かきとか可能にする設定

2022/07/22に公開

概要

個人でアクアビーズデザイナーを作っていて詰まったので、ここにまとめておきます。
こんなサイトです。

https://aqua-beads.hashito.biz/

この記事はHTMLのCanvas要素を利用してiOSなどのタッチ入力でお絵描きさせるためのノウハウです。

下記の記事をベースに記載しています。
https://stackoverflow.com/questions/70252135/lines-drawn-on-html-canvas-not-appearing-with-touch-events

CSSの設定

前提として、Canvasは初期設定だとタッチ入力でスライドされるようになっています。
ですので、CSSのtouch-actionを変更しておく必要があります。

https://developer.mozilla.org/ja/docs/Web/CSS/touch-action

全くスライドさせない場合はnoneでOKですが、マルチ指での入力を許容するために私はpinch-zoomにしておきました。

<canvas id="canvas" style="touch-action: pinch-zoom;"></canvas>

イベント

マウスイベントだとmousemove,mousedown,mouseupなどがありますが、タッチ系だと下記のようなイベントがあります。

取得可能な情報

タッチ関係の情報はe.touchesに入っているようです。
また、複数指の場合があるため、このオブジェクトは配列になっていて、指単位の情報を取得できるようです。

タッチイベントについて
https://developer.mozilla.org/ja/docs/Web/API/TouchEvent

タッチオブジェクトについて
https://developer.mozilla.org/ja/docs/Web/API/Touch

この中で、clientXclientYを取得すればタッチする位置が取得できそうです。

ソースコード

めんどくさい話を書きましたが、タッチとマウス操作に対応したものは下記のようなコードになります。

<canvas id="canvas" style="touch-action: pinch-zoom;"></canvas>
    let mouseDown = 0;
    let mouseMove_fnc = (e) => {
        var rect = e.target.getBoundingClientRect();
        // タッチの場合は clientX は undefined になるため、そこで分岐させる
        if(e.clientX){
            x = e.clientX - rect.left;
            y = e.clientY - rect.top;    
        }else{
            x = e.touches[0].clientX - rect.left;
            y = e.touches[0].clientY - rect.top;    
            // マルチタッチの場合はズームやスライド等の操作であるため、お絵かきをやめる。
            if(e.touches.length>1){
                return;
            }
        }
        if (mouseDown)
            dorw(x, y); // ★ここの関数は自分で作成してください。
    }
    // マウス操作系のイベント登録
    canvas.addEventListener('mousemove', mouseMove_fnc, false);     // 入力イベント
    canvas.addEventListener('mousedown', () => mouseDown++, false); // マウスダウン時は操作開始
    canvas.addEventListener('mousedown', mouseMove_fnc, false);     // マウスダウン時も入力対象とする
    canvas.addEventListener('mouseup', () => mouseDown = 0, false); // マウスアップ時は操作終了

    // タッチ操作系のイベント登録
    canvas.addEventListener('touchmove', mouseMove_fnc, false);      // 入力イベント
    canvas.addEventListener('touchstart', () => mouseDown++, false); // マウスダウン時は操作開始
    canvas.addEventListener('touchstart', mouseMove_fnc, false);     // マウスダウン時も入力対象とする
    canvas.addEventListener('touchend', () => mouseDown = 0, false); // マウスアップ時は操作終了

Discussion