绘制画布撤消功能

时间:2013-06-17 16:34:38

标签: javascript jquery canvas

这些是按钮功能:

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

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

这是撤消功能:

    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);
}
} 

我也将数组声明在顶部:

var drawStack = [];

在我用鼠标按下方法绘制每个笔划之前,我也放了这段代码:

 Stack1.add();

这是我的工作示例..在屏幕上绘制3个圆圈,然后单击撤消,一切都变为空白,然后再次单击它,只剩下2个。它很接近,但我无法弄清楚最后一部分。

1 个答案:

答案 0 :(得分:0)

你让它变得比它需要的更复杂。 undo函数通常如何工作的伪代码:

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]

如你所见:

  • 你永远不需要mod操作符。
  • 您不需要跟踪堆栈的顶部和底部,只需要跟踪当前状态的索引,所需的状态数以及stateArray的大小。
  • 当你为它添加新的状态时,你应该清除当前状态之上的stateArray中的状态,以便按照人们期望的方式运行(除非你要实现大多数应用程序没有的分支历史记录)。

编辑:我发现代码中存在不同的问题,您正试图立即将图像绘制到画布而不是等待它加载。至少你的撤销功能应如下所示:

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);
    }
}

如果您的索引是正确的,我怀疑它们不是。您可以在this fiddle中查看上述算法的示例实现。