Check overlay for many divs issue - javascript

I want to check if some divs are overlaying. Here are the functions i'm using
function collision($div1, $div2) {
var x1 = $div1.offset().left;
var y1 = $div1.offset().top;
var h1 = $div1.outerHeight(true);
var w1 = $div1.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = $div2.offset().left;
var y2 = $div2.offset().top;
var h2 = $div2.outerHeight(true);
var w2 = $div2.outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
return false;
return true;
}
$("#flex[data-item-id]").each(function() {
var id_item = $(this).data('item-id');
var status = collision($('#c + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
});
I don't know why but in console put ok true and false...exact where it needs but the if(status) won't work so well..

Like #Rory McCrossan just told, you are missing a ' in your selector.
Try this code:
function collision($div1, $div2) {
var x1 = $div1.offset().left;
var y1 = $div1.offset().top;
var h1 = $div1.outerHeight(true);
var w1 = $div1.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = $div2.offset().left;
var y2 = $div2.offset().top;
var h2 = $div2.outerHeight(true);
var w2 = $div2.outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
return false;
return true;
}
$.each( "#flex[data-item-id]" , function() {
var id_item = $(this).data('item-id');
var status = collision($('#c' + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
});
EDIT: I adjusted the jQuery each function to the jQuery each documentation. I can't test if it's working untill you add your html code.

A working revision of your collision function, it checks for vertical overlap of both tops and bottoms in addition to horizontal overlaps to confirm an actual overlap.
function collision($div1, $div2) {
var x1 = $div1.offset().left,
y1 = $div1.offset().top,
b1 = $div1.outerHeight(true) + y1,
r1 = $div1.outerWidth(true) + x1;
var x2 = $div2.offset().left,
y2 = $div2.offset().top,
b2 = $div2.outerHeight(true) + y2,
r2 = $div2.outerWidth(true) + x2;
var v = false,
h = false,
collide = false;
if (b1 > y2 && b1 < b2) {
v = true;
}
if (b2 > y1 && b2 < b1) {
v = true;
}
// vertical overlap check
if (r1 > x2 && r1 < r2) {
h = true;
}
if (r2 > x1 && r2 < r1) {
h = true;
}
// horizontal overlap check
if (h && v) {
collide = true;
}
return collide
}
/*
$.each( "#flex[data-item-id]" , function() {
var id_item = $(this).data('item-id');
var status = collision($('#c' + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
}); */
$("#monitor").text(collision($('#alpha'), $('#beta')));
// display the result
#alpha {
position: absolute;
left: 3em;
top: 2em;
width: 4em;
height: 4em;
background: #489;
}
#beta {
position: absolute;
left: 4em;
top: 4em;
width: 4em;
height: 4em;
background: #498;
}
#monitor {
position: fixed;
bottom: 1em;
left: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="alpha"></div>
<div id="beta"></div>
<div id="monitor"></div>

Related

Collision fires only for the last DIV

I'm trying to trigger some events when one DOM element collide with another. A have a bunch of objects, how many I don't know, so I take them like querySelectorAll and then I'm trying to loop them via foreach. Everything works fine except - the even fires only for the last element. Does anyone know why?
Thank you!
Codepen — https://codepen.io/PavelLaptev/pen/ZEQPaRa
const isCollide = (a, b) => {
var x1 = a.offsetLeft;
var y1 = a.offsetTop;
var h1 = a.clientHeight;
var w1 = a.clientWidth;
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = b.offsetLeft;
var y2 = b.offsetTop;
var h2 = b.clientHeight;
var w2 = b.clientWidth;
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
return true;
};
const interactElements = document.querySelectorAll(".object");
const cursor = document.getElementById("cursor");
console.log(interactElements);
document.addEventListener("mousemove", (e) => {
let cursorPos = {
x: e.x - 20 / 2,
y: e.y - 20 / 2,
};
cursor.style.top = `${cursorPos.y}px`;
cursor.style.left = `${cursorPos.x}px`;
interactElements.forEach((item) => {
if (isCollide(cursor, item)) {
cursor.style.background = "blue";
} else {
cursor.style.background = "red";
}
});
})
.objects {
width: 300px;
height: 300px;
background: rgba(0,0,0,0.2);
}
.object {
width: 60px;
height: 60px;
background: rgba(0,0,0,0.5);
margin: 20px;
}
#cursor {
width: 20px;
height: 20px;
background: rgba(0,0,0,1);
border-radius: 20px;
position: absolute;
}
<div id="cursor"></div>
<div class="objects">
<div class="object"></div>
<div class="object"></div>
<div class="object"></div>
</div>
Change this:
interactElements.forEach((item) => {
if (isCollide(cursor, item)) {
cursor.style.background = "blue";
} else {
cursor.style.background = "red";
}
});
to:
cursor.style.background = Array.from(interactElements).some((item) => isCollide(cursor, item)) ? 'blue' : 'red'
const isCollide = (a, b) => {
var x1 = a.offsetLeft;
var y1 = a.offsetTop;
var h1 = a.clientHeight;
var w1 = a.clientWidth;
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = b.offsetLeft;
var y2 = b.offsetTop;
var h2 = b.clientHeight;
var w2 = b.clientWidth;
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
return true;
};
const interactElements = document.querySelectorAll(".object");
const cursor = document.getElementById("cursor");
console.log(interactElements);
document.addEventListener("mousemove", (e) => {
let cursorPos = {
x: e.x - 20 / 2,
y: e.y - 20 / 2,
};
cursor.style.top = `${cursorPos.y}px`;
cursor.style.left = `${cursorPos.x}px`;
cursor.style.background = Array.from(interactElements).some((item) => isCollide(cursor, item)) ? 'blue' : 'red'
})
.objects {
width: 300px;
height: 300px;
background: rgba(0,0,0,0.2);
}
.object {
width: 60px;
height: 60px;
background: rgba(0,0,0,0.5);
margin: 20px;
}
#cursor {
width: 20px;
height: 20px;
background: rgba(0,0,0,1);
border-radius: 20px;
position: absolute;
}
<div id="cursor"></div>
<div class="objects">
<div class="object"></div>
<div class="object"></div>
<div class="object"></div>
</div>

