Zoe Zoe - 5 months ago 26
Javascript Question

Using Clip in canvas causing Pixels

I am trying to using context.clip() to clip a draw arc from other one and fill the clipped result.
But when i clip section & fill it, it gives pixelated fill .

var ctx = document.getElementById("canvas").getContext("2d");
var x = 150 ;
var y = 150 ;
var r = 100 ;

ctx.save() ;
ctx.translate(x,y) ;

ctx.beginPath() ;
ctx.arc(0,0,r,0,2*Math.PI);
ctx.closePath() ;
ctx.fillStyle = "cyan" ;
ctx.fill() ;
ctx.lineWidth = 10;
ctx.stroke();
ctx.restore() ;

ctx.save() ;
ctx.clip() ;
ctx.translate(x,y);

ctx.beginPath();
ctx.moveTo(r,-r-10);
ctx.arc(0,-r-10,r,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle = "#f2f2f2";
ctx.fill();
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();


https://jsfiddle.net/x0d0n40z/1/

K3N K3N
Answer

An alternative approach which eliminates the need for clip()/save()/restore() is to use a few steps of compositing.

Clipping mask is anti-aliased in some browsers while in other not. To obtain consistency (and in some cases also performance since save-clip-restore are relative expensive operations) using composition is preferred if possible.

In this case:

  • Fill main arc in target color
  • Define a clipping arc
  • Change composite mode to destination-out and fill (will cut main)
  • Change composite mode to source-atop and stroke (will outline cut)
  • Change composite mode to source-over and stroke outline of main circle

Example

var ctx = c.getContext("2d"),
    x = 75, y = 75, radius = 70;

// main arc
ctx.arc(x, y, radius, 0, 6.28);
ctx.fillStyle = "cyan";
ctx.fill();

// clipping arc
ctx.beginPath();
ctx.arc(x, y - radius, radius, 0, 6.28);

// cut step
ctx.globalCompositeOperation = "destination-out";
ctx.fill();

// stroke gap step
ctx.globalCompositeOperation = "source-atop";
ctx.lineWidth = 10;
ctx.stroke();

// stroke whole outline
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.arc(x, y, radius, 0, 6.28);
ctx.lineWidth = 5;
ctx.stroke();

// if you want to color the clip then use this:
ctx.globalCompositeOperation = "destination-atop";
ctx.fillStyle = "#09f";
ctx.fill();
body {background:#e9e9e9}
<canvas id=c></canvas>

Comments