Positioning Multiple, Random Sized, Absolutely Positioned Elements So They Don't Overlap

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.

Prevent absolutely-positioned elements from overlapping with text

Is a solution to create another div (div2) that overlaps the absolutely positioned div (div1), but is itself invisible? Then the rest of the text would avoid overlapping div2...

Sketched this out here: http://jsfiddle.net/VKYwD/8/

Not entirely clear on what your constraints are though.

Positioning Divs semi-randomly, without overlaps

The x-value is set on each one, you want to be as high on the page as possible (lowest y) as it can go without overlapping. Not too bad:

1) Render the container - position:relative; Render each item inside the container with "position:absolute; top:0; left:-1000; " - draw them all off screen.

2) One by one, move the element to it's needed x-coorinate and y=0; Check it with all previous render items to see if it collides, if it does, move it down one pixel until it doesn't collide:

var regions = [];
for(var i = 0; i < items.length; i++){
var item = items[i];

item.style.x = getX(item); // however you get this...
var region = YAHOO.util.Dom.getRegion(item);
var startingTop = region.top;
for(var iReg = 0; iReg < regions.length; iReg++){
var existingRegion = regions[iRegion];
while(region.intersect(existingRegion)){
region.top++;
region.bottom++;
}
item.style.y = (region.top - startingTop) + 'px';
}
}

It's important to just update the region and not actually move the dom node 1px at a time for performance reasons.

Put most important items first and they will render with more priority than items below them.

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);

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>

Divs keep moving around seemingly at random

Absolute positioned elements will move according to a fixed distance from the window border. So when you resize the window, all divs will move randomly because they aren't moving relatively to one another. To solve this, simply change all postition: absolute to

position: relative;

and then use a grid system like css grid or flexbox.



Related Topics



Leave a reply



Submit