{article.alt}

Nuxt.js、Contentブログでp5.jsを活用

Nuxt.js Contentのマークダウンファイル内に、p5.jsで作成した動的コンテンツを入れる方法に関する記事です。

開発環境の構築

node.jsのインストール

Node.jsとnpmのインストール。<<<公式のNode.jsサイト>>>からダウンロードしてインストールします。npmはNode.jsに同梱されています。

Nuxt.jsのプロジェクト作成

Nuxt.jsプロジェクトを作成します。

npx create-nuxt-app star-demo

ライブラリインストール

Nuxt Contentモジュールとp5.jsをインストールします。

npm install @nuxt/content p5

フロントエンドの構築

Componentファイルの作成

componentsディレクトリに新しいコンポーネントを作成します。ここでは、P5Component.vueという名前のコンポーネントを作成します。 "resizeCanvas" 関数を使うことでcanvasの幅を div タグの幅に合わせます。

<template>
  <div id="canvas-container" ref="canvasParent"></div>
</template>

<script>
import p5 from 'p5'

export default {
  data() {
    return {
      p5: null,
    }
  },
  mounted() {
    new p5(this.sketch, this.$refs.canvasParent)
  },
  methods: {
    sketch(p) {
      let stars = []
      let speed

      p.setup = () => {
        p.createCanvas(this.$refs.canvasParent.offsetWidth, p.windowHeight)
        for (let i = 0; i < 800; i++) {
          stars[i] = new Star(p);
        }
      }

      p.windowResized = () => {
        p.resizeCanvas(this.$refs.canvasParent.offsetWidth, p.windowHeight) //<div>タグの幅に合わせる
      }

      p.draw = function() {
        p.background(0)
        p.translate(p.width / 2, p.height / 2)
        for (let i = 0; i < stars.length; i++) {
          stars[i].update()
          stars[i].show()
        }
      }

      function Star() {
        this.x = p.random(-p.width, p.width)
        this.y = p.random(-p.height, p.height)
        this.z = p.random(p.width)
        this.pz = this.z
        this.color = p.color(p.random(255), p.random(255), p.random(255))

        this.update = function() {
          this.z = this.z - 10
          if (this.z < 1) {
            this.z = p.width
            this.x = p.random(-p.width, p.width)
            this.y = p.random(-p.height, p.height)
            this.pz = this.z
          }
        }

        this.show = function() {
          p.fill(this.color)
          p.noStroke()

          let sx = p.map(this.x / this.z, 0, 1, 0, p.width)
          let sy = p.map(this.y / this.z, 0, 1, 0, p.height)

          let r = p.map(this.z, 0, p.width, 16, 0)
          p.ellipse(sx, sy, r, r)

          let px = p.map(this.x / this.pz, 0, 1, 0, p.width)
          let py = p.map(this.y / this.pz, 0, 1, 0, p.height)

          this.pz = this.z

          p.stroke(this.color)
          p.line(px, py, sx, sy)
        }
      }
    }
  }
}
</script>

<style scoped>
  #canvas-container {
    width: 100%;
    height: 100vh;
  }
</style>

_slug.vueファイル作成

pagesディレクトリ内に_slug.vueファイルを作成します。これは、個々のマークダウンファイルを表示するための動的ルートを作成します。

<template>
  <article>
    <nuxt-content :document="article" />
  </article>
</template>

<script>

export default {
  async asyncData({ $content, params }) {
    const article = await $content(params.slug || 'index').fetch();

    return {
      article
    }
  }
}
</script>

.mdファイル作成

contentディレクトリを作成し、その中にマークダウンファイル(たとえば、example.md)を作成します。ここに記事の内容を書きます。 マークダウンファイル内でコンポーネントを指定するとき、ハイフン区切りのケバブケース(kebab-case)を使用してコンポーネントを指定することに注意してください。

---
title: Your Article Title
description: Your Article Description
---
<client-only>
  <p5-component />
</client-only>

デモ