wcochran
wcochran

Reputation: 10896

Does canvas have a display event handler?

I am used to using GLUT's PostRedisplay and (App|UI)Kit's setNeedsDisplay methods for requesting a new display event to be posted to the event queue when the app wishes to redraw a scene. I haven't found a counterpart with HTML5's Canvas element. For example, I am currently just calling my display() function directly when I want to redraw to the canvas:

function mouseMove(event) {
      if (mouseDrag) {
          // update camera position
          display();
      }
  }

The display() function renders the scene (which can be expensive):

function display() {
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      // issue WebGL calls to redraw scene
      gl.flush();
}

Most systems I am used to will coalesce multiple display events into one event if multiple rendering requests occur before the last rendering is finished. What I am doing above can be problematic if a long stream of display() calls outpace the rendering speed.

Anyway, what is the correct way to redraw canvas elements effeciently?

You can see the demo app I am working on here (if you have WebGL enabled).

Update : Following the answer below I now use RequestAnimationFrame and use the return value as a flag to indicate that a request has already been made. When the scene is rendered I clear the flag so further requests can be made:

var requestId = 0; // id of current requestAnimationFrame request (0 = no request)

function mouseMove(event) {
      if (mouseDrag) {
          // update camera position
          if (requestId)
            requestId = requestAnimationFrame(display);
          else
             console.log("request already in queued"); // test
      }
 }

function display() {
      requestId = 0;
      // redraw scene
}

Noting the log messages I get this does indeed coalesce multiple requests. This seems like a great approach. Are there any other solutions?

Upvotes: 1

Views: 485

Answers (1)

Stuart P. Bentley
Stuart P. Bentley

Reputation: 10675

You can use requestAnimationFrame(display) to set a callback (in this case, display) to be called at the next repaint.

It's up to you to only call it once when waiting for a repaint (at the repaint, it will do the callback for each call you made to requestAnimationFrame). It's also up to you to request another animation frame if you want to animate continuously.

Upvotes: 2

Related Questions