[Nuxt.js]Canvasで線を描画する

資料に線を描画するという描画を実装したのですが、思ったより簡単に実装できたので共有します。
Composition APIを使用しています。

こちら完成形です。
![aef10ae0522b11bb5f2b832781810bb8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1198226/7c5789e4-172b-8ca1-c59c-4f495253dbb5.gif)

こちらコードになります。

``` index.vue
<template>
  <div id="canvasContainer">
    <h1>キャンバス</h1>
    <canvas
      id="penCanvas"
      width="600px"
      height="800px"
      @mousedown="onDragStart"
      @mousemove="drawLine"
      @mouseup="onDragEnd"
      @mouseout="onDragEnd"
    ></canvas>
  </div>
</template>

<script lang="ts">
import {
  onMounted,
  defineComponent,
  ref,
} from '@nuxtjs/composition-api'

export default defineComponent({
  setup() {
    const canvas = ref()
    const context = ref()
    const isDrawable = ref(false)

    onMounted(() => {
      canvas.value = document.querySelector('#penCanvas')
      context.value = canvas.value.getContext('2d')
      context.value.lineCap = 'round'
      context.value.lineJoin = 'round'
      context.value.lineWidth = 5
      context.value.storokeStyle = '#000000'
    })

    /**
     * キャンバスをドラッグした際の処理
     * @param {MouseEvent} e
     */
    const onDragStart = (e: MouseEvent) => {
      const posX = e.offsetX
      const posY = e.offsetY
      context.value.beginPath()
      context.value.lineTo(posX, posY)
      context.value.stroke()
      isDrawable.value = true
    }

    /**
     * 線を描画する
     * @param {MouseEvent} e
     */
    const drawLine = (e: MouseEvent) => {
      if (!isDrawable.value) return
      // ポインターの位置を格納
      const posX = e.offsetX
      const posY = e.offsetY
      context.value.lineTo(posX, posY)
      context.value.stroke()
    }

    /**
     * 描画終了時の処理
     */
    const onDragEnd = () => {
      context.value.closePath()
      isDrawable.value = false
    }

    return {
      canvas,
      context,
      isDrawable,
      onDragStart,
      drawLine,
      onDragEnd,
    }
  },
})
</script>

<style lang="scss">
#penCanvas {
  background: #6c757d;
}
</style>

```

それぞれ説明していきます。

### onMounted
```
    onMounted(() => {
      canvas.value = document.querySelector('#penCanvas')
      context.value = canvas.value.getContext('2d')
      context.value.lineCap = 'round'
      context.value.lineJoin = 'round'
      context.value.lineWidth = 5
      context.value.storokeStyle = '#000000'
    })
```
DOMが作成された直後に行う処理です。
``document.querySelector('#penCanvas')`` ・・・ canvasを取得
``canvas.value.getContext('2d')`` ・・・ canvas上でペンを描画できるようにします。
``context.value.lineCap = 'round'`` ・・・ 線端の形状指定します。今回は、丸にしています。
``context.value.lineJoin = 'round'`` ・・・ 線の接合箇所の形状を指定します。今回は、丸にしています。
``context.value.lineWidth = 5`` ・・・ 線の幅を指定します。
``context.value.storokeStyle = '#000000'`` 線の色を指定します。

### onDragStart
ドラッグを開始した際に行われる処理です。

```
    /**
     * キャンバスをドラッグした際の処理
     * @param {MouseEvent} e
     */
    const onDragStart = (e: MouseEvent) => {
      const posX = e.offsetX
      const posY = e.offsetY
      context.value.beginPath()
      context.value.lineTo(posX, posY)
      context.value.stroke()
      isDrawable.value = true
    }
```

``posX, posY`` ・・・ カーソルの位置を格納します。
``context.value.beginPath`` ・・・ 現在のパスをリセットする際に使用します。
``context.value.lineTo(posX, posY)`` ・・・ 直前の座標と指定座標を結ぶ直線を引く際に使用します。
``context.value.stroke()`` ・・・ キャンバス上に線を描画します。

### drawLine
ドラッグ中に行われる処理です。
```
    /**
     * 線を描画する
     * @param {MouseEvent} e
     */
    const drawLine = (e: MouseEvent) => {
      if (!isDrawable.value) return
      // ポインターの位置を格納
      const posX = e.offsetX
      const posY = e.offsetY
      context.value.lineTo(posX, posY)
      context.value.stroke()
    }
```
説明はonDragStartの際にしているので省略します。

### onDragEnd
ドラッグ終了時に行われる処理です。
```
context.value.closePath()
isDrawable.value = false
```
``context.value.closePath()`` ・・・ 最終座標と開始座標を結んでパスを閉じる際に使用します。