﻿ Generate Random Element Position and Prevent Overlapping in JavaScript - ITCodar

# Generate Random Element Position and Prevent Overlapping in JavaScript

## Prevent overlap of randomly placed elements

There's a few different ways you can do to achieve this. I find it easiest to try to define the problem in one sentence:

New square's position must be at least X distance from current square positions

Using this sentence, we can make some simple theories as to how the code will work.

Assuming all squares are 50x50 pixels, we can write some checks.

Here are some pseudo code steps we could follow:

• Generate a random position for `newSquare`
• Compare the `x` and `y` positions of `newSquare` to all existing squares
• If either of the `x` and `y` positions of `newSquare` are further away from the other squares, `newSquare` can be placed
• Otherwise, try again

``var container = \$('#container');var squareSize = 50;var containerSize = 500;for (var i = 0; i < 20; i++) {  var foundSpace = false;  while (!foundSpace) {    // Generate random X and Y    var randX = Math.floor(Math.random() * (containerSize - squareSize));    var randY = Math.floor(Math.random() * (containerSize - squareSize));    var hitsSquare = false;    var squares = container.children();    squares.each(function(index, square) {      var square = \$(square);            // parseInt() because .css() returns a string      var left = parseInt(square.css('left'));      var top = parseInt(square.css('top'));            // Check boundaries      var hitsSquareX = Math.abs(left - randX) < squareSize;      var hitsSquareY = Math.abs(top - randY) < squareSize;      // Will overlap a square      if (hitsSquareX && hitsSquareY) {        hitsSquare = true;        // jQuery break .each()        return false;      }    });    // If doesn't overlap any square    if (!hitsSquare) {      foundSpace = true;      var newSquare = \$('<div class="square">');      newSquare.offset({        left: randX,        top: randY      });      container.append(newSquare);    }  }}``
``#container {  position: relative;}.square {  position: absolute;  background-color: red;  width: 48px;  /* border adds 2px */  height: 48px;  /* border adds 2px */  border: 1px solid black;}``
``<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div id="container"></div>``

## Generate random element position and prevent overlapping in JavaScript

I guess there is no plugin. I will implement this like Sander suggested by making predefined div grid and just loading random images to those divs. It's easier and faster than calculating image dimenssions/positions and does pretty much the same job. Not random but visually looks good :)

## How to avoid overlapping of random numbers?

You need to loop over the random number generator for the amount of times you wish to display the created number element in the circle. You can create and return an array of values in `randomValue()` function, then loop over that array in `randNum()` function.

Also, I assume you want the output of the appended element to spread out over the entirety of the circle element yes? If so, you need to randomize the position of the element relative to the size of the circle, not the `randomValue` functions returned value.

#### EDIT:

OP asked after posting answer: There are some numbers at circles border side which are not properly visible how to solve that?

Because of the box model of elements, the border of the circle element is square, not round though the viewable content of the circle element is round due to its border-radius css.

You can use a helper function that will determine if the randomly generated numbers for x and y, or left and top, are within the `border-radius` of the circle element using the size of the radius and the center point of the x and y coords of the circle.

Credit for helper function: Simon Sarris:

``function pointInCircle(x, y, cx, cy, rad) {  const distancesquared = (x - cx) * (x - cx) + (y - cy) * (y - cy);  return distancesquared <= rad * rad;}``

We wrap everything inside a while loop that checks if a counter has reached 50. Inside the loop we run the function that creates the randomly generated positions -> `randomPos()`. Then we run a conditional that will check to see if the randomly generated points are within the circle using the function `pointInCircle(x, y, cx, cy, rad)`. If this conditional returns true we create the number elements, style and append the number elements to the circle and iterate our counter value by one.

``const circle = document.querySelector(".circle");const addNumBtn = document.querySelector('#addNumBtn');// we set the width of the circle element in JS and pass// it to CSS using a css variable and the root elementconst circleWidth = 350;document.documentElement.style.setProperty('--circleWidth', `\${circleWidth}px`);// NOTE: '~~' -> is quicker form of writing Math.floor() // runs faster on most browsers.function randomPos(min, max) {  return ~~(Math.random() * (max - min + 1) + min)}// return a random value between 1 and 50function randomValue(){  return ~~(Math.random() * 50) + 1;}function randomColor() {  let r = ~~(Math.random() * 255) + 1;  let g = ~~(Math.random() * 255) + 1;  let b = ~~(Math.random() * 255) + 1;  return `rgba(\${r},\${g},\${b})`}function randomSize() {  let size = ~~(Math.random() * 30) + 8;  return `\${size}px`}// add a helper function to find the center of the // circle and calculate distance to the edge of circle// x and y are the randomly generated points// cx, cy are center of circle x and y repsectively// rad is circle radiusfunction pointInCircle(x, y, cx, cy, rad) {  const distancesquared = (x - cx) * (x - cx) + (y - cy) * (y - cy);  return distancesquared <= rad * rad;}// you can remove valArray array if you do not want the 50 numbers to not be repeatedconst valArray = [];function randNum() {  // add a counter  let count = 1;  // while loop to check if the counter has reached the target 50  while (count <= 50) {    // set the randomly generated val    let val = randomValue();    // random size = string with px added    let randSize = randomSize();    // random size = the exact number => typeof number     let posSize = randSize.split('px')[0];    // an array to hold our randomly positioned number values    // uses helper function randonPos    // pass in the 1 and the circle width minus the font size    let ran = [randomPos(1, circleWidth - posSize), randomPos(1, circleWidth - posSize)];    // conditional to check bounds of circle using helper function    // we pass in the ran array, center points and radius    // we add buffers to accommodate for the font size    // you can remove !valArray.includes(val) if you do not want the 50 numbers to not be repeated    if (pointInCircle(ran[0], ran[1], circleWidth/2-posSize, circleWidth/2-posSize, circleWidth / 2 - posSize) && !valArray.includes(val)) {      // you can remove valArray.push(val); if you do not want the 50 numbers to not be repeated      valArray.push(val);      // if the conditional returns true,       // create the element, style and append      let randnum = document.createElement("p");      randnum.classList.add('numStyle');      randnum.style.color = randomColor();      randnum.style.fontSize = randSize;      randnum.textContent = val;      randnum.style.position = 'absolute';      randnum.style.top = `\${ran[0]}px`;      randnum.style.left = `\${ran[1]}px`;      circle.append(randnum);      // iterate the counter      count++;    }  }}addNumBtn.addEventListener('click', randNum)``
``html {  --circle-width: 300px;}.circle {    aspect-ratio: 1;  width: var(--circleWidth);  background-color: black;  border-radius: 50%;  position: relative;  overflow: hidden;  padding: .5rem;}#addNumBtn {  position: absolute;  top: 0;  left: 0;}.numStyle {  font-family: "roboto", sans-serif;}``
``//On Clicking button Click Me! I want to place all the random numbers inside the circle //together not one by one, at a time all numbers should be placed inside the circle by //clicking the button Click Me!<div id="container"></div><div class="circle"></div><button id="addNumBtn">Click Me!</button>``

## Generate numbers in side div at random position without overlapping

You've got most of it figured out. You just need to think of the `.container` div as a grid to avoid any overlap or outlying items.

Just check out this fiddle.

Here's what the code looks like:

``var tilesize = 18, tilecount = 15;var gRows = Math.floor(\$(".container").innerWidth()/tilesize);var gCols = Math.floor(\$('.container').innerHeight()/tilesize);var vals = _.shuffle(_.range(tilecount));var xpos = _.shuffle(_.range(gRows));var ypos = _.shuffle(_.range(gCols));_.each(vals, function(d,i){    var \$newdiv = \$('<div/>').addClass("tile");    \$newdiv.css({        'position':'absolute',        'left':(xpos[i] * tilesize)+'px',        'top':(ypos[i] * tilesize)+'px'    }).appendTo( '.container' ).html(d);  });``

PS:I have used underscore in my fiddle to make things easier for me and because I personally hate writing `for` loops.

## How to make sure randomly generated Divs don't overlap

Interestingly you have all of the code that you need to achieve this already. That is two things:

• A function to check if rectangles overlap. That's already in the code: `getOverlap`
• A way to check if a new rectangle placement would overlap with an existing one. That's essentially the same as the final loop.

So all I've done is add some code into the div placement loop, which makes it look at every previous div, to see if they would overlap. If they would overlap, it just generates a new position. This continues until a free location is found.

If no location is found after 50 attempts, the rectangle will be randomly placed anywhere, even if it overlaps. This ensures that we don't end up in an infinite loop, which would occur if the window was tiny and there wasn't enough room to place all rectangles in a non-overlapping way.

I've also increased the amount of rectangles to five, which increases the chance for a collision.

That's here:

(I've made the divs smaller in this version, because the snippet window is very small.)

`` // Returns largest div's width and height function getMaxDimension(arr) {   var maxWidth = 0;   for (var i = 0; i < div_selection.length; i++) {     if (div_selection[i].offsetWidth > maxWidth) {       maxWidth = div_selection[i].offsetWidth;     }   }   var maxHeight = 0;   for (var i = 0; i < div_selection.length; i++) {     if (div_selection[i].offsetHeight > maxHeight) {       maxHeight = div_selection[i].offsetHeight;     }   }   var values = {     maxWidth: maxWidth,     maxHeight: maxHeight   };   return values; } // Retruns a random number x; min < x < max function getRandomNumber(min, max) {   return Math.random() * (max - min) + min; } // returns the position in xy-space of every corner of a rectangular div function getOffset(element) {   var position_x = element.offsetLeft;   var position_y = element.offsetTop;   var height_x = element.offsetWidth;   var height_y = element.offsetHeight;   var tolerance = 0; // will get doubled   return {     A: {       y: position_y - tolerance,       x: position_x - tolerance     },     B: {       y: position_y + height_x + tolerance,       x: position_x - tolerance     },     C: {       y: position_y + height_x + tolerance,       x: position_x + height_y + tolerance     },     D: {       y: position_y - tolerance,       x: position_x + height_y + tolerance     }   }; } // Returns true if any corner is inside the coordinates of the other div function getOverlap(div1, div2) {   coor_1 = getOffset(document.getElementById(div1));   coor_2 = getOffset(document.getElementById(div2));   return (     (coor_1.A.x <= coor_2.A.x && coor_2.A.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.A.y && coor_2.A.y <= coor_1.B.y) ||     (coor_1.A.x <= coor_2.B.x && coor_2.B.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.B.y && coor_2.B.y <= coor_1.B.y) ||     (coor_1.A.x <= coor_2.C.x && coor_2.C.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.C.y && coor_2.C.y <= coor_1.B.y) ||     (coor_1.A.x <= coor_2.D.x && coor_2.D.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.D.y && coor_2.D.y <= coor_1.B.y)   ); } // Number to Letter function getChar(n) {   var ordA = 'a'.charCodeAt(0);   var ordZ = 'z'.charCodeAt(0);   var len = ordZ - ordA + 1;   var s = "";   while (n >= 0) {     s = String.fromCharCode(n % len + ordA) + s;     n = Math.floor(n / len) - 1;   }   return s; } var div_selection = document.getElementsByClassName("random"); maxDimensions = getMaxDimension(div_selection); var widthBoundary = maxDimensions.maxWidth; var heightBoundary = maxDimensions.maxHeight; for (var i = 0; i < div_selection.length; i++) {   var isOverlapping = false;   var attemptCount = 0;   do {     randomLeft = getRandomNumber(0, window.innerWidth - widthBoundary);     randomTop = getRandomNumber(0, window.innerHeight - heightBoundary);     div_selection[i].style.left = randomLeft + "px";     div_selection[i].style.top = randomTop + "px";          isOverlapping = false;     for (var j = 0; j < i; j++) {        if (getOverlap(getChar(i), getChar(j))) {        isOverlapping = true;        break;      }     }   } while (++attemptCount < 50 && isOverlapping); } // check every element for (var i = 0; i < div_selection.length; i++) {   for (var j = i + 1; j < div_selection.length; j++) {     console.log(i, j)     console.log(getChar(i), getChar(j))     console.log(getOverlap(getChar(i), getChar(j)))   } }``
``div {  width: 60px;  height: 60px;  position: absolute;}#a {  background-color: pink;}#b {  background-color: lightblue;}#c {  background-color: lightgreen;}#d {  background-color: silver;}#e {  background-color: yellow;}``
``<html>  <body>    <div class="random" id="a">Div1</div>    <div class="random" id="b">Div2</div>    <div class="random" id="c">Div3</div>    <div class="random" id="d">Div4</div>    <div class="random" id="e">Div5</div>  </body></html>``

## How to prevent randomly generated images from overlapping using Javascript

The area you want to exclude in the centre of the screen is rather large, and on my little laptop, there isn't even any room to still show the random positioned images.

But anyway, this piece of code should do the job -- I added some infinite loop protection which on my PC was a life-saver:

### HTML (added `style` attribute)

``<div id="targetsDiv">    <img src="target2.png" alt="target_shot" class="target"         style="visibility:hidden"/></div>``

### JavaScript:

``window.addEventListener('load', function () {    var targetCollection = document.getElementById("targetsDiv");    var template = document.getElementsByClassName("target")[0];    var targetWidth = template.offsetWidth;    var targetHeight = template.offsetHeight;    var x_pixels = window.innerWidth - targetWidth;    var y_pixels = window.innerHeight - targetHeight;    var x_midScreen = window.innerWidth / 2;    var y_midScreen = window.innerHeight / 2;    function spawnTargets (numberOfSpawns) {        var targets = [];        var count = 0; // infinite recursion protection        for (var i = 0; i < numberOfSpawns; i++) {            do {                do {                    var x = Math.floor(Math.random()*x_pixels);                    var y = Math.floor(Math.random()*y_pixels);                    if (count++ > 200) {                        console.log('give up');                        return;                    }                } while ((x >= x_midScreen-450 && x <= x_midScreen+300) && (y >= y_midScreen-350 || y <= y_midScreen+200));                for (var j = 0; j < i; j++) {                    if (x >= targets[j].x - targetWidth && x <= targets[j].x + targetWidth &&                         y >= targets[j].y - targetHeight && y <= targets[j].y + targetHeight) break; // not ok!                }            } while (j < i);            targets.push({x, y});            img = document.createElement('img');            img.src = template.src;            img.setAttribute('width', targetWidth + 'px');            img.setAttribute('height', targetHeight + 'px');            img.className = template.className;            targetCollection.appendChild(img);            img.style.left = x + "px";            img.style.top = y + "px";        }    }    spawnTargets(3);});``

## Randomly positioned divs with no overlapping

Ammend your JavaScript to the following. This stores each box's dimensions and checks each new box against overlaps.

``var boxDims = new Array();function setRandomPos(elements,x,dx){  elements.each(function(){    var conflict = true;    while (conflict) {        fixLeft=(Math.floor(Math.random()*x)*10) + dx;        fixTop = (Math.floor(Math.random()*40)*10) + 180;        \$(this).offset({            left: fixLeft,            top: fixTop        });        var box = {            top: parseInt(window.getComputedStyle(\$(this)[0]).top),            left: parseInt(window.getComputedStyle(\$(this)[0]).left),            width: parseInt(window.getComputedStyle(\$(this)[0]).width),            height: parseInt(window.getComputedStyle(\$(this)[0]).height)        }        conflict = false;        for (var i=0;i<boxDims.length;i++) {            if (overlap(box,boxDims[i])) {                conflict = true;                break;            } else {                conflict = false;            }                           }    }    boxDims.push(box)      });}function overlap(box1,box2) {  var x1 = box1.left  var y1 = box1.top;  var h1 = box1.height;  var w1 = box1.width;  var b1 = y1 + h1;  var r1 = x1 + w1;  var x2 = box2.left;  var y2 = box2.top;  var h2 = box2.height;  var w2 = box2.width;  var b2 = y2 + h2;  var r2 = x2 + w2;  var buf = 24;  if (b1 + buf < y2 || y1 > b2 + buf || r1 + buf < x2 || x1 > r2 + buf) return false;  return true;}setRandomPos(\$(".boxes"),40,40);``

## Positioning multiple, random sized, absolutely positioned elements so they don't overlap

I'm not sure if you also want to position the words randomly inside a container, but i've written a fiddle that does just that. You can modify the code to position one word right after the other if you want to though. I think the key part is the method to check if there's a collision.

see http://jsfiddle.net/fZtdt/13/

EDIT: Be aware that this is very simple and unoptimized code. If for example you would add to many words, chances are that the script won't be able to fit all words inside the container, and get into an endless loop.

## Javascript Randomly Positioned Div's without overlapping them

The algorithm would look something like this; I might have made a mistake though

1. Get the document's height and width y = docH, x = docW
2. Subtract the `<div>`'s height and width, y = y - divH, x = x - divH
3. Choose random co-ordinates curX, curY between 0..x, 0..y
4. newX = curX, newY = curY
5. For each previous `<div>`
1. Call it's info prevX, prevY, prevW, prevH
2. If prevX < curX then newX = newX + prevW
3. If prevY < curY then newY = newY + prevH
6. Append `<div>` at newX, newY
7. Save `<div>` info curX, curY, divW, divH
8. If there is another `<div>`, go to step 2.

Submit