【问题标题】:Drawing overlapping circles with alpha channeling使用 Alpha 通道绘制重叠圆圈
【发布时间】:2013-07-11 09:59:57
【问题描述】:

这个问题已经在这里得到了回答:Combined area of overlapping circles

我的问题更具体。我在其他任意大小的圆圈内有任意数量的任意大小的圆圈,以制作类似目标的图像:

此图像必须具有一定程度的透明度。整个形状的透明度必须相同。然后,有任意数量的这些形状可以重叠,它需要看起来像这样:

无论重叠多少,透明度量都必须保持不变。

我能想到的唯一方法是遍历画布上的每个像素,并根据像素与每个圆中心的距离计算像素应该是什么颜色,但这需要太长时间。我希望圆圈也可以拖动,所以这需要非常快。有一个更好的方法吗? (对不起,我的 GIMP 技能很差)

【问题讨论】:

  • 这些圆圈是否具有相同的整体不透明度,或者各个圆圈是否具有不同的不透明度?
  • 我认为每个圆圈具有相同的不透明度是安全的。

标签: html algorithm canvas geometry


【解决方案1】:

您必须使用像 RaphaelJS 这样的库。它的功能比您在这里要求的要多。

编辑:您可以通过 js 应用 alpha 透明度,方法是通过编程确定中心之间的距离 (D) 并将其与半径之和 (S) 进行比较。如果 D

(http://raphaeljs.com/)

【讨论】:

  • 我一定会去看看的。它至少会使绘图更容易。
【解决方案2】:

可以在不使用像素操作或任何库的情况下进行本机操作。

只要所有圆圈的透明度都相同,它就非常简单。

解决方案


一些随机背景上的圆圈

你需要做的是:

  • 分配一个屏幕外画布,其中圆圈绘制为实体(无透明度)
  • 分三步画圆圈。
  • 首先是所有圆圈的红色表面,然后是所有圆圈的蓝色表面,以此类推。
  • 为主(可见)画布的透明度设置全局 Alpha
  • 清除两个画布
  • 将屏幕外画布绘制到主画布

您的圈子函数可能如下所示:

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();
}

该函数采用xy 中心点以及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;
}
&lt;canvas id="demo" width="500" height="333"&gt;&lt;/canvas&gt;

【讨论】:

  • @epark009 很高兴我能帮上忙!
猜你喜欢
  • 2018-03-24
  • 2011-02-06
  • 1970-01-01
  • 2021-03-21
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多