简体   繁体   中英

HTML 5 canvas globalCompositeOperation (eraser) issues

Ok, I built a drawing system a few months back which basically lets the user draw on the canvas. Some features that I included were drawing with a user defined color and size of the stroke, eraser, and undo/redo.

I was just going over some projects to see how they were functioning still and noticed a new issue that wasn't happening when I built and published this sketch tool.

My issue is, after the user has drawn whatever and then goes to the eraser to erase a portion of the sketch, the entire canvas is cleared on mousedown. This did not happen before. The eraser is supposed to follow the cursor and clear the stroke path that the mouse takes. So I'm wondering if there were any changes to how the canvas reads the global composite operation or something. I've searched stack and google and can't find any clear answers so I'm hoping maybe someone else has ran into this issue.

I also noticed that when I switch back to the pen tool after the eraser clears the canvas nothing gets drawn anymore. Even if I undo, it will show the previous stroke that was erased but the draw tool no longer does anything.

If I try to erase everything is cleared, but if I undo it will bring back what was stored before the eraser was attempted.

Here are the scripts that I used for drawing and erasing. Any help on the subject would be greatly appreciated. Thank you.

I would also like to note that this issue is happening in the latest version of chrome, firefox, and IE 11.

EDIT: I forgot to mention. After discovering this issue, I tried to switch the globalCompositeOperation to "destination-out" but it did not leave a solid stroke like I would like. It was only making a series of dots (which were erasing) but it wasn't smooth/clean like it should be.

EDIT: Fiddle link 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;
    } 
});

To get your eraser working again, you want to change these lines in your Erase function:

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

to these:

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

As you can see in this article , there was a time when Firefox, Chrome, and Webkit did not support the value copy . I would guess that when your program broke when the browsers implemented this feature.

EDIT: For some reason toDataUrl doesn't seem to properly reflect the changes with the eraser. If you change the values stored in your cPushArray to image data from ctx.getImageData and put the data back on the canvas with ctx.putImageData, it works just fine.

Updated Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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