【问题标题】:HTML 5 canvas globalCompositeOperation (eraser) issuesHTML 5 画布 globalCompositeOperation(橡皮擦)问题
【发布时间】:2014-09-11 13:21:42
【问题描述】:

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

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

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

我还注意到,当我在橡皮擦清除画布后切换回钢笔工具时,不再绘制任何东西。即使我撤消,它也会显示上一个被擦除的笔画,但绘图工具不再做任何事情。

如果我尝试擦除所有内容都会被清除,但如果我撤消它会恢复在尝试擦除之前存储的内容。

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

我还想指出,这个问题发生在最新版本的 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;
    } 
});

【问题讨论】:

  • 您的 strokeStyle 的不透明度为空,因此几乎没有机会绘制任何内容。
  • @GameAlchemist 它怎么是空的?我认为 rgba(0,0,0,0) 是定义它的正确方法吗?关于我应该尝试将其更改为的任何输入?
  • rgba() 颜色的最后一个组成部分是 alpha,范围为 0.0-1.0。如果为 0,则不会绘制任何内容(除非您使用特定的混合模式,但您使用的是复合模式,而不是此处的混合模式)。修复很简单:使用 rgb(,,) 或 rgba(,,,1)。
  • @GameAlchemist 我尝试了您的建议,但仍然面临同样的问题:(。尝试 rgba(0,0,0) 和 rgba(0,0,0,0.0) 现在唯一的区别是光标显示一个黑点,但仍清除整个画布
  • 如果您可以设置一个非常适合理解/调试您的问题的小提琴。

标签: javascript jquery html canvas html5-canvas


【解决方案1】:

要让橡皮擦再次工作,您需要在 Erase 函数中更改这些行:

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

【讨论】:

  • 非常感谢!使用 getImageData 仍然可以在这些浏览器的旧版本上使用,对吧?
  • @xxstevenxo 是的,任何支持canvas元素的浏览器都应该支持getImageData。
猜你喜欢
  • 2013-10-19
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
相关资源
最近更新 更多