JS在其父级中随机分配子元素而不重叠

时间:2017-11-09 19:11:47

标签: javascript dom geometry

我正在尝试制作一些东西,其中一堆圆圈(带有border-radius的div)可以动态生成并放置在它们的容器中而不会重叠。

这是我目前的进展 - https://jsbin.com/domogivuse/2/edit?html,css,js,output

var sizes = [200, 120, 500, 80, 145];
var max = sizes.reduce(function(a, b) {
    return Math.max(a, b);
});
var min = sizes.reduce(function(a, b) {
    return Math.min(a, b);
});
var percentages = sizes.map(function(x) {
    return ((x - min) * 100) / (max - min);
});
percentages.sort(function(a, b) {
    return b-a;
})
var container = document.getElementById('container');
var width = container.clientWidth;
var height = container.clientHeight;
var area = width * height;
var maxCircleArea = (area / sizes.length);
var pi = Math.PI;
var maxRadius = Math.sqrt(maxCircleArea / pi);
var minRadius = maxRadius * 0.50;
var range = maxRadius - minRadius;
var radii = percentages.map(function(x) {
    return ((x / 100) * range) + minRadius;
});
function getRandomArbitrary(min, max) {
    return Math.random() * (max - min) + min;
}

var coords = [];
radii.forEach(function(e, i) {
    var circle = document.createElement('div');
    var randomTop = getRandomArbitrary(0, height);
    var randomLeft = getRandomArbitrary(0, width);
    var top = randomTop + (e * 2) < height ?
        randomTop :
        randomTop - (e * 2) >= 0 ?
        randomTop - (e * 2) :
        randomTop - e;
    var left = randomLeft + (e * 2) < width ?
        randomLeft :
        randomLeft - (e * 2) >= 0 ?
        randomLeft - (e * 2) :
        randomLeft - e;
    var x = left + e;
    var y = top + e;

    coords.push({x: x, y: y, radius: e});
    circle.className = 'bubble';
    circle.style.width = e * 2 + 'px';
    circle.style.height = e * 2 + 'px';
    circle.style.top = top + 'px';
    circle.style.left = left + 'px';
    circle.innerText = i
    container.appendChild(circle);
});

我已将它们添加到父容器中,但您可以看到它们重叠,我真的不知道如何解决这个问题。我尝试实现像(x1 - x2)^2 + (y1 - y2)^2 < (radius1 + radius2)^2这样的公式,但我不知道这个。

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:1)

你要做的事情被称为“包装”,实际上是一个非常难的问题。您可以在这里采取几种可能的方法。

首先,您可以随机分发它们(就像您目前正在做的那样),但包括“重试”测试,如果圆圈与另一个圆圈重叠,您可以尝试新的位置。由于可能最终处于不可能的情况,您还需要一个重试限制,此时它会放弃,返回到开头,并尝试再次随机放置它们。这种方法相对容易,但是由于重叠的可能性非常高,因此无法将它们打包得非常密集。如果圆圈覆盖了总面积的1/3,这可能会有效。

其次,您可以在添加更多时调整先前放置的圆圈的位置。这更像是在物理上如何完成 - 当你添加更多时,你开始不得不推开附近的那些以便适应新的。这不仅需要找到当前圆圈所击中的东西,还需要找到那些要移动的东西。我建议类似于“弹性”算法的东西,你随机放置所有圆圈(不考虑它们是否合适),然后有一个循环,你计算重叠,然后根据重叠在每个圆圈上施加一个力(他们互相推开)。这将使圆圈彼此远离,直到它们停止重叠。它还将支持一个圆圈将第二个圆圈推入第三个圆圈,依此类推。这将是更复杂的编写,但将支持更密集的配置(因为它们最终可能最终触摸)。你仍然可能需要一个“这是不可能的”检查,以防止它被卡住并永远循环。