这个问题在这里得到了回答:Combined area of overlapping circles
我的问题更具体。我在其他任意大小的圆圈内有任意数量的任意大小的圆圈,以制作类似目标的图像:
此图片必须具有一定的透明度。整个形状的透明度必须相同。然后,有任意数量的这些形状可以重叠,它需要看起来像这样:
透明度必须保持不变,无论它们重叠多少。
我唯一能想到的就是遍历画布上的每个像素并根据距离每个圆心的距离来计算像素应该是什么颜色,但这需要太长时间。我希望圆圈也可以拖动,所以这需要非常快。有一个更好的方法吗? (抱歉我的GIMP技能很差)
答案 0 :(得分:2)
可以在不使用像素操作或任何库的情况下进行本地操作。
如果所有圆圈的透明度相同,则非常简单。
在一些随机背景之上的圈子
您需要做的是:
您的圈子功能可能如下所示:
function drawCircle(x, y, r, step) {
ctx.beginPath();
switch (step) {
case 0: // step 0, outer circle red
ctx.fillStyle = '#f00';
break;
case 1: // step 1, middle circle blue
ctx.fillStyle = '#00f';
r *= 0.67;
break;
case 2: // step 2, inner circle green
ctx.fillStyle = '#0f0';
r *= 0.33;
break;
}
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
}
该函数采用x
和y
中心点以及radius
。但另外它在0到2之间取step
值,它决定了绘制哪个表面。这在接下来的步骤中非常重要。
首先,我们可以定义一个包含我们想要绘制的所有圆的数组:
var circs = [
//x y r dx dy (the last two for animation only)
[100, 100, 50, 2, 1],
[200, 200, 50, -2, -3],
[150, 50, 50, 3, -1]
];
从这里你可以拖动它们,偏移x和y然后重绘它们,但为了演示,我会为它们设置动画。
在我们绘制之前,我们在主画布上设置全局alpha(屏幕外保持稳定):
mctx.globalAlpha = 0.7; // main canvas
动画循环:
function start() {
// clear off-screen canvas
ctx.clearRect(0,0, w, h);
// clear main canvas
mctx.clearRect(0,0, w, h);
var t = 0, i, c;
// outer step loop
for(; t < 3; t++) {
// draw all circles at current step
for(i = 0; c = circs[i]; i++) {
drawCircle(c[0], c[1], c[2], t);
}
}
// re-position circles for animation
for(i = 0;c = circs[i]; i++) {
c[0] += c[3]; /// add delta to x
c[1] += c[4]; /// add delta to y
// reverse deltas if at boundaries
if (c[0] < 0 || c[0] > w) c[3] = -c[3];
if (c[1] < 0 || c[1] > h) c[4] = -c[4];
}
// draw off-screen to main canvas
mctx.drawImage(ocanvas, 0, 0);
// loop animation
requestAnimationFrame(start);
}
如果要将其他元素绘制到画布上,可以为每个操作重置全局alpha - 或者使用第二个屏幕画布来保存静态内容。
var demo = document.getElementById("demo");
var w = demo.width, h = demo.height;
var ocanvas = document.createElement('canvas');
ocanvas.width = w;
ocanvas.height = h;
var ctx = ocanvas.getContext('2d');
var mctx = demo.getContext('2d');
var img = document.createElement('img')
img.onload = start;
img.src = 'http://i.imgur.com/CHPdL2y.png';
/// key to it all
mctx.globalAlpha = 0.7;
var circs = [
//x y r dx dy
[100, 100, 50, 2 , 1.5],
[200, 200, 70, -2 , -3],
[150, 50, 50, 3 , -1],
[150, 50, 30, 4 , 4],
[150, 50, 20, -3 , -2],
[100, 100, 55, 2.5, 2.5],
[200, 200, 75, -1 , -2.5],
[150, 50, 45, 3.5, -2],
[150, 50, 35, 5 , 2],
[150, 50, 25, -1.2, -5]
];
function drawCircle(x, y, r, step) {
ctx.beginPath();
switch (step) {
case 0:
ctx.fillStyle = '#f00';
break;
case 1:
ctx.fillStyle = '#00f';
r *= 0.67;
break;
case 2:
ctx.fillStyle = '#0f0';
r *= 0.33;
break;
}
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
}
function start() {
ctx.clearRect(0, 0, w, h);
mctx.clearRect(0, 0, w, h);
var i = 0, t, c;
for(t = 0; t < 3; t++) {
for(i = 0; c = circs[i]; i++) {
drawCircle(c[0], c[1], c[2], t);
}
}
for(i = 0;c = circs[i]; i++) {
c[0] += c[3];
c[1] += c[4];
if (c[0] < 0 || c[0] > w) c[3] = -c[3];
if (c[1] < 0 || c[1] > h) c[4] = -c[4];
}
mctx.drawImage(ocanvas, 0, 0);
requestAnimationFrame(start);
}
body {
margin:0;
background:url(//i.stack.imgur.com/b8eCZ.jpg) no-repeat;
}
<canvas id="demo" width="500" height="333"></canvas>
答案 1 :(得分:1)
您必须使用像RaphaelJS这样的库。它的功能超出了你的要求。
编辑:您可以通过编程方式确定中心之间的距离(D)并将其与半径之和(S)进行比较,从而通过js应用Alpha透明度。如果D < S,然后它们重叠,以便处理红色圆圈。