Javascript canvas - intersecting circle holes in rectangle or how to merge multiple arc paths -
the issue have straightforward. variation of "how can draw hole in shape?" question, classic answer "simply draw both shapes in same path, draw solid clockwise , "hole" counterclockwise." that's great "hole" need compound shape, consisting of multiple circles.
visual description: http://i.imgur.com/9sumswt.png.
jsfiddle: http://jsfiddle.net/d_panayotov/44d7qekw/1/
context = document.getelementsbytagname('canvas')[0].getcontext('2d'); // green background context.fillstyle = "#00ff00"; context.fillrect(0,0,context.canvas.width, context.canvas.height); context.fillstyle = "#000000"; context.globalalpha = 0.5; //rectangle context.beginpath(); context.moveto(0, 0); context.lineto(context.canvas.width, 0); context.lineto(context.canvas.width, context.canvas.height); context.lineto(0, context.canvas.height); //first circle context.moveto(context.canvas.width / 2 + 20, context.canvas.height / 2); context.arc(context.canvas.width / 2 + 20, context.canvas.height / 2, 50, 0, math.pi*2, true); //second circle context.moveto(context.canvas.width / 2 - 20, context.canvas.height / 2); context.arc(context.canvas.width / 2 - 20, context.canvas.height / 2, 50, 0, math.pi*2, true); context.closepath(); context.fill();
edit:
multiple solutions have been proposed , feel question has been misleading. here's more info: need rectangle area act shade. here's screenshot game i'm making (hope not against rules): http://i.imgur.com/tjrjmxc.png.
- the rectangle should able have alpha less 1.0.
- the contents, displayed in "holes" whatever drawn on canvas before applying shade.
@marke:
- alternatively...to "knockout" (erase) double-circles... - "destination-out" replaces canvas content set background. http://jsfiddle.net/d_panayotov/ab21yfgd/ - holes blue instead of green.
- on other hand... - "source-atop" requires content drawn after defining clipping mask. in case inefficient (light drawn concentric circles, shaded area still visible).
@hobberwickey: that's static background, not actual canvas content. can use clip() same way use "source-atop" inefficient.
the solution have implemented right now: http://jsfiddle.net/d_panayotov/ewdyfnj5/. i'm drawing clipped rectangle (in in-memory canvas) on main canvas content. there faster/better solution?
i dread posting first part of answer because of simplicity, why not fill 2 circles on solid background?
var canvas=document.getelementbyid("canvas"); var ctx=canvas.getcontext("2d"); var cw=canvas.width; var ch=canvas.height; var r=50; ctx.fillstyle='rgb(0,174,239)'; ctx.fillrect(0,0,cw,ch); ctx.fillstyle='white' ctx.beginpath(); ctx.arc(cw/2-r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill(); ctx.beginpath(); ctx.arc(cw/2+r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill();
body{ background-color: ivory; } #canvas{border:1px solid red;}
<canvas id="canvas" width=400 height=168></canvas>
alternatively...to "knockout" (erase) double-circles...
if want 2 circles "knockout" blue pixels down double-circles transparent & reveal webpage background underneath, can use compositing "knockout" circles: context.globalcompositeoperation='destination-out
var canvas=document.getelementbyid("canvas"); var ctx=canvas.getcontext("2d"); var cw=canvas.width; var ch=canvas.height; var r=50; // draw blue background // background visible outside double-circles ctx.fillstyle='rgb(0,174,239)'; ctx.fillrect(0,0,cw,ch); // use destination-out compositing "knockout" // double-circles , thereby revealing // ivory webpage background below ctx.globalcompositeoperation='destination-out'; // draw double-circles // , "erase" blue background ctx.fillstyle='white' ctx.beginpath(); ctx.arc(cw/2-r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill(); ctx.beginpath(); ctx.arc(cw/2+r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill(); // clean up! set compositing default ctx.globalcompositeoperation='source-over';
body{ background-color: ivory; } #canvas{border:1px solid red;}
<canvas id="canvas" width=400 height=168></canvas>
on other hand...
if need isolate double-circle pixels containing path, can use compositing draw double-circles without drawing blue background.
here's example:
var canvas=document.getelementbyid("canvas"); var ctx=canvas.getcontext("2d"); var cw=canvas.width; var ch=canvas.height; var r=50; var img=new image(); img.onload=start; img.src="https://dl.dropboxusercontent.com/u/139992952/multple/mm.jpg"; function start(){ // fill double-circles color ctx.fillstyle='white' ctx.beginpath(); ctx.arc(cw/2-r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill(); ctx.beginpath(); ctx.arc(cw/2+r/2,ch/2,r,0,math.pi*2); ctx.closepath(); ctx.fill(); // set compositing source-atop // new drawings drawn // overlap existing (non-transparent) pixels ctx.globalcompositeoperation='source-atop'; // draw new content // new content visible inside double-circles ctx.drawimage(img,0,0); // set compositing destination-over // new drawings drawn "behind" // existing (non-transparent) pixels ctx.globalcompositeoperation='destination-over'; // draw blue background // background visible outside double-circles ctx.fillstyle='rgb(0,174,239)'; ctx.fillrect(0,0,cw,ch); // clean up! set compositing default ctx.globalcompositeoperation='source-over'; }
body{ background-color: ivory; } #canvas{border:1px solid red;}
<canvas id="canvas" width=400 height=168></canvas>
{ additional thoughts given addition answer }
a technical point: xor
compositing works flipping alpha values on pixels not zero-out r,g,b portion of pixel. in cases, alphas of xored pixels un-zeroed , rgb again display. it's better use 'destination-out' compositing parts of pixel value (r,g,b,a) zeroed out don't accidentally return haunt you.
be sure... though it's not critical in example, should begin path drawing commands maskctx.beginpath()
. signals end of previous drawing , beginning of new path.
one option: see you're using concentric circles cause greater "reveal" @ center of circles. if want more gradual reveal, knockout in-memory circles clipped-shadow (or radial gradient) instead of concentric circles.
other that, solution of overlaying in-memory canvas should work (at cost of memory used in-memory canvas).
good luck game!
Comments
Post a Comment