Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use requestAnimationFrame with a TypeScript object?

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?

like image 699
Ian Boyd Avatar asked Feb 21 '14 03:02

Ian Boyd


People also ask

When can I use requestAnimationFrame?

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.

Is requestAnimationFrame better than setInterval?

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).

What does requestAnimationFrame return?

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.

Is requestAnimationFrame asynchronous?

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.


1 Answers

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);
   }
like image 81
Ryan Cavanaugh Avatar answered Sep 21 '22 21:09

Ryan Cavanaugh