Nuxt3でFabric.jsを使用してみる

株式会社アドグローブ ソリューション事業本部(大阪)の𠮷川です。
今回はNuxt3でFabric.jsを使用してCanvas操作をしてみたので簡単にはなりますが、Nuxt3とFabric.jsの概要含めてご紹介します。


Nuxt3とは

Nuxt.jsは無料かつオープンソースのフレームワークであり、直感的で拡張可能な方法で、
Vue.jsを使用してタイプセーフで高パフォーマンスなプロダクショングレードのフルスタックのWebアプリケーションやウェブサイトを作成するためのフレームワークです。

(公式文章を翻訳)

Nuxt3はそのNuxt.jsの最新世代バージョンであり、Vue3とViteを採用しておりパフォーマンス・開発体験・拡張性の向上を実現しています。
CompositionApiによりビジネスロジックを分離しやすくなり、テスタブルになったのは良いことかと思います。
ただ現状vitestの設定が結構複雑なので、そのあたりが改善されるとさらに恩恵を得ることができるのではと思っています。
詳細やインストール方法は公式サイトをご確認ください。

nuxt.com


Fabric.jsとは

Fabric.jsは、強力でシンプルなJavaScript HTML5キャンバスライブラリです。 Fabricは、キャンバス要素の上に対話的なオブジェクトモデルを提供します。 Fabricには、SVGからキャンバスへの変換(およびキャンバスからSVGへの変換)のパーサーもあります。

(公式文章を翻訳)

詳細やチュートリアル、デモは公式に沢山あるので是非是非ご確認ください!

fabricjs.com

fabricjs.com


Fabric.jsをインストールする

ここからが本題です。
まずはNuxtプロジェクトにFabric.jsをご使用のパッケージマネージャを使用してインストールします。

npm install fabric
yarn add fabric
pnpm install fabric


初期設定をする

ページまたはコンポーネント内でFabric.jsをインポートし、初期設定を行います。
canvasタグにidを設定してdocument.querySelectorなどで取得する方法もありますが、Nuxt的にはrefを使ったほうが良いのかなと思います。
上記で取得したElementをもとにnew fabric.Canvasでインスタンスを作成します。
今後は作成したインスタンスに対して必要な要素を追加していく形となります。

<template>
  <canvas ref="canvasElement" />
</template>
<script setup lang="ts">
  import { fabric } from 'fabric'

  const canvasElement = ref<HTMLCanvasElement>()
  const canvas = computed(
    () =>
      new fabric.Canvas(canvasElement.value!, {
        preserveObjectStacking: true,
      })
  )
</script>

preserveObjectStackingはCanvas内のオブジェクトを選択した際に、そのオブジェクトを最前面にさせないオプションとなります。
複数オブジェクトを配置する際の表示順は結構意識する箇所だとおもうので、必要があれば設定してください。

Canvasのサイズを設定する

canvasタグの属性にwidthとheightがあり、こちらを設定することでCanvasのサイズを変更することができます。
デフォルトではwidthは300px、heightは150pxとなっているため、変更が必要な場合は必ず設定してください。

<canvas ref="canvasElement" :width="500" :height="200" />

もしくは先ほど作成したインスタンスに設定することも可能です。

canvas.value.setWidth(500).setHeight(200)


お絵描きできるようにしてみる

ユーザがWeb上でお絵描きできる設定も簡単に実現できます。
先ほどのインスタンス及びサイズ設定と合わせて確認してください。

  onMounted(() => {
    canvas.value.setWidth(500).setHeight(200)
    canvas.value.isDrawingMode = true
  })

isDrawingModeをtrueにすることでユーザが線を描けるようになりました。
ボタンなどを別途配置して、ペンの太さや色等を変えれるようにすればさらにリッチになります。

fabric test

※canvasが背景色と重なり見づらいので1px の border solid をスタイルしています。

Canvasにオブジェクトを追加する

お絵描き以外にもオブジェクトを追加して描画することができます。
オブジェクトは選択することができ、移動や拡大縮小回転といった操作もすることができます(オプションで操作できなくすることも可能です)。

お絵描きで追加した線もオブジェクト化して操作することができるので描いた絵をダウンロードすることもできます。 また、図形だけはなく画像も取り込んでオブジェクト化することができるので、画像の加工なども簡単にできます。
ただ別オリジンの画像をtoDataURL等でデータ化してダウンロードしたりする場合、ご使用の環境によってはCORSによるキャンバスの汚染が発生します。対応策としては環境設定を見直したり、crossOrigin: 'anonymous' を設定することにより回避できますが、今回は説明を見送らせていただきます。

<template>
  <canvas ref="canvasElement" />
  <button type="button" @click="addCircle()">addCircle</button>
  <button type="button" @click="addRect()">addRect</button>
  <button type="button" @click="addImage()">addImage</button>
  <button type="button" @click="toSelectMode()">toSelectMode</button>
  <button type="button" @click="toDrawMode()">toDrawMode</button>
</template>
<script setup lang="ts">
  import { fabric } from 'fabric'

  const canvasElement = ref<HTMLCanvasElement>()
  const canvas = computed(
    () =>
      new fabric.Canvas(canvasElement.value!, {
        preserveObjectStacking: true,
      })
  )
  onMounted(() => {
    canvas.value.isDrawingMode = true
    canvas.value.setWidth(500).setHeight(500)
  })

  const addCircle = () => {
    canvas.value.add(
      new fabric.Circle({
        left: 50,
        top: 50,
        fill: 'blue',
        radius: 30,
      })
    )
  }
  const addRect = () => {
    canvas.value.add(
      new fabric.Rect({
        left: 100,
        top: 100,
        fill: 'red',
        width: 20,
        height: 20,
      })
    )
  }
  const addImage = () => {
    fabric.Image.fromURL(
      'https://source.unsplash.com/random?orange',
      function (oImg) {
        oImg.scale(0.1)
        canvas.value.add(oImg)
      }
    )
  }
  const toSelectMode = () => {
    canvas.value.isDrawingMode = false
  }
  const toDrawMode = () => {
    canvas.value.isDrawingMode = true
  }
</script>

fabric test

※addCircleボタンを押下することで円のオブジェクトを追加します
※addRectボタンを押下することで四角形のオブジェクトを追加します
※addImageボタンを押下することで外部画像のオブジェクトを追加します
※toSelectModeボタンを押下することでオブジェクト選択モードになります
※toDrawModeボタンを押下することでお絵描きモードになります

まとめ

今回はインスタンスに直接オブジェクトを追加していましたが、
実際使用するときはレイヤーを別途定義してそのレイヤーに対してオブジェクトの追加や削除を実施、最後にそのレイヤーをCanvasに反映するほうが適切かと思われます。
階層構造を意識して実装したほうが、より複雑な要求仕様にも耐えれるはずです。

Nuxt3とFabric.jsでサクッとCanvasの実装ができることが伝わったでしょうか……?今回の記事で、少しでもイメージが伝われば幸いです。
※実際はFabric.jsの公式とにらめっこする日々が続くと思います(笑)
最後までお読みいただきありがとうございました。


現在アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています。
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。
hrmos.co