【问题标题】:Position different size circles around a circular path with no gaps围绕圆形路径放置不同大小的圆圈,没有间隙
【发布时间】:2014-08-24 21:49:37
【问题描述】:

我正在创建一个 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;
}

这会导致:

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

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

我希望第一个和最后一个圆圈之间有一个间隙。

我正在努力解决这个问题,所以任何帮助将不胜感激:)

干杯!

【问题讨论】:

  • 哦,数学。乐趣。每个step 都必须相等吗?这很容易。
  • 嗯...我认为这是一个线索... :)
  • 顺便说一句,这里有一个错字:var total = cirlces.length
  • 已更正。谢谢 matthias_h
  • 我仍然在这里挣扎鲁迪。你能详细说明一下吗:)

标签: javascript math canvas


【解决方案1】:

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

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

【讨论】:

  • 非常感谢!这看起来很棒!然而, circleCount 直接影响圆的大小。我已经定义了我所有的圆圈大小,并希望它们保持相同的大小。有任何想法吗?谢谢:)
  • 您在这里设置了动画:jsfiddle.net/dj2v7mbw/6 :-) 您的意思是您想用所有固定大小的圆圈“填充”圆圈的圆周,然后将圆圈的其余部分留空?
  • 正确。实际上,我将有一半的圆圈沿着顶部,另一半沿着圆圈的底部,左右有空格:)
  • 您能否更新您的帖子,例如,提供一个填充了所需半径的数组的函数?我会看看如何更新我的答案。
  • 每个圆的半径实际上是使用简单函数 cRadius = getRandomInt(5, 50); 在 5 到 50 个像素之间随机生成的。不过,我会将其添加到问题中...
【解决方案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 之间创建一个随机弧度(没有特殊原因,但看起来不错)。您可以将其修正为合适的尺寸。
  • draw.radCircle(rad, step) 在位置 rad 处创建一个大小为 step 的圆(也是弧度)。
  • step 每次迭代添加两次:一次是从当前圆的中心到其边缘,一次是找到下一个圆的中心
  • firstStep 很重要,因为您必须知道在哪里停止绘制(因为第一个圆交叉成负角)
  • 我还没有弄清楚如何使最后一个圆圈达到完美的大小 =)

draw.radCircle()也有一点魔力:

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

如果您想为这些圆圈大小设置动画并保持对齐,您将很难。他们现在都是随机的。在动画中,只有第一次迭代可以是随机的,剩下的就是一堆乱七八糟的缓存和数学 =)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    • 2021-07-30
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多