Nuxt, Meet Particles

mtpiercey

Matthew Piercey

Posted on April 14, 2020

Nuxt, Meet Particles

This article is part of a series on my experiences with Nuxt.js that I built into the nuxt-toolkit by OverScore Media

GitHub logo overscore-media / nuxt-toolkit

A bunch of useful example code snippets for use with Nuxt.js

See a live example at https://nuxt-toolkit.overscore.media! :]


Ah, particle effects. Wondrous things, really. And I can think of no better particle effects library for the web (that isn't something related to game development or 3D rendering) than Particles.JS.

GitHub logo VincentGarreau / particles.js

A lightweight JavaScript library for creating particles

particles.js

A lightweight JavaScript library for creating particles.


Demo / Generator

particles.js generator

Configure, export, and share your particles.js configuration on CodePen:
http://vincentgarreau.com/particles.js/

CodePen demo:
http://codepen.io/VincentGarreau/pen/pnlso


Usage

Load particles.js and configure the particles:

index.html

<div id="particles-js"></div>

<script src="particles.js"></script>
Enter fullscreen mode Exit fullscreen mode

app.js

/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
particlesJS.load('particles-js', 'assets/particles.json', function() {
  console.log('callback - particles.js config loaded');
});
Enter fullscreen mode Exit fullscreen mode

particles.json

{
  "particles": {
    "number": {
      "value": 80,
      "density": {
        "enable": true,
        "value_area": 800
      }
    },
    "color": {
      "value": "#ffffff"
    },
    "shape": {
      "type": "circle",
      "stroke": {
        "width": 0,
        "color": "#000000"
      },
      "polygon": {
        "nb_sides": 5
      },
      "image": {
        "src": 
Enter fullscreen mode Exit fullscreen mode

Now, how does one go about implementing this awesome library into one's Nuxt project? Sure, there are at least a few Vue libraries that work with Particles, but I was able to hack together a complete component without using any other libraries.

Here's the Code

In its entirety, this is my implementation, inspired by https://www.npmjs.com/package/vue-particles-generator and https://github.com/creotip/vue-particles.

<template>
  <div
    :id="id"
    class="particles-js"
    :color="color"
    :particleOpacity="particleOpacity"
    :linesColor="linesColor"
    :particlesNumber="particlesNumber"
    :shapeType="shapeType"
    :particleSize="particleSize"
    :linesWidth="linesWidth"
    :lineLinked="lineLinked"
    :lineOpacity="lineOpacity"
    :linesDistance="linesDistance"
    :moveSpeed="moveSpeed"
    :movementDirection="movementDirection"
    :hoverEffect="hoverEffect"
    :hoverMode="hoverMode"
    :clickEffect="clickEffect"
    :clickMode="clickMode"
  ></div>
</template>
<script>
/* eslint-disable */
export default {
  props: {
    color: {
      type: String,
      default: '#dedede'
    },
    particleOpacity: {
      type: Number,
      default: 1.0
    },
    particlesNumber: {
      type: Number,
      default: 80
    },
    shapeType: {
      type: String,
      default: 'circle'
    },
    particleSize: {
      type: Number,
      default: 4
    },
    linesColor: {
      type: String,
      default: '#dedede'
    },
    linesWidth: {
      type: Number,
      default: 1
    },
    lineLinked: {
      type: Boolean,
      default: true
    },
    lineOpacity: {
      type: Number,
      default: 0.4
    },
    linesDistance: {
      type: Number,
      default: 150
    },
    moveSpeed: {
      type: Number,
      default: 3
    },
    movementDirection: {
      type: String,
      default: 'bottom-left'
    },
    hoverEffect: {
      type: Boolean,
      default: false
    },
    hoverMode: {
      type: String,
      default: 'grab'
    },
    clickEffect: {
      type: Boolean,
      default: false
    },
    clickMode: {
      type: String,
      default: 'push'
    }
  },
  data () {
    return {
      id: 'particles-instance-' + Math.floor(Math.random() * 5000)
    }
  },
  mounted () {
    require('particles.js')
    this.$nextTick(() => {
      this.initParticleJS(
        this.color,
        this.particleOpacity,
        this.particlesNumber,
        this.shapeType,
        this.particleSize,
        this.linesColor,
        this.linesWidth,
        this.lineLinked,
        this.lineOpacity,
        this.linesDistance,
        this.moveSpeed,
        this.movementDirection,
        this.hoverEffect,
        this.hoverMode,
        this.clickEffect,
        this.clickMode
      )
    })
  },
  methods: {
    initParticleJS (
      color,
      particleOpacity,
      particlesNumber,
      shapeType,
      particleSize,
      linesColor,
      linesWidth,
      lineLinked,
      lineOpacity,
      linesDistance,
      moveSpeed,
      movementDirection,
      hoverEffect,
      hoverMode,
      clickEffect,
      clickMode
    ) {
        particlesJS(this.id, {
          "particles": {
            "number": {
              "value": particlesNumber,
              "density": {
                "enable": true,
                "value_area": 800
              }
            },
            "color": {
              "value": color
            },
            "shape": {
            // circle, edge, triangle, polygon, star, image
              "type": shapeType,
              "stroke": {
                "width": 0,
                "color": "#192231"
              },
              "polygon": {
                "nb_sides": 5
              }
            },
            "opacity": {
              "value": particleOpacity,
              "random": false,
              "anim": {
                "enable": false,
                "speed": 1,
                "opacity_min": 0.1,
                "sync": false
              }
            },
            "size": {
              "value": particleSize,
              "random": true,
              "anim": {
                "enable": false,
                "speed": 40,
                "size_min": 0.1,
                "sync": false
              }
            },
            "line_linked": {
              "enable": lineLinked,
              "distance": linesDistance,
              "color": linesColor,
              "opacity": lineOpacity,
              "width": linesWidth
            },
            "move": {
              "enable": true,
              "speed": moveSpeed,
              "direction": movementDirection,
              "random": false,
              "straight": false,
              "out_mode": "out",
              "bounce": false,
              "attract": {
                "enable": false,
                "rotateX": 600,
                "rotateY": 1200
              }
            }
          },
          "interactivity": {
            "detect_on": "canvas",
            "events": {
              "onhover": {
                "enable": hoverEffect,
                "mode": hoverMode
              },
              "onclick": {
                "enable": clickEffect,
                "mode": clickMode
              },
              "onresize": {
                "enable": true,
                "density_auto": true,
                "density_area": 400
              }
            },
            "modes": {
              "grab": {
                "distance": 140,
                "line_linked": {
                  "opacity": 1
                }
              },
              "bubble": {
                "distance": 400,
                "size": 40,
                "duration": 2,
                "opacity": 8,
                "speed": 3
              },
              "repulse": {
                "distance": 200,
                "duration": 0.4
              },
              "push": {
                "particles_nb": 4
              },
              "remove": {
                "particles_nb": 2
              }
            }
          },
          "retina_detect": true
        })
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Well, that was a doozy! Anyway, to use it, do something like this (don't miss the <client-only></client-only>:

<template>
<!-- -->
  <client-only>
    <Particles
      color="#DCBA8F"
      :particles-number="100"
      shape-type="star"
      :particle-size="3"
      movement-direction="top"
      lines-color="#dedede"
      :line-linked="false"
      :move-speed="0.75"
    />
  </client-only>
<!-- -->
</template>

<script>
import Particles from '~/components/Particles.vue'

export default {
  components: {
    Particles
  }
}
</script>

<style lang="scss">
div[id^="particles-instance-"] {
  height: 100vh !important;
  width: 100vw !important;
  position: fixed !important;
  top: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  background: rgba($color: #05114e, $alpha: 0.4);
  z-index: 2 !important;
}
</style>
Enter fullscreen mode Exit fullscreen mode

The above code gives you a fullscreen particles background. Mixed with something like this (with a background of ~assets/img/background.png):

.hero-background {
  height: 100vh !important;
  width: 100vw !important;
  position: fixed !important;
  top: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  background-size: cover !important;
  background-repeat: no-repeat !important;
  background-blend-mode: overlay !important;
  background-attachment: fixed !important;
  background-position: fixed !important;
  background: rgba($color: #05114e, $alpha: 0.4);
  background-image: url("~assets/img/background.png") !important;
  z-index: 1 !important;
}
Enter fullscreen mode Exit fullscreen mode

you'd get a nice overlay. There are a ton of options, really; it's all CSS past this point. https://vincentgarreau.com/particles.js/ is your friend when it comes to checking out what changing props does.

Hope this was helpful; enjoy! Stay safe and keep on coding!

💖 💪 🙅 🚩
mtpiercey
Matthew Piercey

Posted on April 14, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Nuxt, Meet Particles
nuxt Nuxt, Meet Particles

April 14, 2020