A word of warning!
Saving the entire canvas as an undo / redo image is memory intensive and performance killer.
However, your idea of ​​gradually storing user drawings in an array is still a good idea.
Instead of saving the entire canvas as an image, just create an array of dots to record each musomov that the user makes when he draws. This is your "drawing array", which can be used to completely redraw the canvas.
Whenever the user drags the mouse, they create a polyline (a group of connected line segments). When the user drags to create a line, save that mousemove point in your drawing array and extend your polyline to the current mousemove position.
function handleMouseMove(e) { // calc where the mouse is on the canvas mouseX = parseInt(e.clientX - offsetX); mouseY = parseInt(e.clientY - offsetY); // if the mouse is being dragged (mouse button is down) // then keep drawing a polyline to this new mouse position if (isMouseDown) { // extend the polyline ctx.lineTo(mouseX, mouseY); ctx.stroke(); // save this x/y because we might be drawing from here // on the next mousemove lastX = mouseX; lastY = mouseY; // Command pattern stuff: Save the mouse position and // the size/color of the brush to the "undo" array points.push({ x: mouseX, y: mouseY, size: brushSize, color: brushColor, mode: "draw" }); } }
If the user wants to “cancel”, just pull the last point from the drawing array:
function undoLastPoint() {
Logically repeating is more difficult.
The simplest repetition is when the user can only restart immediately after cancellation. Store each undo in a separate redo array. Then, if the user wants to repeat, you can simply add a repeat bit to the main array.
The complication is if you allow the user to “repeat” after they have made more drawings.
For example, you might have a dog with two tails: a newly drawn tail and a second tail, “redo”!
So, if you allow the replay after the additional drawing, you will need a way to avoid confusion during the replay. Matt Grears' idea of ​​"repeating layers" is one of the good ways. Just change this idea, retaining the repeat points, not the entire canvas. The user can then turn on / off the repeat to see if they want to save their repeat.
Here is an example of using the undo array that I created for the previous question: Drawing on canvas, as in paint
Here is this code and script: http://jsfiddle.net/m1erickson/AEYYq/
<!doctype html> <html> <head> <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> <style> body{ background-color: ivory; } canvas{border:1px solid red;} </style> <script> $(function(){ var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var lastX; var lastY; var mouseX; var mouseY; var canvasOffset=$("#canvas").offset(); var offsetX=canvasOffset.left; var offsetY=canvasOffset.top; var isMouseDown=false; var brushSize=20; var brushColor="#ff0000"; var points=[]; function handleMouseDown(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY); </script> </head> <body> <p>Drag to draw. Use buttons to change lineWidth/color</p> <canvas id="canvas" width=300 height=300></canvas><br> <button id="undo">Hold this button down to Undo</button><br><br> <button id="brush5">5px Brush</button> <button id="brush10">10px Brush</button> <button id="brushRed">Red Brush</button> <button id="brushBlue">Blue Brush</button> </body> </html>