🎨

Vue・NuxtでCanvas要素を使った処理をする方法・vue-konva & konvaの使い方まとめ

2023/10/03に公開

こんにちは、AIQ株式会社のフロントエンドエンジニアのまさぴょんです!

今回は、Vue・NuxtでCanvas要素を使った処理をする方法・vue-konva & konvaの使い方について解説します。

Vue・Nuxtで、Canvas処理をするにはどうすればいいのか?

今回、プロジェクトの要件で、服のイメージ画像の上に、Print位置を示す赤い四角形を描画するようなCanvas処理が必要になりました。

このような服のイメージ画像に。。。

このようなPrint位置を示す赤い四角形を描画する感じの実装です。

以前に、JavaScriptで、Canvas操作をする方法は、こちらの記事で、ご紹介しました。
https://zenn.dev/aiq_dev/articles/581c83ec934c72

このような「Canvas処理を Vue・Nuxt上でするには、どうすればいいのか?」と疑問に思い。
Vue・Nuxtで、Canvas要素を使った処理をするなら、どんな方法があるのか調べていたところ、
VueでCanvas要素を使用するなら、vue-konva & konva.jsがよさそうなので、実際に使ってみた結果のまとめ記事になります。

Konva(Konva.js)とは?

Knova.jsは、JavaScriptで、グラフィックを描く際に使用するCanvas機能のフレームワークです。

詳細は、Konva 公式の概要説明が参考になります。

Konva は、デスクトップおよびモバイル アプリケーションのキャンバスの対話性を可能にすることで 2D コンテキストを拡張する HTML5 Canvas JavaScript フレームワークです。
Konva は、デスクトップおよびモバイル アプリケーションの高性能アニメーション、トランジション、ノードのネスト、階層化、フィルタリング、キャッシュ、イベント処理などを可能にします。
引用元: Konva Framework Overview

vue-konvaとは?

vue-konvaとは、グラフィックスや図形を描画および操作するためのフレームワークであるKnova.jsをVue.jsフレームワーク上で使いやすくするためのライブラリです。

具体的には、vue-konvaを使用することで、Vueコンポーネント内でキャンバス上に図形を描画したり、アニメーションを作成したりすることができます。

また、vue-konvaは、Vueのコンポーネントとして、Knova.jsの機能を提供してくれているので、Vue.jsのプロジェクトで、Knova.jsを使いたい時に、利用しやすくしてくれます。

その他の詳細事項は、vue-konvaのGetting startedから説明を引用します。

Vue Konva は、Vue を使用して複雑なキャンバス グラフィックを描画するための JavaScript ライブラリです。
これはKonvaフレームワークへの宣言型およびリアクティブなバインディングを提供します。
vue-konvaのすべてのコンポーネントは、接頭辞「v-」が付いた同じ名前のコンポーネントに対応します。
Konvaオブジェクトで使用できるすべてのパラメータは、対応するvue-konvaコンポーネントのpropに設定として追加できます。
コア シェイプは次のとおりです: v-rect, v-circle, v-ellipse, v-line, v-image, v-text, v-text-path, v-star, v-label, v-path, v-regular-polygon.
カスタム形状を作成することもできます。
引用元: Getting started with vue and canvas via Konva

Vue・Nuxt2系に、vue-konva & konva.js を導入する(環境構築)

前提条件として、Vue.jsのバージョン 2.4 以降が必要です。

1. konva.js & vue-konva をインストールする

Vue3系の場合は、次のようにして、konva.js & vue-konva をインストールします。

bash
npm install vue-konva konva --save

# または

yarn add vue-konva konva

Vue2系の場合は、次のようにして、konva.js & vue-konva をインストールします。

bash
npm install vue-konva@2 konva --save

# または

yarn add vue-konva@2 konva

2. plugins/vue-konva.jsファイルを作成する

ライブラリのインストールが完了したら、plugins/vue-konva.jsファイルを作成します。

plugins/vue-konva.js
import Vue from 'vue'
import VueKonva from 'vue-konva'

Vue.use(VueKonva)

3. nuxt.config.jsファイルのpluginsキー内にファイルパスを追加

vue-konva.jsファイルのPluginの作成ができたら、nuxt.config.jspluginsキーに設定を追加します。

