HTML5 <canvas>
elements have a sort of save state mechanism, by repeatedly calling cxt.save()
and cxt.restore()
, where cxt
is the <canvas>
's "context", gotten by, for example, calling document.getElementById('my-canvas')
. However, I have not seen a way to save/restore to more than one state at a time. It seems that <canvas>
has access to multiple states, as calling restore
multiple times restores each respective "last" saved state.
Is there a way to jump back to before the "last" state without calling restore
multiple times? Also, is there a way to go "forward" through the states? This would probably be easier to do if we could give each state a name, but I could work with ID's, if I needed to. In the end it would probably look similar to Adobe Photoshop's "layers" concept.
I would also take an answer that saves each state to a different variable, or that can copy the context without creating a whole new <canvas>
. Copying functions like angular.copy
do not seem to work with contexts, possibly because they are not technically objects; I believe they inherit from interfaces.
Finally, is this efficient? I am aware of how graphics-intensive <canvas>
is, how taxing it can be on the client's computer. Is there a better way of manipulating the context without disrupting other parts of the canvas than implementing a layering system?
Some background:
context.save
and context.restore
save and restore the context state. Context state includes styling, transformations, compositing, etc.
.save
will push the current state on top of a stack. .restore
will pop the last added state off the top of a stack. So they act as a last-in-first-out stack of states.
You can do multiple .save
which will push multiple states onto the stack. Then you can pop multiple states off the stack by doing multiple .restore
.
Since .save
will save all context state, saves & restores are relatively expensive operations.
An example of multiple save/restore:
context.fillStyle='red';
context.fillRect(0,0,10,10); // red rectangle
context.save(); // fillStyle=='red'
context.fillStyle='blue'; // fillStyle='blue'
context.fillRect(0,0,10,10); // blue rectangle
context.save(); // fillStyle=='blue'
context.fillStyle='green'; // fillStyle=='green'
context.fillRect(0,0,10,10); // green rectangle
context.restore(); // fillStyle='blue';
context.fillRect(0,0,10,10); // blue rectangle
context.restore(); // fillStyle='red'
context.fillRect(0,0,10,10); // red rectangle
Answer#1: No, there is no way to regress to prior saved states without executing multiple restores. The states are saved on a stack so unlike an array of states, you cannot "jump" to states[2].
Answer#2: In practice, it's much more common to not use save/restore, but rather to use javascript objects to store the least state info as required.
For example:
// put various fillStyles in a fills object
var fills={};
fills.red='red';
fills.green='green';
fills.blue='blue';
// create a function that draws a rect with specified fillStyle
function styledRect(x,y,w,h,fill){
var priorFill=context.fillStyle;
context.fillStyle=fill;
context.fillRect(x,y,w,h);
context.fillStyle=priorFill;
}
// use the fills object to control the fillStyle "state"
styledRect(0,0,10,10,fills.red);
A more complex "state" object might look like this:
buttonStyles={};
buttonStyles.normal={ font:'12px verdana', fill:'black' };
buttonStyles.warning={font:'12px italic verdana', fill:'orange' };
buttonStyles.danger={ font:'14px italic verdana', fill:'red' };
// example usage
someButtonDrawingFunction("You're in danger!",buttonStyles.danger);
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