Hide an element when it touches other elements on the page with jQuery

I wanted to hide a sidebar element when it overlaps with the images on the page. I found a great answer on StackOverflow, but it doesn't entirely solve my problem. Right now, it only works with the first image on the page. It will hide the sidebar when it touches the first image. But it won't hide for the rest of the images. What should I do if I want it to work with all the images on the page?
Here is my code.
function collision ($div1, $div2) {
var x1 = $div1.offset().left
var y1 = $div1.offset().top
var h1 = $div1.outerHeight(true)
var w1 = $div1.outerWidth(true)
var b1 = y1 + h1
var r1 = x1 + w1
var x2 = $div2.offset().left
var y2 = $div2.offset().top
var h2 = $div2.outerHeight(true)
var w2 = $div2.outerWidth(true)
var b2 = y2 + h2
var r2 = x2 + w2
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) {
$div1.addClass('show')
} else {
$div1.removeClass('show')
}
}
window.setInterval(function () {
collision($('#content-nav'), $('.image-container'))
}, 100)
Here is how it's working right now. https://imgur.com/a/BvTyiDQ
What's happening is that you're calling only the first element with the image-container class, so it'll only check the topmost image-container. You have to retrieve all instances of image-container and check against them for overlap.
Here's what your collision function would look like & a working JSFiddle
function collision ($nav) {
var x1 = $nav.offset().left
var y1 = $nav.offset().top
var h1 = $nav.outerHeight(true)
var w1 = $nav.outerWidth(true)
var b1 = y1 + h1
var r1 = x1 + w1
var hide = false
$(".image-container").each(function() {
var x2 = $(this).offset().left
var y2 = $(this).offset().top
var h2 = $(this).outerHeight(true)
var w2 = $(this).outerWidth(true)
var b2 = y2 + h2
var r2 = x2 + w2
if (!(b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)) {
hide = true;
}
});
if (!hide) {
$nav.removeClass('hide')
} else {
$nav.addClass('hide')
}
}

Is this a bug? (JavaScript conditional)

