简体   繁体   English

绘画画布撤消功能

[英]Paint canvas undo feature

These are the button functions: 这些是按钮功能:

$("#undo").click(function() {
    Stack1.undo();
});

$("#redo").click(function() {
  Stack1.redo();
});

This is the undo function: 这是撤消功能:

    function clearCanvas()
    {
    ctx.clearRect(0,0,canvasWidth,canvasHeight);

    }
   Stack1 = new Stack();
    ///////////////////

    function Stack(firstImg , size) {
    var drawStack = new Array();
    var stackIndex = 0;
    var stackTop = 0;
    var stackFloor = 0;
    var stackSize = size; 

    drawStack[0] = firstImg;

this.add = function() {
    drawStack[++stackIndex%stackSize] = canvas.toDataURL("image/png");
    if (stackIndex >= stackSize) stackFloor = (stackIndex +1) % stackSize ;
    stackTop = stackIndex % stackSize;
}

this.undo = function () {
    if (stackIndex%stackSize == stackFloor ) return;
    clearCanvas();
    var tmpImg = new Image();
    tmpImg.src = drawStack[--stackIndex%stackSize];
    ctx.drawImage(tmpImg, 0, 0);

}

this.redo = function () {
    if (stackIndex%stackSize == stackTop) return;
    clearCanvas();
    var tmpImg = new Image();
    tmpImg.src = drawStack[++stackIndex%stackSize];
    ctx.drawImage(tmpImg, 0, 0);
}
} 

Also I declare the array at the top: 我也在顶部声明数组:

var drawStack = [];

I also put this code before I draw each stroke in my mouse down method: 在用鼠标按下方法绘制每个笔画之前,我还放置了以下代码:

 Stack1.add();

Here is my working example..draw 3 circles on screen then click undo, everything goes blank, then click it again and only 2 remain. 这是我的工作示例。在屏幕上绘制3个圆圈,然后单击“撤消”,所有内容变为空白,然后再次单击它,仅剩2个。 Its close but I cannot figure out the last part. 它很接近,但我无法弄清最后一部分。

You've made this more complicated than it needs to be. 您已经使它变得比所需复杂。 The pseudo code for how an undo function usually works goes: 有关撤消功能通常如何工作的伪代码如下:

currentState = 0
maxStates = 10
stateArray = []

initialize:
   push the current state onto the top of stateArray 

save:
  if there are states in stateArray above the currentState
    clear the states in stateArray above the current state
  push the current state onto the top of stateArray 
  currentState++
  if the size of stateArray exceeds maxStates
     remove the oldest state from the bottom of stateArray 
     currentState--

undo:
  if there are previous states in stateArray 
    currentState--
    revert the canvas to stateArray[currentState]

redo:
  if there are newer states in stateArray 
     currentState++
     revert the canvas to stateArray[currentState]

As you can see: 如你看到的:

  • You don't ever need the mod operator. 您根本不需要mod运算符。
  • You don't need to keep track of the top and bottom of the stack, only the index of the current state, the number of states you want and the size of the stateArray. 您无需跟踪堆栈的顶部和底部,只需跟踪当前状态的索引,所需状态的数量以及stateArray的大小即可。
  • You should clear the states in the stateArray above the current state when you add a new one for it to function the way people expect (unless you are going to implement a branching history which most applications do not). 当您添加新的状态数组以使其达到人们期望的功能时,应清除stateArray中当前状态上方的状态(除非您要实现大多数应用程序都不希望的分支历史记录)。

Edit : I noticed a different problem in your code, you are trying to immediately draw the image to the canvas instead of waiting for it to load. 编辑 :我注意到您的代码中的另一个问题,您试图立即将图像绘制到画布上,而不是等待它加载。 At minimum your undo function should look like: 至少您的撤消功能应如下所示:

this.undo = function () {
    if (stackIndex%stackSize == stackFloor) return;
    var tmpImg = new Image();
    tmpImg.src = drawStack[--stackIndex%stackSize];
    tmpImg.onload = function() {
       clearCanvas();
       ctx.drawImage(this, 0, 0);
    }
}

If your indexes are right, which I suspect they are not. 如果您的索引正确,我怀疑它们不合适。 You can look at an example implementation of the algorithm I described above in this fiddle . 您可以在小提琴中查看我上面描述的算法的示例实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM