Reputation: 211
I am trying to create a class which has a canvas as an object in an attempt learn more about classes. I wrote the following code but it gives nothing but a blank screen.
class Canvas
{
constructor(canvasId = 'canvas', dimension = '2d', canvasWidth = document.body.clientWidth,canvasHeight = window.innerHeight,canvasDisplay = 'block',canvasOverflow = 'hidden')
{
// Initialize Canvas and Context variables
this.can = document.getElementById(canvasId);
this.ctx = this.can.getContext(dimension);
// Set canvas properties
this.can.width = canvasWidth;
this.can.height = canvasHeight;
this.can.style.display = canvasDisplay;
this.can.style.overflow = canvasOverflow;
this.count = 0;
}
display(ctx)
{
var ctx = ctx;
var scrollSS = new Image();
scrollSS.src = "../../../Assets/Media/Images/Scroll/ScrollSpriteSheet.png";
ctx.drawImage(scrollSS,0,0,102,345,10,0,canvas.width / 10,canvas.height);
}
animate(ctx)
{
var ctx = ctx;
console.log(this.count);
this.count++;
this.display(ctx)
requestAnimationFrame(this.animate(ctx));
}
}
var canvas = new Canvas();
console.log(canvas.ctx);
canvas.animate(canvas.ctx);
Am I doing something wrong?
Upvotes: 1
Views: 182
Reputation: 50684
Your issue is that you are calling animate()
again and again within your requestAnimationFrame()
method. You instead need to let JS call the function animate
for you when requestAnimationFrame() decides to do so.
This means you need to pass the animate
function into requestAnimationFrame
, not the actual function call (because when you call the function, you're really passing through its return value):
requestAnimationFrame(this.animate.bind(this));
Since JS will handle the calling of the animate
method, the this
inside of animate()
(when invoked) will not be your Canvas
object, but rather the window
. To make this
refer to your Canvas
object you'll need to .bind(this)
to your animate
function. The above is equivalent to using an arrow function:
requestAnimationFrame(() => this.animate());
Your other issue is that you're trying to display the image before it has loaded. You firstly need to load the image and then display it. If your image is going to stay the same, I recommend you load it before you draw, rather than loading it every time you want to redraw (see second code snippet).
Also, ctx
is part of your canvas instance. Each canvas object will have a .ctx
property as it is defined in the constructor. So, there is no need to pass it through as an argument to animate
or display
, as you can access it by using this.ctx
.
See example below (note the image is a temporary image):
class Canvas {
constructor(canvasId = 'canvas', dimension = '2d', canvasWidth = document.body.clientWidth, canvasHeight = window.innerHeight, canvasDisplay = 'block', canvasOverflow = 'hidden') {
// Initialize Canvas and Context variables
this.can = document.getElementById(canvasId);
this.ctx = this.can.getContext(dimension);
// Set canvas properties
this.can.width = canvasWidth;
this.can.height = canvasHeight;
this.can.style.display = canvasDisplay;
this.can.style.overflow = canvasOverflow;
this.count = 0;
}
display() {
var ctx = this.ctx;
var scrollSS = new Image();
scrollSS.src = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRha_-J-uQR_8pUrUQOiPYZ_JXRoqfoqDt8BO8icSfkworyz9woQQ&s";
scrollSS.addEventListener('load', e => {
ctx.drawImage(scrollSS, 0, 0, 102, 345, 10, 0, this.can.width / 10, this.can.height);
});
}
animate() {
this.count++;
this.display();
requestAnimationFrame(this.animate.bind(this));
}
}
var canvas = new Canvas();
canvas.animate();
<canvas id="canvas" style="border: 1px solid black"></canvas>
Here is an approach using Promises that you might want to take if you only need to load the one image:
class Canvas {
constructor(canvasId = 'canvas', dimension = '2d', canvasWidth = document.body.clientWidth, canvasHeight = window.innerHeight, canvasDisplay = 'block', canvasOverflow = 'hidden') {
// Initialize Canvas and Context variables
this.can = document.getElementById(canvasId);
this.ctx = this.can.getContext(dimension);
// Set canvas properties
this.can.width = canvasWidth;
this.can.height = canvasHeight;
this.can.style.display = canvasDisplay;
this.can.style.overflow = canvasOverflow;
this.count = 0;
}
loadImage(url) {
var img = new Image();
img.src = url;
return new Promise((resolve) => {
img.addEventListener('load', function(e) {
resolve(this);
});
});
}
display(img) {
var ctx = this.ctx;
ctx.drawImage(img, 0, 0, 102, 345, 10, 0, this.can.width / 10, this.can.height);
}
animate(img) {
this.count++;
this.display(img);
requestAnimationFrame(this.animate.bind(this, img));
}
}
var canvas = new Canvas();
var img_url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRha_-J-uQR_8pUrUQOiPYZ_JXRoqfoqDt8BO8icSfkworyz9woQQ&s";
canvas
.loadImage(img_url)
.then(function(image) {
canvas.animate(image);
});
<canvas id="canvas" style="border: 1px solid black"></canvas>
Upvotes: 2