I've got some code for part of a game where an absolutely positioned div (id = 'cursor') follows your mouse's cursor around. When the cursor div runs into another div (class = 'thing') (these are the white boxes in the jsfiddles), the cursor speed changes.
In this JSfiddle you'll see that it works perfectly fine. When cursor hits thing, cursor speeds up. This is the conditional used to change the speed (newSpeed is what determines the speed for cursor):
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 200;
changeCursorSpeed();
} else {
newSpeed = 12;
changeCursorSpeed();
console.log('hit');
}
The problem I'm having is when I switch around the values for newSpeed in the conditional:
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
Here's the JSFiddle for this. This causes the collision to not change newSpeed in the else part of the condition. However, using console.log('hit'), you can clearly see that the collision is detected.
Logically, this doesn't seem to make sense. I'd like to hear input from others about this as well as possible solutions. Thanks for any help.
Here's the entire code for the collision detection. The JSfiddles have a more complete code for the program.
var newSpeed;
var newInt = setInterval(function() {
function collision($cursor, $thing) {
var x1 = $cursor.offset().left;
var y1 = $cursor.offset().top;
var h1 = $cursor.outerHeight(true);
var w1 = $cursor.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
$thing.each(function(i){
var x2 = $(this).offset().left;
var y2 = $(this).offset().top;
var h2 = $(this).outerHeight(true);
var w2 = $(this).outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
});
function changeCursorSpeed(){
$xp += (($mouseX - $xp)/newSpeed);
$yp += (($mouseY - $yp)/newSpeed);
$("#cursor").css({left:$xp +'px', top:$yp +'px'});
}
}
$(collision($('#cursor'), $('.thing')));
}, 20);

Calling function inside jQuery returns wrong result

I have the following javascript code that runs fine if called outside the jQuery function on the bottom. I don't know what I am doing wrong.
Bresenham Algorithm:
function bresenham(x0,y0,x1,y1){
var bresenham = [];
var x = 0;
var dx = x1-x0;
var dy = y1-y0;
var D = 2 * dy - dx;
bresenham.push(x0 + "," + y0);
var y = y0;
for (x = x0+1;x<=x1;x++){
if (D>0){
y = y+1;
bresenham.push(x + "," + y);
D = D + (2*dy - 2*dx);
} else {
bresenham.push(x + "," + y);
D = D + (2*dy);
}
}
return bresenham;
};
JQuery:
$(document).ready(function(){
$(".button").click(function(){
$("div#output p").remove();
var x0 = $('input[name=x0]').val();
var y0 = $('input[name=y0]').val();
var x1 = $('input[name=x1]').val();
var y1 = $('input[name=y1]').val();
var bres = bresenham(x0,y0,x1,y1);
console.log(bres);
});
});
If I input: x0 = 1, y = 0 and x1 = 15, y2 = 9
it outputs: ["1,0", "11,01", "12,01", "13,011", "14,0111", "15,0111"]
I would change
$(document).ready(function(){
$(".button").click(function(){
$("div#output p").remove();
var x0 = $('input[name=x0]').val();
var y0 = $('input[name=y0]').val();
var x1 = $('input[name=x1]').val();
var y1 = $('input[name=y1]').val();
var bres = bresenham(x0,y0,x1,y1);
console.log(bres);
});
});
to
$(document).ready(function(){
$(".button").click(function(){
$("div#output p").remove();
var x0 = parseInt($('input[name=x0]').val());
var y0 = parseInt($('input[name=y0]').val());
var x1 = parseInt($('input[name=x1]').val());
var y1 = parseInt($('input[name=y1]').val());
var bres = bresenham(x0,y0,x1,y1);
console.log(bres);
});
});

Smooth random line, with loops, using Raphael/JS

$(document).ready(function(){
var x1 = Math.random()*$(window).width(); var y1 = Math.random()*$(window).height();
var x2 = 1; var y2 = 1;
var paper = Raphael(document.body);
setInterval(function() {
randx = Math.random(); randy = Math.random();
if (randx > 0.9) {
if (x2 = 1) {
if (randx > 0.99) x2 = -1;
}
else if (x2 = -1) {
if (randx > 0.99) x2 = 1;
}
} else x2 = 0;
if (randy > 0.9) {
if (y2 = 1) {
if (randy > 0.99) y2 = -1;
}
else if (y2 = -1) {
if (randy > 0.99) y2 = 1;
}
} else y2 = 0;
paper.path("M"+x1+" "+y1+"L"+(x1+x2)+" "+(y1+y2));
x1 = x1+x2;
y1 = y1+y2;
}, 0);
});
This is my "random line" generating script. I know it must look terrible, I am just learning. But I am trying to get something resembling this: http://i.stack.imgur.com/R7Kkv.png
I'd really appreciate some tips/suggestions for the algorithm that will make the line smoother and more likely to turn do a u-turn etc.
Thanks
The answer is to generate points within a 40x40 or so box around the previous point, and interpolate between them with a cubic spline.

Categories