InsOp
InsOp

Reputation: 2699

canvas - Substract shape from a clipped canvas

I want to clip an annulus (i.e. ring) from an image via javascripts canvas. I already have an approach but i think its too inelegant (and I really dont understand why this works, and why it doesnt just result in a smaller circle).

see this jsfiddle

    context.drawImage(imageObj, 0, 0, 500, 500);

    //crop outer circle
    context2.beginPath();
    context2.arc(250, 250, 200, 0, 2 * Math.PI, false);
    context2.closePath();
    context2.clip();

    //draw circle
    context2.drawImage(canvas,0,0);

    //crop inner circle
    context2.beginPath();
    context2.arc(250, 250, 100, 0, 2 * Math.PI, false);
    context2.closePath();
    context2.clip();

    //clear context 2
    context2.clearRect(0,0,500,500)

    // finally draw annulus
    context2.drawImage(canvas2,0,0);

is there a better way to do this?

Upvotes: 1

Views: 186

Answers (1)

Kaiido
Kaiido

Reputation: 136627

This does work because clipping areas called by clip method do stack.

IMO, this is indeed not the best way to do it, as you definitely need to call ctx.save(); before clipping and ctx.restore() afterward, which are really heavy methods.

My preferred way is to use compositing :

var ctx = canvas.getContext('2d');

var imageObj = new Image();

imageObj.onload = function() {

  ctx.drawImage(imageObj, 0, 0, 500, 500);
  // keep only the outer circle
  ctx.globalCompositeOperation = 'destination-in';
  ctx.beginPath();
  ctx.arc(250, 250, 200, 0, 2 * Math.PI, false);
  ctx.fill();
  // remove the inner one
  ctx.globalCompositeOperation = 'destination-out';
  ctx.beginPath();
  ctx.arc(250, 250, 100, 0, 2 * Math.PI, false);
  ctx.fill();
  // reset gCO
  ctx.globalCompositeOperation = 'source-over';

};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
<canvas id="canvas" width="500" height="500"></canvas>

Upvotes: 2

Related Questions