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
What Is the Fastest or Most Elegant Way to Compute a Set Difference Using JavaScript Arrays
Wait 5 Seconds Before Executing Next Line
Difference Between (Function(){})(); and Function(){}();
Correct Way to Convert Size in Bytes to Kb, Mb, Gb in JavaScript
Differencebetween the Mouseover and Mouseenter Events
Passing Arguments Forward to Another JavaScript Function
Why How to Access Typescript Private Members When I Shouldn't Be Able To
How to Append Timestamp to the JavaScript File in <Script> Tag Url to Avoid Caching
Keydown Simulation in Chrome Fires Normally But Not the Correct Key
Jquery - Multiple $(Document).Ready ...
Can JavaScript Access a Filesystem
Detect Double Tap on iPad or iPhone Screen Using JavaScript
How to Fire an Event on Class Change Using Jquery
HTML Button to Not Submit Form
Find All Possible Subset Combos in an Array
Changing the Key Name in an Array of Objects