HTML 5 canvas globalCompositeOperation(橡皮擦)问题

时间:2014-07-21 05:35:59

标签: javascript jquery html5 canvas html5-canvas

好的,我在几个月前建立了一个绘图系统,基本上让用户在画布上绘图。我包含的一些功能是使用用户定义的笔触,橡皮擦和撤消/重做的颜色和大小进行绘制。

我刚刚看了一些项目,看看它们是如何运作的,并注意到我在构建和发布这个草图工具时没有发生的新问题。

我的问题是,在用户绘制了任何内容然后转到橡皮擦以擦除草图的一部分之后,整个画布在mousedown上被清除。这种情况以前没有发生过。橡皮擦应该跟随光标并清除鼠标所采用的笔划路径。所以我想知道画布如何读取全局复合操作或其他内容是否有任何变化。我搜索了堆栈和谷歌,但找不到任何明确的答案,所以我希望也许其他人遇到过这个问题。

我还注意到,当橡皮擦清除画布后我切换回钢笔工具时,不再有任何东西被画出来了。即使我撤消,它也会显示已删除的上一个笔划但绘图工具不再执行任何操作。

如果我尝试擦除所有内容都被清除,但是如果我撤消它会带回在尝试使用橡皮擦之前存储的内容。

以下是我用于绘图和擦除的脚本。任何有关该主题的帮助将不胜感激。谢谢。

我还要注意,这个问题发生在最新版本的chrome,firefox和IE 11中。

编辑:我忘了提及。在发现这个问题之后,我尝试将globalCompositeOperation切换为“destination-out”,但它并没有像我想的那样留下一个实线。它只是制作了一系列的点(它们正在擦除),但它并不像它应该的那样光滑/干净。

编辑:小提琴链接http://jsfiddle.net/p889d/

function Draw(x, y, isDown) {
if (isDown) {
    ctx.beginPath();
    ctx.globalCompositeOperation="source-over";
    ctx.strokeStyle = gd.color;             
    ctx.lineWidth = gd.toolSize;            
    ctx.lineJoin = "round";
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(x, y);
    ctx.closePath();
    ctx.stroke();
}
    lastX = x;
    lastY = y;
}

function Erase(x, y, isDown) {
if (isDown) {
    ctx.beginPath();
    ctx.globalCompositeOperation="copy";
    ctx.strokeStyle = "rgba(0,0,0,0)";              
    ctx.lineWidth = gd.toolSize;            
    ctx.lineJoin = "round";
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(x, y);
    ctx.closePath();    
    ctx.stroke();   
}
   lastX = x;
   lastY = y;
}

$canvas.bind("mousedown touchstart", function (e) {                         
    mousePressed = true;    

    lastX = e.pageX - $(this).offset().left;
    lastY = e.pageY - $(this).offset().top;

    if (gd.pushIt == true) {    
        if (gd.tool == 'marker') {
            Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
        } 
        if (gd.tool == 'eraser') {
            Erase(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
        }
    }
    if (gd.pushIt == false) {
        invisibleCanvas(e, $(this));
    }
    if ($(".multi-item-menu").is(":visible")) {
        $(".multi-item-menu").fadeOut(400);
    }
    if ($("#draw-colors-pallet").is(":visible")) {
        $("#draw-colors-pallet").fadeOut(400);
    }

    // for text area tool
    if (gd.tool == 'text') {        
        mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
        mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;

        start_mouse.x = mouse.x;
        start_mouse.y = mouse.y;
    }
});

$canvas.bind("mousemove touchmove", function (e) {                          
    if (mousePressed == true && gd.pushIt == true) {
        if (gd.tool == 'marker') {
            Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
        } 
        if (gd.tool == 'eraser') {
            Erase(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
        }

        if (gd.tool == 'text') {
            mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
            mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;

            adjustTextArea();
        }
    }
    if (gd.pushIt == false) {
        var x = e.pageX,
            y = e.pageY;

        mousePressed = false;

        if (x !== lastX || y !== lastY) {
            invisibleCanvas(e, $(this));
        }

        lastX = x;
        lastY = y;
    } 
});

1 个答案:

答案 0 :(得分:4)

要让橡皮擦再次工作,您需要在擦除功能中更改这些行:

ctx.globalCompositeOperation="copy";
ctx.strokeStyle = "rgba(0,0,0,0)";

到这些:

ctx.globalCompositeOperation="destination-out";
ctx.strokeStyle = "rgba(0,0,0,1)";

正如您在this article中所看到的,有一段时间Firefox,Chrome和Webkit不支持值copy。我猜想当你的程序在浏览器实现这个功能时破了。

编辑: 出于某种原因,toDataUrl似乎没有正确反映橡皮擦的变化。如果将cPushArray中存储的值更改为来自ctx.getImageData的图像数据并使用ctx.putImageData将数据放回到画布上,则它可以正常工作。

Updated Demo