JavaScript automatically arranges child elements within their parent container in a random distribution without any overlapping

I am experimenting with creating a dynamic layout of circles (divs with border-radius) within a container without any overlap.

Check out my progress here - 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);
});

I've successfully added the circles to the container, but they are overlapping. I'm unsure how to resolve this issue. I attempted using a formula like

(x1 - x2)^2 + (y1 - y2)^2 < (radius1 + radius2)^2
, but it's beyond my expertise.

Any assistance would be greatly appreciated.

Answer №1

The task you are attempting to accomplish is known as "Packing" and poses quite a challenge. There are several potential strategies that could be pursued.

One approach involves randomly distributing the circles (as you are currently doing), but with an added "retry" feature. This means that if a circle ends up overlapping another, a new location is attempted. However, there should also be a limit on the number of retries in case the situation becomes impossible. While this method is relatively straightforward, it does have limitations in terms of packing density, as the chances of overlap increase significantly. This would work best when only about 1/3 of the total area needs to be covered by circles.

Another option is to adjust the positions of previously placed circles as new ones are added. This mimics a physical scenario where existing circles need to make room for new additions. A suggestion is to use a "springy" algorithm, where all circles are initially randomly placed without considering fit, then a loop calculates overlaps and applies forces to push circles apart until they no longer overlap. This approach allows for denser configurations, as circles may end up touching each other in the final layout. It will require more complexity in programming, but can handle more intricate arrangements. However, a check for impossibility is still recommended to prevent endless looping.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Spotting the Visible Element; Detecting the Element in

Currently, my webpage has a fixed header and I am facing the challenge of dynamically changing the styling of the li elements within the navigation based on the user's scrolling position. To achieve this, I believe the most effective approach would b ...

NodeJS is throwing a `ReferenceError` because the `io` variable is not

I am working on a NodeJS project and I need to access a variable that is defined in my app.js file from another file. Is this possible? Here is my code: app.js var app = express(); var io = require('socket.io').listen(app); ... otherFile ...

Experience choppy scrolling in Internet Explorer

Check out my click and drag scrolling Image Viewer here. While it functions perfectly in Firefox and Chrome, Internet Explorer is giving me some trouble. The movement seems jerky, especially when scrolling diagonally. It's like the scroll is sluggish ...

Cast your vote once for each post within the Angular application

Currently, users are only able to vote up or down once in general. I would like to allow users to vote up or down once per post. <div ng-repeat="post in posts | orderBy:'-upvotes'"> <span class="glyphicon glyphicon-thumbs-up" ...

Updating an existing value with a cascading dropdown list

My JavaScript code dynamically populates a dropdown list called District based on the selection made by the user in another dropdown list called Department. Here is the snippet of the code: Firstly, I populate the Department dropdownlist and add a ' ...

Loading modules conditionally in Nuxt.js

In my Nuxt.js configuration, I have included a module for Google Tag Manager like this: modules: [ [ '@nuxtjs/google-tag-manager', { id: 'GTM-XXXXXXX' } ] ] Everything is functioning properly, but I am curious ab ...

Using Styled Components to achieve full width for input tag in relation to its parent

I am working with an input field that has a specific width set. My goal is to increase the width of this input field to 100% by selecting it from its parent component. Is there a way to achieve this without passing an explicit width prop in the styled c ...

At times, the loading image fails to appear on Ajax

Take a look at my code below: function apply_image_effect(){ $.ajax({ url: "image/image.php", global: false, type: "POST", data: ({my_color:encodeURIComponent($('#my_color').val()),my_size:$('#my_size&apos ...

Guide on restricting the character count and displaying the leftover characters using PHP with Ajax

I've been working on implementing a feature to display the remaining characters in a PHP AJAX call. I was successful using JavaScript, but I'm having trouble doing it with AJAX in PHP. Can someone provide assistance? <script type="text/javasc ...

Retrieving Mouse Coordinates using Ajax in PHP

I'm wondering if it's feasible to send an Ajax request with mouse coordinates using PHP. For instance, I am fetching a page with cUrl and would like to trigger a mouse movement event on that page. At this point, I haven't written any code ...

The AJAX request is failing to reach the server

I'm currently using AJAX to populate a dropdown, but for some reason the call isn't reaching the server. Upon checking Firebug, I see the following error: POST 0 status 404 not found This is the code I'm working with: function selec ...

How can I create a computed field in TypeORM by deriving its value from other fields within the same Entity?

My goal is to implement a 'rating' field in my User Entity. Within the User Entity, there exists a relationship with the Rating Entity, where the User has a field called ratingsReceived that eagerly loads all Ratings assigned to that User. The & ...

Best practices for effectively managing a sizable dataset in Vue.js

My task at hand is to create a visualization dashboard that can operate solely in the browser, utilizing Vue.js, D3, and JavaScript. The dataset I am working with is stored in a .json file that is 48 MB in size. However, upon parsing the file using d3.json ...

You cannot nest a map function within another map function in React

Having some trouble applying the map function in HTML using React. Below is the code snippet: response = [ data : { name: 'john', title: 'john doe', images: { slider: { desktop: 'link1', mo ...

Error message stating 'compression is not defined' encountered while attempting to deploy a Node.js application on Heroku

Why is Heroku indicating that compression is undefined? Strangely, when I manually set process.env.NODE_ENV = 'production' and run the app with node server, everything works perfectly... Error log can be found here: https://gist.github.com/anony ...

Trouble Arising in Showing the "X" Symbol upon Initial Click in Tic-Tac-Toe Match

Description: I'm currently developing a tic-tac-toe game, and I've run into an interesting issue. When I click on any box for the first time, the "X" symbol doesn't show up. However, it works fine after the initial click. Problem Details: ...

Ways to activate javascript following a PHP submission?

It's a bit tricky to explain. function m(val){ var element=document.getElementById('othermethod'); if(val=='others') element.style.display='block'; else element.style.display=&apo ...

The feature for adding a function in Moment.js seems to be malfunctioning

Unfortunately, the moment().add() function is not functioning properly in my JavaScript code. var theDate = moment(event.start.format("YYYY-MM-DD HH:mm")); //start Date of event var checkquarter = theDate.add(30, 'minutes'); var plus = 30; if ...

Tips for accessing the @keyframes selector and extracting the value from it

In my CSS code, I have a shape element with an animation that spins infinitely for 50 seconds. #shape { -webkit-animation: spin 50s infinite linear; } @-webkit-keyframes spin { 0% { transform: rotateY(0); } 100% { transform: rotateY(-360deg ...

Having trouble with implementing a 64-bit bitwise AND operation in JavaScript?

I've been attempting to perform a bitwise AND operation on long numbers using Javascript. Despite trying the solutions provided at (How to do bitwise AND in javascript on variables that are longer than 32 bit?), none of them have been accurate for the ...