HTMLのcanvasとJavaScriptでお絵かきアプリ作る【カラーパレット・消しゴム機能追加編】

## はじめに

前回記事「[【初心者向け】HTMLのcanvasとJavaScriptでお絵かきアプリ作る【最低限の機能実装編】](https://qiita.com/tsuyopon_xyz/items/41ca2674afb8a6af0db7)」の続きの内容となります。

また、今回話す内容は「[HTMLのcanvasとJavaScriptでお絵かきアプリ【色・消しゴム追加編】](https://tsuyopon.xyz/2018/09/15/how-to-create-drawing-app-part2/)」の内、主に機能実装の概要をまとめたものになります。

## 完成イメージ

![oekaki-color-eraser.gif](https://qiita-image-store.s3.amazonaws.com/0/289248/61cb8254-7b45-95d7-3068-1a86b1593040.gif)

## 今回作成したコードのレポジトリと公開しているアプリケーション

- [GitHubのレポジトリ](https://github.com/tsuyopon-xyz/drawing_app_part2)
- [公開しているアプリ](https://tsuyopon-xyz.github.io/drawing_app_part2/)

## 今回追加した機能

- カラーパレットを使った色変更機能
- 消しゴムモードによる部分消し機能

### カラーパレットを使った色変更機能

カラーパレットを実装するために今回は「[colorjoe](https://github.com/bebraw/colorjoe)」というライブラリを利用しました。

「colorjoe」を使うことで次の機能が実現できます

- カラーパレットのカスタマイズ
- 色情報をRGB or HSLで取得することが出来る
- colorjoeの独自イベントで選択中・選択後の色を取得することが出来る

カラーパレットのカスタマイズはいくつか種類があるので、興味がある方は「[colorjoeの本サイト](http://bebraw.github.io/colorjoe/)」のデモを見ると良いかと思います。


### 消しゴムモードによる部分消し機能

消しゴムモードはとてもシンプルで、選択する色を**canvasと同じ背景色**(今回の場合は白)を選択すれば良いだけです。

上記の「完成イメージ」のアニメーション画像では、「消しゴムモード」ボタンをクリックしたときに、色の指定で「#FFFFFF」と白をセットするようにしています。

## 今回作成したコード

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <!-- 色変更に使うライブラリで用意されているCSSを導入 https://github.com/bebraw/colorjoe -->
  <link rel="stylesheet" href="css/colorjoe.css">
  <title>お絵かきアプリ</title>
</head>
<body>
  <h1>お絵かきアプリ</h1>
  <div>
    <canvas
      id="draw-area"
      width="400px"
      height="400px"
      style="border: 1px solid #000000;"></canvas>
    <!-- 色を選択できるカラーパレットを用意する。 -->
    <span id="color-palette"></span>
  </div>
  <div>
    <button id="clear-button">全消し</button>
  </div>
  <div>
    <button id="eraser-button">消しゴムモード</button>
  </div>
  <!-- 色変更に使うライブラリを導入 https://github.com/bebraw/colorjoe -->
  <script src="./js/colorjoe.min.js"></script>
  <script src="./js/main.js"></script>
</body>
</html>
```

```js:main.js
// https://github.com/tsuyopon-xyz/drawing_app_part1/blob/master/main.js
// 上記のコードを元に以下の追加機能を追加します。
// - 線の色を変更する機能
// - 消しゴム機能
//
// 元々書かれてた説明のコメントは削除しました。理由は次のとおりです。
// - 今回の変更差分の説明コメントのみにすることで、どの部分で変更があったかわかりやすくするため
window.addEventListener('load', () => {
  const canvas = document.querySelector('#draw-area');
  const context = canvas.getContext('2d');
  const lastPosition = { x: null, y: null };
  let isDrag = false;

  // 現在の線の色を保持する変数(デフォルトは黒(#000000)とする)
  let currentColor = '#000000';

  function draw(x, y) {
    if(!isDrag) {
      return;
    }
    context.lineCap = 'round';
    context.lineJoin = 'round';
    context.lineWidth = 5;
    context.strokeStyle = currentColor;
    if (lastPosition.x === null || lastPosition.y === null) {
      context.moveTo(x, y);
    } else {
      context.moveTo(lastPosition.x, lastPosition.y);
    }
    context.lineTo(x, y);
    context.stroke();

    lastPosition.x = x;
    lastPosition.y = y;
  }

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

  function dragStart(event) {
    context.beginPath();

    isDrag = true;
  }

  function dragEnd(event) {
    context.closePath();
    isDrag = false;
    lastPosition.x = null;
    lastPosition.y = null;
  }

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

    // 消しゴムモードを選択したときの挙動
    const eraserButton = document.querySelector('#eraser-button');
    eraserButton.addEventListener('click', () => {
      // 消しゴムと同等の機能を実装したい場合は現在選択している線の色を
      // 白(#FFFFFF)に変更するだけでよい
      currentColor = '#FFFFFF';
    });

    canvas.addEventListener('mousedown', dragStart);
    canvas.addEventListener('mouseup', dragEnd);
    canvas.addEventListener('mouseout', dragEnd);
    canvas.addEventListener('mousemove', (event) => {
      draw(event.layerX, event.layerY);
    });
  }

  // カラーパレットの設置を行う
  function initColorPalette() {
    const joe = colorjoe.rgb('color-palette', currentColor);

    // 'done'イベントは、カラーパレットから色を選択した時に呼ばれるイベント
    // ドキュメント: https://github.com/bebraw/colorjoe#event-handling
    joe.on('done', color => {
      // コールバック関数の引数からcolorオブジェクトを受け取り、
      // このcolorオブジェクト経由で選択した色情報を取得する

      // color.hex()を実行すると '#FF0000' のような形式で色情報を16進数の形式で受け取れる
      // draw関数の手前で定義されている、線の色を保持する変数に代入して色情報を変更する
      currentColor = color.hex();
    });
  }

  initEventHandler();

  // カラーパレット情報を初期化する
  initColorPalette();
});
```

上記コードの詳しい解説はコードに埋め込んだコメントを読んで頂けたらと思います。

コメント以外でも詳しい解説が欲しい方は「[HTMLのcanvasとJavaScriptでお絵かきアプリ【色・消しゴム追加編】](https://tsuyopon.xyz/2018/09/15/how-to-create-drawing-app-part2/)」で書いているので、そちらを参照して頂けたらと思います。