nuxt.config.js
  plugins: [
    // vue-konva は、 Canvasライブラライである konva.js を Vue で扱えるようにした Vue用のライブラリです。
    {
      src: '~/plugins/vue-konva',
      ssr: false, // SSRはしない設定
    },

4. Sample Componentを作って表示確認をする

vue-konvaのREADME.mdでも紹介されているSample Componentで表示のテストをします。

https://github.com/konvajs/vue-konva

SampleCodeは、次のとおりです。

components/ui-elements/canvas/CanvasTest.vue
<template>
  <!-- 1. Stage: Canvasの最上位の領域 -->
  <v-stage :config="configKonva">
    <!-- 2. 1つのレイヤー(層)を作成する -->
    <v-layer>
      <!-- 3. Canvas内に、円を描く -->
      <v-circle :config="configCircle"></v-circle>
    </v-layer>
  </v-stage>
</template>
<script>
export default {
  data() {
    return {
      /** Canvasの最上位の領域を設定する */
      configKonva: {
        width: 200,
        height: 200,
      },
      /** 円の設定値 */
      configCircle: {
        x: 100,
        y: 100,
        radius: 70,
        fill: "red",
        stroke: "black",
        strokeWidth: 4,
      },
    };
  },
};
</script>

SampleComponentを表示すると、次のような赤丸がレンダリングされるはずです。

これで、環境構築から、動作確認までが完了しました。

Print位置をCanvasで描くComponentを作成する

それでは、今回の本題であるPrint位置をCanvasで描くComponentの作成に入っていきます。

完成したSampleCodeは、次のとおりです。

今回作成したCanvas Componentでの処理の要点をまとめると、次のとおりです。

Canvas Componentでの処理の要点まとめ
  1. Canvasの最上位の領域であるStage領域を設定する。
    • 設定は、Propsで受け取れる。
  2. Canvasの1つのレイヤー(層)を作成する。
  3. Canvas上に、ベースとなる画像を表示する。
    • 設定は、Propsで受け取れる。
    • 画像に関しては、Image Instanceを作成する。
    • Image Instanceを作成するために、クライアントサイドonlyのComponentとなる。
  4. 赤い四角形をCanvas上に表示する。
    • 設定は、Propsで受け取れる。
components/ui-elements/canvas/CanvasTest.vue
<template>
  <!-- no-ssr タグで、クライアントサイドでのみのレンダリングを指定する -->
  <no-ssr>
    <div>
      <!-- 1. Stage: Canvasの最上位の領域 -->
      <v-stage :config="stageConfig">
        <!-- 2. 1つのレイヤー(層)を作成する -->
        <v-layer>
          <!-- 3. ベースとなる画像を表示する -->
          <v-image :config="imageConfig" />
          <!-- 4. 赤い四角形を表示する -->
          <v-rect
            v-for="(rect, index) in squareConfigList"
            :key="index"
            :config="rect"
          />
        </v-layer>
      </v-stage>
    </div>
  </no-ssr>
</template>

<script>
export default {
  props: {
    /** Canvasの領域設定・Object */
    canvasStageConfig: {
      type: Object,
      default: () => {
        return { width: 278, height: 278 }
      },
    },
    /** 表示するベース Image 画像の設定情報・Object */
    imageConfigObj: {
      type: Object,
      default: () => {
        return {
          /** 表示する 商品画像の URL */
          image:
            'https://www.photolibrary.jp/mhd6/img326/450-20140125170616151742.jpg',
          /** 画像の幅 */
          width: 200,
          /** 画像の高さ */
          height: 200,
          /** Canvas上の X座標 */
          x: 0,
          /** Canvas上の Y座標 */
          y: 0,
        }
      },
      /** 必須・Props */
      required: true,
    },
    /** 四角形の設定情報・Object を 格納した List */
    squareList: {
      type: Array,
      default: () => {
        return [
          {
            /** Canvas上の X座標 */
            x: 75,
            /** Canvas上の Y座標 */
            y: 60,
            /** 四角形の幅 */
            width: 50,
            /** 四角形の高さ */
            height: 50,
            /** 塗りつぶし色: 半透明な赤色 */
            fill: 'rgba(255, 0, 0, 0.5)',
          },
        ]
      },
      /** 必須・Props */
      required: true,
    },
  },
  data() {
    return {
      /** Canvas の 領域設定 */
      stageConfig: this.canvasStageConfig,
      /** 表示する Base 画像の 設定 Object */
      imageConfig: {
        /** Image Instance を Set する */
        image: null,
        /** 画像の幅 */
        width: this.imageConfigObj.width,
        /** 画像の高さ */
        height: this.imageConfigObj.height,
        /** Canvas上の X座標 */
        x: this.imageConfigObj.x,
        /** Canvas上の Y座標 */
        y: this.imageConfigObj.y,
      },
      /** 四角形の設定を格納する配列 */
      squareConfigList: this.squareList,
    }
  },
  computed: {},
  watch: {},
  methods: {
    /**
     * NOTE: createImageObject
     * => Propsで受け取った Image画像を設定した Image・Object を生成する Func
     */
    createImageObject() {
      /** Canvasに合成したい画像のPath */
      const imagePath = this.imageConfigObj.image
      console.log('imagePath', imagePath)
      /** Image Instance を作成する */
      let image = null
      /** クライアント側でしか処理させない */
      if (process.client) {
        image = new Image()
        /** Image Instance に 画像ファイルのPathを設定する */
        image.src = imagePath
      }
      console.log('Image Instance', image)
      return image
    },
  },
  /** LifeCycleHook: CreatedTiming */
  created() {
    // Data & Props を確認する
    console.log('this.$data', this.$data)
    console.log('this.$props', this.$props)
    /** Image・Instance を作成する */
    const imageInstance = this.createImageObject()
    this.imageConfig.image = imageInstance
  },
}
</script>

<style></style>

SampleCodeを実行すると、PropsのDefault値だけでも、次のようなベースとなる画像イメージの上に、赤い四角形をレンダリングした表示がでてきます。

まとめ

vue-konva & konvaを初めて使いましたが、使い勝手がよかったので、おすすめです。

個人で、Blogもやっています、よかったら見てみてください。

https://masanyon.com/

参考・引用

https://zenn.dev/aiq_dev/articles/581c83ec934c72

https://github.com/konvajs/vue-konva

https://konvajs.org/docs/vue/index.html

https://konvajs.org/docs/overview.html

https://qiita.com/s-tanoue/items/43270a462407e3561cb8

https://qiita.com/h13a/items/95335b8b8bc42008a72a

注意事項

この記事は、AIQ 株式会社の社員による個人の見解であり、所属する組織の公式見解ではありません。

求む、冒険者!

AIQ株式会社では、一緒に働いてくれるエンジニアを絶賛、募集しております🐱🐹✨

エンジニア視点での我が社のおすすめポイント

  1. フルリモート・フルフレックスの働きやすい環境!
    • 前の会社でアサインしてた現場は、フル出社だったので、ありがたすぎる。。。
    • もうフル出社には、戻れなくなります!
  2. 経験豊富なエンジニアの先輩方
    • 私は、3年目の駆け出しエンジニアなので、これが、かなりありがたいです!
  3. 自社開発とR&D(受託開発)を両方している会社なので、経験できる技術が多い。
    • 自社のProduct開発と、他社からの受託案件で、いろいろな技術を学ぶことができます。
  4. AI関連の最新の技術に触れられるチャンスが多い。
    • 自社で特許を持つほど、AI技術に強い会社で、プロファイリングを得意とした技術体系があります。
    • ChatGPTを自社アプリに搭載など、AIトレンドも、もちろん追っており、最新の技術に触れられるチャンスが多いです。
  5. たまに、札幌ラボ(東京から札幌) or 東京オフィス(札幌から東京)に出張で行ける!
    • 東京と、札幌に2拠点ある会社なので、会合などで集まる際に、出張で行けます。

採用技術 (一部抜粋)

  • FrontEnd: TypeScript, JavaScript, React.js, Vue.js, Next.js, Nuxt.js など
  • BackEnd: Node.js, Express,Python など
  • その他技術: Docker, AWS, Git, GitHub など

エントリー方法

  1. 私達と東京か札幌で一緒に働ける仲間を募集しています。
    詳しくは、Wantedly (https://www.wantedly.com/companies/aiqlab)を見てみてください。

Webエンジニア向け説明

https://www.wantedly.com/projects/1089410

データサイエンティスト向け説明

https://www.wantedly.com/projects/1089406

人事に直通(?)・ご紹介Plan(リファラル採用)

私経由で、ご紹介もできますので、興味のある方や気軽にどんな会社なのか知りたい方は、X(旧:Twitter)にて、DMを送ってくれても大丈夫です。
https://twitter.com/masanyon1212

AIQ Tech Blog (有志)

Discussion