Magnus Pääru Magnus Pääru - 1 month ago 11
Javascript Question

JS: How to check collision of a lot of elements?

I have randomly generated 40 img with random position, but at some case some of these img collide.

So my question would be how to check that they don't collide and give new positions if they collide?

I have my code below and there is also comments to make it clear.

$( document ).ready(function() {
var viewport = $(window).height();
var pageHeight = $(document).height();
var pageWidth = $(document).width();
var x = 1;
var y = 1;
var itemsPerPage = Math.floor(pageHeight / viewport * 10);

var imgsArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];

//Generate random nr for picking one of the images
function generateRandomForArray() {
var num = Math.floor(Math.random() * 9);
return num;
}

//Generate random nr for picking one of the left position (max is page width)
function generateLeftRandom() {
var num = Math.floor(Math.random() * pageWidth);
return num;
}

//Generate random nr for picking one of the top position (max is page height)
function generateTopRandom() {
var num = Math.floor(Math.random() * pageHeight);
return num;
}

//Generate random nr for parallax data-velocity value
function generateVelocityRandom() {
var num = Math.random() * (0.1 - -0.1) + -0.1;;
return num;
}

showLetter();

//Attach img tags with random img src to #toAttachElements container
function showLetter() {
var letter = imgsArray[generateRandomForArray()];

$("#toAttachElements").append("<img class='parallax' data-velocity='" + generateVelocityRandom() + "' src='wp-content/themes/thenewtonstartertheme/img/bg-elements/" + letter + ".png'>");

x++;

if (x < itemsPerPage) {
showLetter();
}
}

//Add random positions to previosly attached imgs
$('#toAttachElements > img').each( function(){
var left = generateLeftRandom();
var top = generateTopRandom();

$(this).css({"position":"absolute","z-index":"1","top": top + "px", "left": left + "px"});
});

});


EDIT! Solution what I eventually came up is that I divide my page into rows and on every row can be one img. Code below.

$( document ).ready(function() {
if ($(".to-attach-elements")[0]){
var viewport = $(window).height();
var pageHeight = $(document).height();
var pageWidth = $(document).width();
var x = 1;
var y = 1;
var itemsPerPage = Math.floor(pageHeight / viewport * 10);

var topRows = Math.floor(pageHeight / itemsPerPage);

var imgsArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];

//Generate random nr for picking one of the images
function generateRandomForArray() {
var num = Math.floor(Math.random() * 9);
return num;
}

//Generate random nr for picking one of the left position (max is page width)
function generateLeftRandom() {
var num = Math.floor(Math.random() * pageWidth);
return num;
}

//Generate random nr for picking one of the top position (max is page height)
function generateTopRandom() {
var num = Math.floor(Math.random() * topRows);
return num;
}

//Generate random nr for parallax data-velocity value
function generateVelocityRandom() {
var num = Math.random() * (0.1 - -0.1) + -0.1;;
return num;
}

var top = generateTopRandom();

showLetter();

//Attach img tags with random img src to #toAttachElements container
function showLetter() {
var letter = imgsArray[generateRandomForArray()];

$(".to-attach-elements").append("<img class='parallax' data-velocity='" + generateVelocityRandom() + "' src='wp-content/themes/thenewtonstartertheme/img/bg-elements/" + letter + ".png'>");

x++;

if (x < itemsPerPage) {
showLetter();
}
}

//Add random positions to previosly attached imgs
$('.to-attach-elements > img').each( function(){
var left = generateLeftRandom();

$(this).css({"position":"absolute","z-index":"1","top": top + "px", "left": left + "px"});

top = top + topRows;
});
}
});

Answer

You first need to get a random position for your image and then check it against the positions of all images already added to the page. If the positions intersects then you need to generate a new position.

The following code will place every image in a random position and make sure so there are no intersections. Notice that this code assumes that every image has the same width and height i.e 32x32.

function pointInPoint(point1, point2) {
  return !(point1.left > point2.left + 32 || 
           point1.left + 32 < point2.left || 
           point1.top > point2.top + 32 ||
           point1.top + 32 < point2.top);
}

var images = $('#toAttachElements > img');
var current = 0;
var position = {};
do {
  // get a random position
  position = { left: generateLeftRandom(), top: generateTopRandom() };
  // check for intersections
  for(var i = 0; i < images.length; i++) {
    if(pointInPoint($(images[i]).position(), position)) {
      break;
    }
  }
  if(i == images.length) {
    $(images[current]).css({"position":"absolute", "z-index":"1", "top": position.top + "px", "left": position.left + "px"});
    current++;
  }
} while(current < images.length);

If you would like to use different sizes for you could change the pointInPoint to use rectangles instead. Then you need to get the width and height for each image and modify the parameters accordingly.