J. Doe J. Doe - 2 months ago 7
CSS Question

overlapping absolutely positioned divs

I'm working on a little html5 game where the user has to click on a specified circle. I want the circles to change position every second randomly. I was able to make this. My only problem with it is that the circles often overlap one another. Is there any way I can prevent this? I've tried using margins, but that won't work because the circles have a position of absolute.
Here's the code for it:



//circles for game
var circle1 = document.getElementById('circle1');
var circle2 = document.getElementById('circle2');
var circle3 = document.getElementById('circle3');

//viewport height and width
var vh = 100;
var vw = 100;

//when the document loads, the circles change their position on screen
function changePosition() {
//Intercval that runs every second
setInterval ( function() {
//generates random numbers and assings them to the top and
//left properties of the circles
var circle1Top = Math.floor(Math.random() * vh ) + 1;
var circle2Top = Math.floor(Math.random() * vh ) + 1;
var circle3Top = Math.floor(Math.random() * vh ) + 1;
var circle1Left = Math.floor(Math.random() * vw) + 1;
var circle2Left = Math.floor(Math.random() * vw) + 1;
var circle3Left = Math.floor(Math.random() * vw) + 1;

//if the random number is greater than or equal to the device size, another number is generated
//this prevents the circles from appearing off screen


//circle1
while (circle1Top >= vh - 16 || circle1Top > vh) {
circle1Top = Math.floor(Math.random() * vh ) + 1;
};

while (circle1Left >= vw - 15 || circle1Top > vw) {
circle1Left = Math.floor(Math.random() * vw ) + 1;
};


//circle2
while (circle2Top >= vh - 16 || circle2Top > vh) {
circle2Top = Math.floor(Math.random() * vh ) + 1;
};

while (circle2Left >= vw - 15 || circle2Top > vw) {
circle2Left = Math.floor(Math.random() * vw ) + 1;
};


//circle3
while (circle3Top >= vh - 16 || circle3Top > vh) {
circle3Top = Math.floor(Math.random() * vh ) + 1;
};

while (circle3Left >= vw - 15 || circle3Top > vw) {
circle3Left = Math.floor(Math.random() * vw ) + 1;
};

//once the numbers are generated, they are assigned to the circles accordingly
circle1.style.top = circle1Top + 'vh';
circle1.style.left = circle1Left + 'vw';
circle2.style.top = circle2Top + 'vh';
circle2.style.left = circle2Left + 'vw';
circle3.style.top = circle3Top + 'vh';
circle3.style.left = circle3Left + 'vw';


}, 1000);
};

body {
background-color: aliceblue;
height: 100vh;
width: 100vw;
margin: 0;
overflow: hidden;
}

main {
width: 100%;
height: 100%;
margin: 0;
}

.circle {
width: 110px;
height: 110px;
background-color: blue;
border-radius: 50%;
position: absolute;
}

#circle1 {
background-color: red;
}

#circle2 {
background-color: blue;
}

#circle3 {
background-color: yellow;
}



/*media queries*/
@media only screen and (max-width: 435px) {
.circle {
width: 70px;
height:70px;
}
}

<!DOCTYPE html>
<html>

<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link type="text/css" rel="stylesheet" href="test.css">
</head>

<body onload="changePosition()">

<main>
<div class="circle" id="circle1"></div>
<div class="circle" id="circle2"></div>
<div class="circle" id="circle3"></div>
</main>

<!-- Scripts -->
<script type="text/javascript" src="test.js"></script>
</body>

</html>





Any responses are greatly appreciated.

Answer

You have to check if the circles overlap and if they do, reload the script. To check if they overlap you have to do some math:

1) Find out what the center of the circle is:

var circle1centerX = circle1Left * document.documentElement.clientHeight * 0.65 + 55;
var circle1centerY = circle1Top * document.documentElement.clientHeight * 0.65 + 55;

document.documentElement.clientHeight * 0.65 is the factor you need to multiply with to convert vh or vw to px. 55 is half the radius of the circles.

2) Check if circles overlap:

If the circles overlap, then the distance between their centers must be lower than two times the radius. If the distance between the centers is equal to or larger than two times the radius, they don't overlap. (In your case 2 times the radius is 110px)

var distanceBetween1and2 = Math.sqrt(Math.pow(circle2centerX - circle1centerX, 2) + Math.pow(circle2centerY - circle1centerY));
var distanceBetween1and3 = Math.sqrt(Math.pow(circle3centerX - circle1centerX, 2) + Math.pow(circle3centerY - circle1centerY));
var distanceBetween2and3 = Math.sqrt(Math.pow(circle3centerX - circle2centerX, 2) + Math.pow(circle3centerY - circle2centerY));

(Pythagorean theorem)

if(distanceBetween1and2 < 2*radius || distanceBetween2and3 < 2*radius || distanceBetween1and3 < 2*radius) {
  changePosition();
} else {
  //place the circles
}

But there is one disadvantage of this method, when the area in which the circles are, is small enough, so there must be circles overlapping, there will be an infinite loop. You can prevent this by setting a minimum size on the screen in which the circles are placed.