views:

973

answers:

3

I am drawing a graph on a <canvas> that requires expensive calculations. I would like to create an animation (when moving the mouse across the canvas) where the graph is unchanging, but some other objects are drawn over it.

Because the canvas will have to be redrawn a lot, I don't want to perform the calculations to render the graph for every frame. How can I draw the graph once, save it, and then use the saved rendering to redraw subsequent frames of the animation, so that the expensive calculations only have to happen once & all I have to redraw is the much simpler animation layer?

I tried drawing the graph on a second canvas & then using ctx.drawImage() to render it onto the main canvas, but drawing on the canvas doesn't seem to work unless it's in the dom & not display:none;. Do I have to do something hacky like position the temp canvas out of view, or is there a cleaner way to do this?

+1  A: 

I had to make a few changes to the flot.js charting library. I'm 99% sure that it uses overlapping canvases. There's a chart layer and an overlay layer. You could look at the source code.

Nosredna
A: 

How about drawing your graph the first time on your canvas and then

var imdata = ctx.getImageData(0,0,width,height);

and then

ctx.putImageData( imdata, 0,0);

for the rest of the rendering.

Clint
Would that work in IE? Does excanvas support the imagedata functionality of canvas?
Nosredna
No and no. But this was a question about <canvas> which IE does not support.
Clint
Good point. That's true if your target is Adobe AIR, Mobile Safari, Titanium, or any other sane Platform where you can shed your IE worries.
Nosredna
+6  A: 

You need to use at least 2 canvases : one with the complex drawing, and the second, on top of the first (with the same size, positioned in absolute), with the animated shapes. This method will work on IE, and getImageData doesn't work with ExCanvas.

Every library which does complex drawings on canvases use this method (Flot and others).

<div style="width: 600px; height: 300px; position: relative;" id="container">
  <canvas class="canvas" style="position: absolute; left: 0px; top: 0px;" width="600" height="300"/>
  <canvas class="overlay" style="position: absolute; left: 0px; top: 0px;" width="600" height="300"/>
</div>
Fabien Ménager
I didn't know this - and never saw anything about this in all the Canvas docs I have read. Good note.
Paul Chernoch