tomatentobi
tomatentobi

Reputation: 3157

Draw overlap of 3 circles on a canvas

I need to draw the following image on an HTML5 canvas without a temporary canvas:

enter image description here

With a temporary canvas it's easy, because I can handle the overlaps independently like you can see here:

Check this jsFiddle.

// init
var canvas = document.getElementById('canvas');
var tempCanvas = document.getElementById('tempCanvas');
var ctx = canvas.getContext('2d');
var tempCtx = tempCanvas.getContext('2d');

// draw circle function
var drawCircle = function( c, color ) {
  ctx.beginPath();
  ctx.arc( c.x, c.y, 50, 0, 2 * Math.PI, false );
  ctx.fillStyle = color;
  ctx.fill();
}

// draw overlap function
var drawOverlap = function( c1, c2, color ) {
  tempCtx.clearRect( 0, 0, 300, 300 );
  // first circle
  tempCtx.globalCompositeOperation = 'source-over';
  tempCtx.beginPath();
  tempCtx.arc( c1.x, c1.y, 50, 0, 2 * Math.PI, false );
  tempCtx.fillStyle = color;
  tempCtx.fill();
  // second circle
  tempCtx.globalCompositeOperation = 'destination-in';
  tempCtx.beginPath();
  tempCtx.arc( c2.x, c2.y, 50, 0, 2 * Math.PI, false );
  tempCtx.fill();
  // draw on main canvas
  ctx.drawImage( tempCanvas, 0, 0 );
}

// circle objects
var c1 = { x:100, y: 200 };
var c2 = { x:180, y: 200 };
var c3 = { x:140, y: 140 };

// draw background
ctx.beginPath();
ctx.rect( 0, 0, 300, 300 );
ctx.fillStyle = 'black';
ctx.fill();

// draw circles
drawCircle( c1, 'grey' );
drawCircle( c2, 'white' );
drawCircle( c3, 'white' );

// draw overlaps
drawOverlap( c1, c2, 'red' );
drawOverlap( c1, c3, 'blue' );
drawOverlap( c2, c3, 'blue' );

Do you know a way to draw this without a second canvas? Thanks a lot.


EDIT:

I solved it thanks to @user13500. There are still ugly borders but it's very fast:

Check this jsFiddle

Upvotes: 2

Views: 2353

Answers (2)

user13500
user13500

Reputation: 3856

Ai, my head hurts.

Not a quite a solution. Not one at all I guess. But if we do not care about the background we have this:

Fiddle Updated to new version as below.

Giving us this:

enter image description here

Tried to solve this using only globalCompositeOperation ;-P


Edit:

OK. Moving away from it for a few minutes and here we go again. This time with this as result. There is still the issue with stray lines around the circle red:

enter image description here

Though it might not be what you are after, it is here ;-) @markE is in another realm when it comes to authority on the subject.

Fiddle.

Code:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ct = [
    'source-over',         //  0
    'source-in',           //  1
    'source-out',          //  2
    'source-atop',         //  3
    'destination-over',    //  4
    'destination-in',      //  5
    'destination-out',     //  6
    'destination-atop',    //  7
    'lighter',             //  8
    'darker',              //  9
    'copy',                // 10
    'xor'                  // 11
];

ctx.beginPath();
ctx.globalCompositeOperation = ct[0];
ctx.fillStyle = "#888";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[6];
ctx.fillStyle = "#fff";
ctx.arc(180,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[11];
ctx.fillStyle = "#f00";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.fillStyle = "#888";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[9];
ctx.fillStyle = "#fff";
ctx.arc(180,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[11];
ctx.fillStyle = "#fff";
ctx.arc(140,140,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.fillStyle = "#00f";
ctx.arc(140,140,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.rect( 0, 0, 300, 300 );
ctx.fillStyle = '#000';
ctx.fill();

Upvotes: 2

markE
markE

Reputation: 105015

You can do this without a temporary canvas using clipping regions -- context.clip()

If you need, I can code the solution but since you know how to do compositing you can probably figure it out quickly ;)

But more importantly! ...

Why are you disabling your tool choices by not using a temporary canvas?

You could do document.createElement("canvas") to create a temporary canvas that's not even visible on the screen.

Upvotes: 1

Related Questions