The question is published on by Tutorial Guruji team.
I have an animation like there are some boxes (actually they are divs) that are moving randomly and if any box hits with the walls of the parent container they bounce back and change their direction, everything works fine till here. The problem comes when I give the rotation to the boxes, by giving the rotation the boxes are going out of the parent container and not colliding with the walls of the parent container. So I want to know why this is happening and how to fix that like boxes have to collide with the walls container while rotating.
Here is my code
document.addEventListener("DOMContentLoaded", e => { const test = document.querySelectorAll(".test") test.forEach(function(many) { let rect = many.getBoundingClientRect(), rectBox = many.parentNode.getBoundingClientRect(), xMax = rectBox.width + rectBox.x - rect.width, yMax = rectBox.height + rectBox.y - rect.height, maxSpeed = 1; let x = rect.x, y = rect.y, xDelta, yDelta; setSpeed(); many.addEventListener("click", setSpeed); window.requestAnimationFrame(move); many.classList.toggle("move", true); function move(timestamp) { x = x + xDelta; y = y + yDelta; if (x < rectBox.x || x > xMax) { xDelta = -xDelta; x = x < rectBox.x ? rectBox.x : xMax; } if (y < rectBox.y || y > yMax) { yDelta = -yDelta; y = y < rectBox.y ? rectBox.y : yMax; } many.style.transform = `rotate(${x/2}deg)` many.style.left = x + "px"; many.style.top = y + "px"; window.requestAnimationFrame(move); }; //console.log(xDelta) function setSpeed() { xDelta = rand(-maxSpeed, maxSpeed); yDelta = rand(-maxSpeed, maxSpeed); } function rand(min, max) { return Math.random() * (max - min + 1) + min; } }) });
html, body { height: 100%; margin: 0; padding: 0; user-select: none; } .box { width: 500px; height: 500px; border: 2px solid red; margin: 0 auto; position: relative; margin-top: 50px; } * { box-sizing: border-box; } body { background-color: #fff; text-align: center; } .bgcolor { background-color: black; color: rgba(255, 255, 255, 0.8); } .test { width: 100px; height: 100px; margin: 0 auto; display: flex; flex-wrap: wrap; background-color: #FCD757; } .move { margin: 0; position: absolute; } .check { border: 2px solid black; width: 50px; height: 105px; } .big { width: 120px; }
<div class="box"> <div id="test" class="test"></div> <div class="test"></div> <div class="test"></div> <div class="test big"></div> <div class="test big"></div> <div class="test big"></div> <div class="test"></div> </div>
Answer
Remove position:relative;
from .box
class. It will contain the boxes within the parent, however because rect
is used outside of move
function it contains non-rotated dimensions of the box which does not properly render box collision:
document.addEventListener("DOMContentLoaded", e => { const test = document.querySelectorAll(".test") test.forEach(function(many) { let rect = many.getBoundingClientRect(), rectBox = many.parentNode.getBoundingClientRect(), xMax = rectBox.width + rectBox.x - rect.width, yMax = rectBox.height + rectBox.y - rect.height, maxSpeed = 1; //dotted box const boundBox = document.createElement("div"); boundBox.className = "boundBox"; boundBox.addEventListener("click", setSpeed); document.body.appendChild(boundBox); let x = rect.x, y = rect.y, xDelta, yDelta; setSpeed(); many.addEventListener("click", setSpeed); window.requestAnimationFrame(move); many.classList.toggle("move", true); function move(timestamp) { x = x + xDelta; y = y + yDelta; if (x < rectBox.x || x > xMax) { xDelta = -xDelta; x = x < rectBox.x ? rectBox.x : xMax; } if (y < rectBox.y || y > yMax) { yDelta = -yDelta; y = y < rectBox.y ? rectBox.y : yMax; } many.style.transform = `rotate(${x/2}deg)` many.style.left = x + "px"; many.style.top = y + "px"; boundBox.style.left = x + "px"; boundBox.style.top = y + "px"; boundBox.style.width = rect.width + "px"; boundBox.style.height = rect.height + "px"; window.requestAnimationFrame(move); }; //console.log(xDelta) function setSpeed() { xDelta = rand(-maxSpeed, maxSpeed); yDelta = rand(-maxSpeed, maxSpeed); } function rand(min, max) { return Math.random() * (max - min + 1) + min; } }) });
html, body { height: 100%; margin: 0; padding: 0; user-select: none; } .box { width: 500px; height: 500px; border: 2px solid red; margin: 0 auto; /* position: relative;*/ margin-top: 50px; } * { box-sizing: border-box; } body { background-color: #fff; text-align: center; } .bgcolor { background-color: black; color: rgba(255, 255, 255, 0.8); } .test { width: 100px; height: 100px; margin: 0 auto; display: flex; flex-wrap: wrap; background-color: #FCD757; } .move { margin: 0; position: absolute; } .check { border: 2px solid black; width: 50px; height: 105px; } .big { width: 120px; } .boundBox { position: absolute; border: 1px dotted black; }
<div class="box"> <div id="test" class="test"></div> <div class="test"></div> <div class="test"></div> <div class="test big"></div> <div class="test big"></div> <div class="test big"></div> <div class="test"></div> </div>
To fix that, we need to get box rect
for each frame and for both before and after it was rotated:
document.addEventListener("DOMContentLoaded", e => { const test = document.querySelectorAll(".test"); test.forEach(function(many){ const rectBox = many.parentNode.getBoundingClientRect(), rect = many.getBoundingClientRect(), maxSpeed = 1; //dotted box const boundBox = document.createElement("div"); boundBox.className = "boundBox"; boundBox.addEventListener("click", setSpeed); document.body.appendChild(boundBox); let x = rect.x, y = rect.y, xDelta, yDelta; setSpeed(); many.addEventListener("click", setSpeed); window.requestAnimationFrame(move); many.parentNode.classList.toggle("move", true); function move(timestamp) { x = x + xDelta; y = y + yDelta; many.style.transform = ""; const rectInit = many.getBoundingClientRect(); many.style.transform = `rotate(${x/2}deg)`; const rectBox = many.parentNode.getBoundingClientRect(), rect = many.getBoundingClientRect(), xDif = rect.x - rectInit.x, yDif = rect.y - rectInit.y, xMin = rectBox.x - xDif, yMin = rectBox.y - yDif, xMax = rectBox.width + rectBox.x - rect.width - xDif, yMax = rectBox.height + rectBox.y - rect.height - yDif; if (x < xMin || x > xMax) { xDelta = -xDelta; x = x < xMin ? xMin : xMax; } if (y < yMin || y > yMax) { yDelta = -yDelta; y = y < yMin ? yMin : yMax; } many.style.left = x + "px"; many.style.top = y + "px"; boundBox.style.left = x + xDif + "px"; boundBox.style.top = y + yDif + "px"; boundBox.style.width = rect.width + "px"; boundBox.style.height = rect.height + "px"; window.requestAnimationFrame(move); } //move() //console.log(xDelta) function setSpeed() { xDelta = rand(-maxSpeed, maxSpeed); yDelta = rand(-maxSpeed, maxSpeed); } function rand(min, max) { return Math.random() * (max - min + 1) + min; } }) //forEach });
html, body { height: 100%; margin: 0; padding: 0; user-select: none; } .box { width: 500px; height: 500px; border:2px solid red; margin: 0 auto; /* position:relative;*/ margin-top: 50px; } *{ box-sizing:border-box; } body { background-color: #fff; text-align: center; } .bgcolor { background-color: black; color: rgba(255, 255, 255, 0.8); } .test { width:100px; height:100px; margin:0 auto; display:flex; flex-wrap:wrap; background-color: #FCD757; } .move .test { margin: 0; position: absolute; } .check{ border:2px solid black; width:50px; height:105px; } .big{ width:120px; } .boundBox { position: absolute; border: 1px dotted black; }
<div class="box"> <div id="test" class="test"></div> <div class="test"></div> <div class="test"></div> <div class="test big"></div> <div class="test big"></div> <div class="test big"></div> <div class="test"></div> </div>