在圆形路径周围放置不同尺寸的圆圈,没有间隙

时间:2014-08-24 10:28:06

标签: javascript math canvas

我创建了一个Canvas动画,并设法将x个圆圈定位在圆形路径中。这是我使用的代码的简化版本:

var total = circles.length,
    i = 0,
    radius = 500,
    angle = 0,
    step = (2*Math.PI) / total;

for( i; i < total; i++ ) {
    var circle = circles[i].children[0],
        cRadius = circle[i].r,
        x = Math.round(winWidth/2 + radius * Math.cos( angle ) - cRadius),
        y = Math.round(winHeight/2 + radius * Math.sin( angle ) - cRadius);

    circle.x = x;
    circle.y = y;

    angle += step;
}

结果如下: enter image description here

我想要实现的是让所有圆圈彼此相邻,它们之间没有间隙(第一个和最后一个除外)。圆形尺寸(半径)是随机生成的,不应调整以适合圆形路径:

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

我预计第一个和最后一个圈之间会有差距。

我正在努力解决这个问题,所以任何帮助都会非常感激:)

干杯!

2 个答案:

答案 0 :(得分:3)

主要创作循环:
•取当前半径
•计算它所覆盖的角度(= atan2(smallRadius / bigRadius))
•以最新角度移动底角。

enter image description here

http://jsfiddle.net/dj2v7mbw/9/

function CircledCircle(x, y, radius, margin, subCircleCount, subRadiusMin, subRadiusMax) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.subCircleCount = subCircleCount;
    var circles = this.circles = [];
    // build top sub-circles
    var halfCount = Math.floor(subCircleCount / 2);
    var totalAngle = addCircles(halfCount);
    // re-center top circles
    var correction = totalAngle / 2 + Math.PI / 2;
    for (var i = 0; i < halfCount; i++) this.circles[i].angle -= correction;
    // build bottom sub-circles
    totalAngle = addCircles(subCircleCount - halfCount);
    // re-center bottom circles
    var correction = totalAngle / 2 - Math.PI / 2;
    for (var i = halfCount; i < subCircleCount; i++) this.circles[i].angle -= correction;
    // -- draw this C
    this.draw = function (angleShift) {
        for (var i = 0; i < this.circles.length; i++) drawDistantCircle(this.circles[i], angleShift);
    }
    //
    function drawDistantCircle(c, angleShift) {
        angleShift = angleShift || 0;
        var thisX = x + radius * Math.cos(c.angle + angleShift);
        var thisY = y + radius * Math.sin(c.angle + angleShift);
        ctx.beginPath();
        ctx.arc(thisX, thisY, c.r, 0, 2 * Math.PI);
        ctx.fillStyle = 'hsl(' + (c.index * 15) + ',75%, 75%)';
        ctx.fill();
        ctx.stroke();
    }
    //
    function addCircles(cnt) {
        var currAngle = 0;
        for (var i = 0; i < cnt; i++) {
            var thisRadius = getRandomInt(subRadiusMin, subRadiusMax);
            var thisAngle = Math.atan2(2 * thisRadius + margin, radius);
            var thisCircle = new subCircle(thisRadius, currAngle + thisAngle / 2, i);
            currAngle += thisAngle;
            circles.push(thisCircle);
        }
        return currAngle;
    }
}

function subCircle(radius, angle, index) {
    this.r = radius;
    this.angle = angle;
    this.index = index;
}

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

一起使用
 var myCircles = new CircledCircle(winWidth / 2, winHeight / 2, 350, 2, 24, 5, 50);
 myCircles.draw();

动画:

var angleShift = 0;

function draw() {
    requestAnimationFrame(draw);
    ctx.clearRect(0, 0, winWidth, winHeight);
    myCircles.draw(angleShift);
    angleShift += 0.010;
}
draw();

答案 1 :(得分:2)

这是这样的,但你必须弄清楚最后一个圆圈的大小:

http://jsfiddle.net/rudiedirkx/ufvf62yf/2/

主要逻辑:

var firstStep = 0, rad = 0, step = 0;
firstStep = step = stepSize();
for ( var i=0; i<30; i++ ) {
    draw.radCircle(rad, step);
    rad += step;
    step = stepSize();
    rad += step;
}
  • stepSize()Math.PI/48Math.PI/48 + Math.PI/36之间创建一个随机rad(没有特殊原因,但看起来不错)。您可以将其修复为正确的尺寸。
  • draw.radCircle(rad, step)在尺寸为rad的位置step处创建一个圆圈(也是以rad为单位)。
  • step每次迭代添加两次:一次从当前圆圈的中心步进到边缘,一次找到下一个圆圈的中心
  • firstStep很重要,因为你必须知道在哪里停止绘图(因为第一个圆圈交叉成负角度)
  • 我还没弄明白如何让最后一个圆圈成为完美的尺寸=)

draw.radCircle()中还有一些魔力:

var r = rRad * Math.PI/3 * 200 * .95;
  • 200显然是大圆的半径
  • 95%是因为圆的边长略长于每个圆的(直)半径
  • 我不知道为什么Math.PI/3是......我认为它必须是Math.PI / 2,这是1 rad,但这根本不起作用。 1/3由于某种原因确实.....解释!

如果您想要设置这些圆圈大小的动画并保持它们对齐,那么您将会遇到困难。他们现在都是随机的。在动画中,只有第一次迭代可以是随机的,其余的是一大堆缓存和数学=)