如何撤消 HTML5 Canvas 绘图应用程序的橡皮擦操作

How to Undo the eraser action for HTML5 Canvas Drawing App

我创建了一个 HTML5 绘图应用程序,它具有允许用户 select 绘图颜色、更改绘图工具的大小(半径)、撤销、重做,彻底清除 canvas.

我最近添加了一个使用 globalCompositionProperty(desitnation-out)的橡皮擦工具来擦除 canvas 的 selected 区域。这部分工作正常,但是当我去撤消擦除时,整个 canvas 被清除并且重做功能不起作用。当我使用常规绘图工具(使用 source-over)恢复绘图时,undo/redo 有效。我已经包含了应用程序中使用的一些功能的代码。每次关闭绘图工具时,我都会存储 canvas 的快照。这被添加到用于撤消和恢复 canvas.

的数组中

有人可以解释一下我在这里做错了什么吗?我不确定我是否理解 globalCompositeOperation 属性 如何影响保存的 canvas DataURI。

function storeSnapshot() {
    cStep++;
    if (cStep < cPushArray.length) { cPushArray.length = cStep; }
    cPushArray.push(canvas.toDataURL());
}

var putPoint = function(e){
    if(dragging){
    context.lineTo(e.clientX - 174, e.clientY - 50);
    context.stroke();
    context.beginPath();
    if(eraser == true){
        context.globalCompositeOperation="destination-out";

    }else{
        context.globalCompositeOperation="source-over"; 
    }
    context.arc(e.clientX - 174, e.clientY - 50 , radius, 0, 2 * Math.PI);
    context.fill();
    context.beginPath();
    context.moveTo(e.clientX - 174, e.clientY - 50);
    }
}

更新: 玩了一会儿之后,我尝试了一些解决问题的方法。我不确定这是否是正确的做事方式,但我想我会向您展示我所做的一切。

我有一个在鼠标松开时触发的脱离功能。这是之前的功能:

var disengage = function(){
dragging = false;
context.beginPath();
storeSnapshot();
    }

我添加了一些代码,这允许用户使用橡皮擦工具和 undo/redo 操作。我还不确定为什么会这样,所以如果有人有见识,我将不胜感激。

var disengage = function(){
dragging = false;
context.beginPath();
if(eraser == true)
{
    context.globalCompositeOperation="source-over"; 
}
storeSnapshot();
    }

我遇到了与您完全相同的问题,我很高兴遇到您 question/solution 因为这对我来说是一个灵光一现的时刻。我一看到您的解决方案,就完全明白发生了什么事。

为了深入了解您的解决方案为何有效,globalCompositeOperation 是 canvas 的 属性,它基本上规定了如何将内容(在本例中为线条描边)放在canvas。默认情况下它是 source-over,它只是在任何现有笔划之上放置一个新的线条笔划。正如您提到的,擦除使用 destination-out,它将所有现有内容保留在不与新线条笔划重叠的位置(因此擦除)。对于一些信息图表和解释,我强烈推荐 globalCompositeOperation 的 MDN 文档:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation

因此,如果您进入擦除模式(对您而言,擦除器 = true)、擦除,然后立即尝试撤消,则 globalCompositeOperation 仍将设置为目标输出。这意味着当您撤消尝试将存储的图像绘制到 canvas 时,所有内容都会消失,因为它基本上仍在擦除(如 destination-out 所说,它会丢弃与新内容重叠的任何现有内容,在这种情况下是整个 canvas space)。因此,您需要像在解决方案中那样将其设置回 source-over,以便恢复的图像实际出现在 canvas 上。希望对您有所帮助!