Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/420.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript画布-在矩形中相交圆孔或如何合并多个圆弧路径_Javascript_Canvas_Path_Clipping - Fatal编程技术网

Javascript画布-在矩形中相交圆孔或如何合并多个圆弧路径

Javascript画布-在矩形中相交圆孔或如何合并多个圆弧路径,javascript,canvas,path,clipping,Javascript,Canvas,Path,Clipping,我的问题很简单。这是“如何在一个形状上画一个孔?”问题的一个变体,经典答案是“简单地在同一条路径上画两个形状,但顺时针画实体,逆时针画“孔”。这很好,但我需要的“孔”通常是一个复合形状,由多个圆组成 视觉描述: jsfiddle: 编辑: 提出了多种解决方案,我觉得我的问题有误导性。以下是更多信息: 我需要矩形区域作为阴影。这是我正在制作的游戏的截图(希望这不违反规则): 矩形的alpha值应小于1.0 “孔”中显示的内容是在应用阴影之前在画布上绘制的内容 @马克: 或者…要“删除”(删除

我的问题很简单。这是“如何在一个形状上画一个孔?”问题的一个变体,经典答案是“简单地在同一条路径上画两个形状,但顺时针画实体,逆时针画“孔”。这很好,但我需要的“孔”通常是一个复合形状,由多个圆组成

视觉描述:

jsfiddle:

编辑:

提出了多种解决方案,我觉得我的问题有误导性。以下是更多信息: 我需要矩形区域作为阴影。这是我正在制作的游戏的截图(希望这不违反规则):

  • 矩形的alpha值应小于1.0
  • “孔”中显示的内容是在应用阴影之前在画布上绘制的内容
@马克:

  • 或者…要“删除”(删除)双圆- “目标输出”将画布内容替换为设置的背景。 -这些洞是蓝色的而不是绿色的
  • 另一方面 “source Top”要求在定义剪裁遮罩后绘制内容。在我的例子中,这将是低效的(光被绘制为同心圆,阴影区域仍然可见)
@霍伯维克钥匙: 这是一个静态背景,而不是实际的画布内容。但是,我可以使用clip()与使用“source-top”的方式相同,但这样做效率低下


我现在已经实现的解决方案:。我只是在主画布内容上绘制剪裁的矩形(在内存画布中)。有更快/更好的解决方案吗?

由于答案的简单性,我几乎不敢发布第一部分,但为什么不在坚实的背景上只填充两个圆圈呢

var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var cw=画布宽度;
var ch=画布高度;
var r=50;
ctx.fillStyle='rgb(0174239)';
ctx.fillRect(0,0,cw,ch);
ctx.fillStyle='white'
ctx.beginPath();
ctx.arc(cw/2-r/2,ch/2,r,0,数学PI*2);
ctx.closePath();
ctx.fill();
ctx.beginPath();
弧(cw/2+r/2,ch/2,r,0,数学π*2);
ctx.closePath();
ctx.fill()
body{背景色:象牙;}
#画布{边框:1px纯红;}

更简单的方法是使用剪裁和完整的圆。除非出于某种原因,您需要使用单一路径来执行此操作

var cutoutCircle = function(x, y, r, ctx){
  ctx.save()
  ctx.arc(x, y, r, 0, Math.PI * 2, false) 
  ctx.clip()
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
  ctx.restore();
}

var myCircles = [{x: 75, y: 100, r: 50}, {x: 125, y: 100, r: 50}], 
    ctx = document.getElementById("canvas").getContext('2d');

ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for (var i=0; i<myCircles.length; i++){
  cutoutCircle(myCircles[i].x, myCircles[i].y, myCircles[i].r, ctx)
}
var cutoutCircle=函数(x,y,r,ctx){
ctx.save()
ctx.arc(x,y,r,0,Math.PI*2,false)
ctx.clip()
clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
ctx.restore();
}
var myCircles=[{x:75,y:100,r:50},{x:125,y:100,r:50}],
ctx=document.getElementById(“画布”).getContext(“2d”);
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);

对于(var i=0;i如果我理解正确:您希望在游戏顶部有一个遮罩的外观,以便两个相交的圆高亮显示,而其他一切都变暗

我建议保持简单——创建一个屏幕外的画布,在透明的黑色背景上画出圆圈

然后在需要的时候在游戏顶部画出屏幕外的画布。这比为每一帧重新合成效果好得多——只需重复使用一次

演示 该遮罩显示在下面的演示窗口中(滚动或使用整个页面查看所有内容)。通常您会创建一个屏幕外画布,然后使用它

//创建掩码
//对于屏幕外,使用createElement(“画布”)
var mask=document.getElementById(“mask”),
ctxm=mask.getContext(“2d”),
w=掩模宽度,h=掩模高度,x,y,半径=80;
ctxm.fillStyle=“rgba(0,0,0,0.5)”;
ctxm.fillRect(0,0,w,h);//用50%透明黑填充掩模
ctxm.globalCompositeOperation=“destination out”//敲除背景
ctxm.fillStyle=“#000”//一些纯色
x=w/2——半径/1.67;
y=h/2;
ctxm.moveTo(x,y);//圈1
ctxm.弧(x,y,半径,0,数学PI*2);
x=w/2+半径/1.67;
ctxm.moveTo(x,y);//圈2
ctxm.弧(x,y,半径,0,数学PI*2);
ctxm.fill();//击倒他们,完成!
//-----游戏中使用面具,下面是伪动作------
var canvas=document.getElementById(“游戏”),ctx=canvas.getContext(“2d”);
(函数循环(){
ctx.fillStyle=“#742”;
ctx.fillRect(0,0,w,h);//清除背景
ctx.fillStyle=“#960”;
对于(x=0;x


用一个简单的例子更新了我的问题。我认为你必须在同一条路径上制作一个包含两个弧的形状……寻找圆交点和计算复合周长的复杂性超过了整个项目的复杂性。在我确定这是唯一的选择之前,我不想重新发明轮子。我已经考虑到您对问题的补充,我在回答中添加了一些想法。祝您的项目好运!:-)@hobberwickey…剪辑在逻辑上更容易理解,但
上下文。与使用合成相比,剪辑
是一项昂贵的操作。;-)是的,但优化并不总是必要的。如果要剪切3或4个圆,整个过程需要1ms才能运行,为什么要优化?是的……在这个简单的例子中,剪切很好。:-)即使是在简单的情况下,我也倾向于考虑优化编码……它只是强化了我心目中的“最佳实践”-首先感谢您的时间和广泛的回答!由于我有一些问题,我目前正在撰写回复。我最初认为目的地正是我需要的解决方案
var cutoutCircle = function(x, y, r, ctx){
  ctx.save()
  ctx.arc(x, y, r, 0, Math.PI * 2, false) 
  ctx.clip()
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
  ctx.restore();
}

var myCircles = [{x: 75, y: 100, r: 50}, {x: 125, y: 100, r: 50}], 
    ctx = document.getElementById("canvas").getContext('2d');

ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for (var i=0; i<myCircles.length; i++){
  cutoutCircle(myCircles[i].x, myCircles[i].y, myCircles[i].r, ctx)
}