I am experimenting with class based code. I create a class for the canvas and pass a component to it which is then rendered. The problem is that when the browser requests the animation frame the context is lost, and becomes undefined. I am looking for an explanation of why this is the case.
I am not concerned with best practice just with figuring out why the context is lost.
I have attached a link to the example on codepen.
http://codepen.io/BrianDGLS/pen/BoJorM?editors=001
Here is the JS code:
class Canvas {
constructor() {
this.canvas = document.getElementById('canvas');
this.context = this.canvas.getContext('2d');
this.width = this.canvas.width = window.innerHeight;
this.height = this.canvas.height = window.innerWidth;
this.components = [];
}
draw() {
this.context.clearRect(0, 0, this.width, this.height);
this.context.globalCompositeOperation = 'hard-light';
this.components.map(_ => _.render());
window.requestAnimationFrame(this.draw);
}
listeners() {
window.addEventListener('resize', () => {
this.width = this.canvas.width = window.innerHeight;
this.height = this.canvas.height = window.innerWidth;
}, false);
}
init() {
this.listeners();
this.draw();
}
}
class Utils {
randomNum(max, min) {
return Math.floor(max * Math.random()) + min;
}
color(opacity) {
return `hsla(${this.randomNum(360, 1)}, 70%, 60%, ${opacity})`;
}
}
const utils = new Utils();
const _canvas = new Canvas();
class Stars {
constructor(_) {
this.total = _.total;
this.spawn = [];
this.z = 300;
this.canvas = _.canvas;
this.xw = this.canvas.width * this.z;
this.xh = this.canvas.height * this.z;
}
create() {
while (this.spawn.length < this.total) {
this.spawn.push({
pos: [this.xw * Math.random() - this.canvas.width / 2 * this.z, this.xh * Math.random() - this.canvas.height / 2 * this.z, this.z],
vel: [0, 0, -2],
r: utils.randomNum(500, 100),
color: utils.color(1)
});
}
}
draw() {
for (let i = 0; i < this.spawn.length; ++i) {
let t = this.spawn[i];
let x = t.pos[0] / t.pos[2];
let y = t.pos[1] / t.pos[2];
if (x < -this.canvas.width / 2 || x > this.canvas.width / 2 || y < -this.canvas.height / 2 || y > this.canvas.height / 2 || t.pos[2] < 0) {
this.spawn.splice(i, 1);
--i;
continue;
}
this.canvas.context.beginPath();
this.canvas.context.fillStyle = t.color;
this.canvas.context.arc(x, y, t.r / t.pos[2], 0, Math.PI * 2, false);
t.pos[0] += t.vel[0];
t.pos[1] += t.vel[1];
t.pos[2] += t.vel[2];
this.canvas.context.fill();
}
}
render() {
this.create();
this.canvas.context.save();
this.canvas.context.translate(this.canvas.width / 2, this.canvas.height / 2);
this.draw();
this.canvas.context.restore();
}
}
_canvas.components.push(new Stars({
canvas: _canvas,
total: 200
}));
When you invoke draw()
via window.requestAnimationFrame(this.draw)
the scope in draw()
is bound to window
instead of Canvas
. Try binding the scope explicitly like this:
window.requestAnimationFrame(this.draw.bind(this));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With