"Erasing" in HTML5 Canvas

HTML5 Canvas eraser tool without overdraw white color

Your idea of using compositing to create an eraser is a good idea.

destination-out will remove existing drawings where a new drawing overlaps those existing drawings.

var canvas=document.getElementById("canvas");var ctx=canvas.getContext("2d");var lastX;var lastY;var strokeColor="red";var strokeWidth=5;var mouseX;var mouseY;var canvasOffset=$("#canvas").offset();var offsetX=canvasOffset.left;var offsetY=canvasOffset.top;var isMouseDown=false;

function handleMouseDown(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here lastX=mouseX; lastY=mouseY; isMouseDown=true;}
function handleMouseUp(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here isMouseDown=false;}
function handleMouseOut(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here isMouseDown=false;}
function handleMouseMove(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here if(isMouseDown){ ctx.beginPath(); if(mode=="pen"){ ctx.globalCompositeOperation="source-over"; ctx.moveTo(lastX,lastY); ctx.lineTo(mouseX,mouseY); ctx.stroke(); }else{ ctx.globalCompositeOperation="destination-out"; ctx.arc(lastX,lastY,8,0,Math.PI*2,false); ctx.fill(); } lastX=mouseX; lastY=mouseY; }}
$("#canvas").mousedown(function(e){handleMouseDown(e);});$("#canvas").mousemove(function(e){handleMouseMove(e);});$("#canvas").mouseup(function(e){handleMouseUp(e);});$("#canvas").mouseout(function(e){handleMouseOut(e);});
var mode="pen";$("#pen").click(function(){ mode="pen"; });$("#eraser").click(function(){ mode="eraser"; });
body{ background-color: ivory; }canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><canvas id="canvas" width=300 height=300></canvas></br><button id="pen">Pen</button><button id="eraser">Eraser</button>

Erasing in html5 canvas

If you want to draw a black transparent stroke, you probably want:

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

Remember to save the previous globalCompositeOperation and then restore it later or transparency won't work properly!

Add erase ink functionality in HTML5 canvas whiteboard

Try using a brush the same color as the background color of the canvas. It will look like erasing, but it's like putting white-out on white paper.

sugs on your code:
use let instead of var
for onPaint, do function onPaint() {...}
instead.

Eraser tool in html5 canvas

Use multiple layers. Have one canvas for the background image and another for the drawing; that why you never erase any of the background image.

If you need to, you can have multiple layers as they don't generally impact performance.

And of course if you can combine layers, say the last drawn squiggle to the background layer, if you deem a drawing to be "permanent".

How to clear the canvas for redrawing

Given that canvas is a canvas element or an OffscreenCanvas object, use clearRect:

const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);

Erasing Parts of an Image on HTML5 Canvas?

You can use Compositing to "erase" pixels.

Specifically you use destination-out compositing.

KineticJS does not support compositing, but you still have a couple of options:

(Note: KineticJS has become KonvaJS and I haven't checked whether KonvaJs supports compositing. If it now does, just use destination-out compositing inside KonvaJS)

Option#1: Use a native canvas element as your Kinetic.Image source

  • Create an in-memory html5 canvas using var c=document.createElement,

  • Resize the canvas to image size,

  • drawImage your image onto the canvas,

  • Create a Kinetic.Image and set its image property to a reference to the native canvas. The Kinetic.Image will display whatever is drawn onto the native canvas.

    var kImage=new Kinetic.Image({
    ...
    image:c,
    ...
  • Set the canvas Compositing to cause new drawings to "erase" existing pixels:

    c.globalCompositeOperation='destination-out';
  • Listen for drag events on your circle-eraser. Use those events to draw a circle on the canvas that move just like the Kinetic circle-eraser moves. Since the canvas's compositing is set to "erase", new drawings of the circle on the canvas will erase the image on the canvas.

Your Kinetic.Image exactly reflects its canvas source (var c), so your Kinetic.Image will also display the image being erased in response to the Kinetic circle-eraser movements.

Option#2: Use a Kinetic.Shape

You can do the same operation as Option#1 by creating a Kinetic.Shape on a separate layer and getting a reference to the native canvas context using:

var ctx = myShapeLayer.getContext()._context;

This is a weaker option because KineticJS will redraw the shape--causing your erasing to be undone. Therefore you must do the additional step of saving all your circle-eraser's movements and replaying those movements (in drawFunc) to redo your erasing.



Related Topics



Leave a reply



Submit