【初心者向け】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【最低限の機能実装編】

## はじめに

この記事は「[【初心者】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【ベース作り編】](https://tsuyopon.xyz/2018/09/14/how-to-create-drawing-app-part1/)」の内容を短くまとめたものになります。

ソースコードを交えた詳しい解説を読みたい方は「[【初心者】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【ベース作り編】](https://tsuyopon.xyz/2018/09/14/how-to-create-drawing-app-part1/)」を参照していただけたらと思います。

## 今回含め3回にわけて追加機能の解説もします

この記事とは別でもう2つ、以下の機能を追加した内容の説明記事を作成する予定です。

1. カラーパレットを使った色変更機能と・部分消しが出来る消しゴム機能を追加
2. 線の太さ変更機能、canvasにマウスカーソルを乗っけた時に線の太さがわかるインジケーターを表示する機能

## 今回作成した「お絵かきアプリ」

実際に動かしている様子は以下の画像をご確認ください。

![oekaki.gif](https://qiita-image-store.s3.amazonaws.com/0/289248/25f0a542-bd2f-cb5e-c28d-df0f37f0e528.gif)


今回実装したコードと公開しているアプリケーションは以下のリンクからアクセスしてください。

- [GitHubレポジトリ](https://github.com/tsuyopon-xyz/drawing_app_part1)
- [アプリケーション](https://tsuyopon-xyz.github.io/drawing_app_part1/)

## 今回実装した2つの機能

今回は「お絵かきアプリ」に最低限必要だと思われる以下の2つの機能を実装しました。

1. マウスのドラッグ中に線を描く機能(色は黒のみ)
2. 「全消し」ボタンをクリックしたら「canvas」上に描画している線を全て削除する機能

### ドラッグ時のときだけ線を描く処理の流れ

１つ目のマウスのドラッグ中に線を描くときに使う変数・関数を以下に抜粋しました。

```javascript:線の描画に関係あるコードのみ抜粋
let isDrag = false;

function draw(x, y) {
  // マウスがドラッグされていなかったら処理を中断する。
  // ドラッグしながらしか絵を書くことが出来ない。
  if(!isDrag) {
    return;
  }

  // 以降、canvasのcontextを使って描画処理
}

function dragStart(event) {
  isDrag = true;
}
// マウスのドラッグが終了したら、もしくはマウスがcanvas外に移動したら
// isDragのフラグをfalseにしてdraw関数内でお絵かき処理が中断されるようにする
function dragEnd(event) {
  isDrag = false;
}

// マウス操作やボタンクリック時のイベント処理を定義する
function initEventHandler() {
  canvas.addEventListener('mousedown', dragStart);
  canvas.addEventListener('mouseup', dragEnd);
  canvas.addEventListener('mouseout', dragEnd);
  canvas.addEventListener('mousemove', (event) => {
    draw(event.layerX, event.layerY);
  });
}
```

メインは、一番最後のinitEventHandler関数内で定義している「マウスイベント」の定義です。

ドラッグ・ドロップの機能は以下のそれぞれのマウスイベントを組み合わせることで実現できます。

- mousedownイベント
    - 指定した要素でマウスのボタンを押し込んだ時に呼ばれる
    - 今回の場合はcanvas要素でmousedownイベントを検知したらdragStart関数が実行されて、isDragフラグがtrueとなる
        - isDragフラグがtrueの時にdraw関数を実行すると線が描画される
- mouseupイベント
    - 指定した要素内で「マウスのボタンを押し込んだ状態」から「押し込んでいない元の状態」に戻したときに呼ばれる
    - 今回の場合はcanvas要素でmouseupイベント検知をしたらdragEnd関数が実行されて、isDragフラグがfalseとなる
        - isDragフラグがfalseの時にdraw関数を実行すると、draw関数最初の条件分岐(if文)で処理が中断されて線が描画されない
- mouseoutイベント
    - 指定した要素からマウスカーソルが外に出たときに呼ばれる
    - 今回の場合はcanvas要素でmouseoutイベントを検知したらdragEnd関数が実行されて、isDragフラグがfalseとなる
        - 「mouseupイベント」の処理内容と同じでisDragフラグがfalseになるので、draw関数が呼ばれても線が描画されない
- mousemoveイベント
    - 指定した要素内でマウスカーソルが動いたときに呼ばれる
    - 今回の場合はcanvas要素でmousemoveイベントをしたらdraw関数を実行する
        - isDragの値は気にしない(draw関数内で判断してくれるから)
        - コールバック関数の引数であるeventオブジェクトの中のlayerX, layerYプロパティを利用することで、canvas要素の左上(始点)から見たマウスの位置のx座標、y座標を返す。
            - canvas要素の左上(始点)にマウスカーソルを合わせると(x, y) は (0, 0)となる


上記の内容をまとめると次のとおりです。

- isDragフラグがtrueのときだけマウスを動かしたときに呼ばれるdraw関数の処理を実行する (ドラッグ時のみ処理を実行する)
- isDragがtrueになるのはcanvas要素内でマウスのボタンを押し込んでいる状態のときだけ
- マウスのボタンを離したり、マウスカーソルがcanvasの外に出たらisDragがfalseになるため、ドラッグ状態ではなくなりdraw関数が実行されなくなる


### 「全消し」ボタンを押してcanvasをリセットする流れ

上記で説明した線の描画を行う処理と比べるととてもシンプルです。

「全消し」ボタンで利用するコードを抜粋します。

```javascript:全消し機能に関係ある機能のみ抜粋

function clear() {
  context.clearRect(0, 0, canvas.width, canvas.height);
}

function initEventHandler() {
  const clearButton = document.querySelector('#clear-button');
  clearButton.addEventListener('click', clear);
}
```

上記のコードを見ても分かる通り、canvas上をリセットする流れは次のとおりです。

1. initEventHandlerイベント関数内のclearButtonに定義したクリックイベントを定義する
2. ①で定義したイベントが検知されて実行されたらclear関数内の[context.clearRect](https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/clearRect)メソッドを読んでcanvasをまっさらな状態にする。
    - [context](https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D)はcanvas要素から取得することができて、canvasの描画や切り取りなどを行うのに必要な情報
    - 「clearRect(0, 0, canvas.width, canvas.height)」では、canvasの上の指定した範囲の描画を消す機能
        - clearRect(x座標, y座標, 横幅, 高さ)で、今回はcanvasの左上(始点)からcanvasの横幅分、高さ分を削除すると宣言している

## さいごに

「[【初心者】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【ベース作り編】](https://tsuyopon.xyz/2018/09/14/how-to-create-drawing-app-part1/)」の内容の内、機能実装の部分を抜粋して説明しました。

より詳細な説明は「[【初心者】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【ベース作り編】](https://tsuyopon.xyz/2018/09/14/how-to-create-drawing-app-part1/)」を参照していただけたらと思います。