I have an object that i want to do drawing on a canvas. It will use requestAnimationFrame
to start a game loop:
Contoso.ts
class Contoso
{
//private ctx: CanvasRenderingContext2D;
Initialize(ctx: CanvasRenderingContext2D) {
//this.ctx = ctx;
Render();
}
Render() {
//...snip doing any actual drawing for the purpose of this question
requestAnimationFrame(this.Render);
}
}
app.ts
var contoso: Contoso;
contoso = new Contoso();
contoso.Initialize(canvas);
The first time someone calls Initialize
, the requestAnimationFrame
manages to correctly call Render
.
The second time requestAnimationFrame
calls Render
, the this.Render
is undefined
and it crashes.
It's almost as though the object was destroyed after the initial call to Initialize
.
What is going on?
The requestAnimationFrame() method tells the browser to run a callback function right before the next repaint happens. It's particularly useful when using JavaScript for animations and repeating UI updates.
requestAnimationFrame() is much more efficient than setTimeout() or setInterval() , and the result is smoother and more accurate (just check the provided demo and the consumed CPU).
The requestAnimationFrame method returns an integer ID which can be used to cancel the queued request using the cancelAnimationFrame(id) method. The animation callback function can also accept a timestamp value, which is the time elapsed in milliseconds since the web page was loaded.
As now you know that the rAF is a Web API, that means the callback will be called asynchronously. Unlike setInterval , requestAnimationFrame does not accept delay argument, instead, it only calls the callback function when the browser is ready to perform the next paint operation.
You've lost this
context. Two possible fixes:
class Contoso
{
/* ... */
// Use () => syntax so Render always gets 'this' context
// from the class instance
Render = () => {
//...snip doing any actual drawing for the purpose of this question
requestAnimationFrame(this.Render);
}
}
The alternate fix is probably slightly clearer, but has the downside of making a lot more allocations (you probably don't want to allocate 1 closure per frame!)
Render() {
//...snip doing any actual drawing for the purpose of this question
requestAnimationFrame(() => this.Render);
}
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