0

I am testing things right now (just started out with web development a few days ago) so I pretty much just copied and pasted the undo function from http://www.codicode.com/art/undo_and_redo_to_the_html5_canvas.aspx. Right now I am unable to access the full source code so i'm kinda just guessing where to place things.

Here is a snippet of the code that I think is relevant to the question:

var cPushArray = new Array();
var cStep = -1;
var ctx = document.getElementById('canvas').getContext("2d");

function cPush() {
    cStep++;
    if (cStep < cPushArray.length) {
        cPushArray.length = cStep;
    }
    cPushArray.push(document.getElementById('canvas').toDataURL());
}

function cUndo() {
    if (cStep > 0) {
        cStep--;
        var canvasPic = new Image();
        canvasPic.src = cPushArray[cStep];
        canvasPic.onload = function() {
            ctx.drawImage(canvasPic, 0, 0);
        }
    }
}

//This draws the dots on the face.   
function drawCoordinates(x, y) {
    var pointSize = 3; // Change according to the size of the point.
    var ctx = document.getElementById("canvas").getContext("2d");
    ctx.fillStyle = "#ff2626";
    ctx.beginPath(); //Start path
    ctx.arc(x, y, pointSize, 0, Math.PI * 2, true); // Draw a point using the arc function of the canvas with a point structure.
    ctx.fill(); // Close the path and fill.
    cPush();
}

//count variable keeps track of the flicks
var count = 1;

//this listens for button clicks and displays the elements
document.getElementById('button').onclick = function() {
    document.getElementById(count).style.display = "block";
    count++;
}
document.getElementById('buttonUndo').onclick = function() {
    cUndo();
}

So far I know for a fact that the undo button is correctly linked because when I code alert("hello"), the alert pops up when the button is clicked. However, the undo function doesn't do anything in the code and i'm having trouble figuring out why it's behaving that way and how to fix it.

5
  • cUndo will only undo what was done when cPush was called. Make sure you're calling cPush after modifying the canvas. Commented May 19, 2016 at 19:43
  • in your cUndo() function it checks for if (cStep > 0) so everything inside that block will only run if cStep is greater than 0. Commented May 19, 2016 at 19:46
  • @MikeC That makes sense! I just modified the code so that cPush is called after the drawCoordinates but still, nothing happens. Commented May 19, 2016 at 19:47
  • @LunZhang Right! But even after I modify cStep to be something like >-2, still nothing happens. I've also tried drawing multiple dots (to increase the cStep count) and then undoing, but it fails. Commented May 19, 2016 at 19:51
  • make sure that canvasPic.src = cPushArray[cStep]; is returning a src Commented May 19, 2016 at 19:59

1 Answer 1

1

The problem is that the canvas needs to be cleared. When you do ctx.drawImage(canvasPic, 0, 0) that's saying "draw the previous state of the canvas over what's currently on the canvas." The problem is that the previous canvas state had clear or empty pixels on it. So it's like using a stamp with only the stuff that was actually drawn last time. Meaning the "blank" parts of the stamp aren't going to erase any part of the current screen. You can fix this by clearing the canvas between drawing. (I added a random dot function to show this):

var cPushArray = new Array();
var cStep = -1;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");


// Don't worry about this, I just wrote this for showing random colors
function generateColor() {
  var r = Math.floor(Math.random() * 256).toString(16);
  var g = Math.floor(Math.random() * 256).toString(16);
  var b = Math.floor(Math.random() * 256).toString(16);
  return '#' + r + g + b;
}

function cPush() {
  cStep++;
  if (cStep < cPushArray.length) {
    cPushArray.length = cStep;
  }
  cPushArray.push(document.getElementById('canvas').toDataURL());
}

function cUndo() {
  if (cStep >= 0) {
    cStep--;

    // V Clear the canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // ^ Clear the canvas
    
    var canvasPic = new Image();
    canvasPic.src = cPushArray[cStep];
    canvasPic.onload = function() {
      ctx.drawImage(canvasPic, 0, 0);
    }
  }
}

//This draws the dots on the face.   
function drawCoordinates(x, y) {
  var pointSize = 30; // Change according to the size of the point.
  var ctx = document.getElementById("canvas").getContext("2d");
  ctx.fillStyle = generateColor();
  ctx.beginPath(); //Start path
  ctx.arc(x, y, pointSize, 0, Math.PI * 2, true); // Draw a point using the arc function of the canvas with a point structure.
  ctx.fill(); // Close the path and fill.
  cPush();
}

document.getElementById('buttonUndo').onclick = function() {
  cUndo();
}
document.getElementById('addDot').addEventListener('click', function() {
  drawCoordinates(Math.random() * canvas.width, Math.random() * canvas.height);
});
html,
body {
  background: #222;
}
canvas {
  background: #FFF;
  display: block;
  margin: 10px auto;
}
<canvas id="canvas" width="320" height="240"></canvas>
<button id="buttonUndo">Undo</button>
<button id="addDot">Add Dot</button>

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your answer (it basically works like how I want it to in your demo minus the fact that the user doesn't get to draw on the canvas but rather, the circles are added in a random fashion) but unfortunately, when I use the clear and then click undo, my entire canvas image disappears and then when I click the button. I then tried adding a bunch of random dots inside the blank canvas and then clicking undo but all of them ended up disappearing at once instead of one at a time.
@somanyerrorswhy Are you only calling cPush at the end of drawCoordinates? That should be the only time you call it (in this context anyway)
Yup. Maybe I did something wrong earlier on or something.
@somanyerrorswhy Did you check your console? (hit F12 on Windows or Opt + Cmd + I on Mac) The canvas is tainted from that. That occurs if you load in data from a different domain than your own. If you need data from a different domain then search Stack Overflow, there's a few questions about that. Otherwise, try running it on your own site. It will work fine.
Oh, I didn't know that was a thing! Thank you so much once again!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.