-2

I've been trying to use some of the particle designs on this website https://speckyboy.com/particle-animation-code-snippets/ but failing. I've included the stylesheet and javascript files. I'm not sure what i'm missing. Also, this does not work on a django project as well. Are there restrictions between these particle design and django?

ERROR:

Uncaught TypeError: Cannot read property 'getContext' of null at javascript.js:2

var canvas = document.querySelector("#scene"),
  ctx = canvas.getContext("2d"),
  particles = [],
  amount = 0,
  mouse = {
    x: 0,
    y: 0
  },
  radius = 1;

var colors = ["#468966", "#FFF0A5", "#FFB03B", "#B64926", "#8E2800"];

var copy = document.querySelector("#copy");

var ww = canvas.width = window.innerWidth;
var wh = canvas.height = window.innerHeight;

function Particle(x, y) {
  this.x = Math.random() * ww;
  this.y = Math.random() * wh;
  this.dest = {
    x: x,
    y: y
  };
  this.r = Math.random() * 5 + 2;
  this.vx = (Math.random() - 0.5) * 20;
  this.vy = (Math.random() - 0.5) * 20;
  this.accX = 0;
  this.accY = 0;
  this.friction = Math.random() * 0.05 + 0.94;

  this.color = colors[Math.floor(Math.random() * 6)];
}

Particle.prototype.render = function() {
  this.accX = (this.dest.x - this.x) / 1000;
  this.accY = (this.dest.y - this.y) / 1000;
  this.vx += this.accX;
  this.vy += this.accY;
  this.vx *= this.friction;
  this.vy *= this.friction;

  this.x += this.vx;
  this.y += this.vy;

  ctx.fillStyle = this.color;
  ctx.beginPath();
  ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
  ctx.fill();

  var a = this.x - mouse.x;
  var b = this.y - mouse.y;

  var distance = Math.sqrt(a * a + b * b);
  if (distance < (radius * 70)) {
    this.accX = (this.x - mouse.x) / 100;
    this.accY = (this.y - mouse.y) / 100;
    this.vx += this.accX;
    this.vy += this.accY;
  }
}

function onMouseMove(e) {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
}

function onTouchMove(e) {
  if (e.touches.length > 0) {
    mouse.x = e.touches[0].clientX;
    mouse.y = e.touches[0].clientY;
  }
}

function onTouchEnd(e) {
  mouse.x = -9999;
  mouse.y = -9999;
}

function initScene() {
  ww = canvas.width = window.innerWidth;
  wh = canvas.height = window.innerHeight;

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.font = "bold " + (ww / 10) + "px sans-serif";
  ctx.textAlign = "center";
  ctx.fillText(copy.value, ww / 2, wh / 2);

  var data = ctx.getImageData(0, 0, ww, wh).data;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.globalCompositeOperation = "screen";

  particles = [];
  for (var i = 0; i < ww; i += Math.round(ww / 150)) {
    for (var j = 0; j < wh; j += Math.round(ww / 150)) {
      if (data[((i + j * ww) * 4) + 3] > 150) {
        particles.push(new Particle(i, j));
      }
    }
  }
  amount = particles.length;

}

function onMouseClick() {
  radius++;
  if (radius === 5) {
    radius = 0;
  }
}

function render(a) {
  requestAnimationFrame(render);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (var i = 0; i < amount; i++) {
    particles[i].render();
  }
};

copy.addEventListener("keyup", initScene);
window.addEventListener("resize", initScene);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onTouchMove);
window.addEventListener("click", onMouseClick);
window.addEventListener("touchend", onTouchEnd);
initScene();
requestAnimationFrame(render);
body {
  margin: 0;
  overflow: hidden;
  font-size: 0;
}

canvas {
  background: black;
  width: 100vw;
  height: 100vh;
}

input {
  width: 250px;
  height: 40px;
  line-height: 40px;
  position: absolute;
  bottom: 35px;
  left: calc(50% - 125px);
  background: none;
  color: white;
  font-size: 30px;
  font-family: arial;
  text-align: center;
  border: 1px solid white;
  background: rgba(255, 255, 255, 0.2);
}

p {
  position: fixed;
  left: 0;
  bottom: 5px;
  color: #fff;
  z-index: 10;
  font-size: 16px;
  font-family: Helvetica, Verdana, sans-serif;
  opacity: 0.5;
  width: 100%;
  text-align: center;
  margin: 0;
}
<!-- Edit the text with whatever you want :) -->
<!-- Works with emojis too ! -->
<link rel="stylesheet" href="stylesheet.css">
<script src="javascript.js"></script>
<canvas id="scene"></canvas>
<input id="copy" type="text" value="Hello Codepen ♥" />
<p>Click anywhere to change the radius of your mouse</p>
shrys
  • 5,381
  • 2
  • 15
  • 29
STOPIMACODER
  • 669
  • 4
  • 14

1 Answers1

2

The error you get says it all. You can't call .getContext() on a null context. In this case, canvas is null because the <script> tag is inserted before the <canvas> tag. Similarly, you cannot call .addEventListener() on copy because the copy element is after the <script> tag as well.

You have a few options, but the simplest is to invert their order.

<canvas id="scene"></canvas>
<input id="copy" type="text" value="Hello Codepen ♥" />

<!-- put this after the other tags -->
<script src="javascript.js"></script>

For future reference, take a close look at the error messages and look them up. I'm sure you could figure this out on your own if you take a little extra time to decipher it.

Jonathan Lam
  • 15,294
  • 14
  • 60
  • 85