Check if element is in viewport doesn't work properly - javascript

I've got three elements - every element is hidden from the start. If user scrolls onto them, they show up. I wrote a function that checks if element named bubbles is inside viewport. If it is, then function should show the rest of the elements.
But it doesn't. Element boxes is higher than element bubbles, and it also fires a function. But it shouldn't. I have no idea where the problem is.
document.addEventListener("scroll", checkViewport);
function checkViewport() {
var bubbles = document.getElementsByClassName("bubble-chat");
var boxes = document.getElementsByClassName("boxes");
var avatar = document.getElementsByClassName("msg-avatar");
for (let i = 0; i < avatar.length; i++) {
var bounding = bubbles[i].getBoundingClientRect();
if (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight)
) {
avatar[i].style.opacity = "1";
bubbles[i].style.opacity = "1";
(function(i) {
setTimeout(function() {
bubbles[i].style.display = "none";
boxes[i].style.opacity = "1";
}, 3000);
})(i);
}
}
}

you should also consider the scrolling positioning as the bounding box is relative to that.
Fixed code:
bounding.top >= document.documentElement.scrollTop &&
bounding.left >= 0 &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <= document.documentElement.scrollTop + (window.innerHeight || document.documentElement.clientHeight)

Well, I feel stupid. The code was okay all the time. I just commented one of the msg-text divs, and turns out, that it was the reason for the code to break.

Related

Dry-er Way of Writing a Bunch of If Else Statements

I have a variable placement that can be set to the following values: top, top-left, top-right, bottom, bottom-left, bottom-right, right, right-top, right-bottom, left, left-top, left-bottom.
I have another variable const trigger = triggerRef.current.getBoundingClientRect(); so I can determine where the trigger element is, and based on that, set the placement variable accordingly.
I am currently using a lot of if else statements. For instance:
if (placement === "top" && trigger.top < 75 && windowWidth - trigger.right > 75 && trigger.left > 175)
{ placement = "bottom";
} else if ( placement === "top" && windowWidth - trigger.right < 75 && windowHeight - trigger.bottom > 75 && trigger.top < 75)
{ placement = "left-top"; }
...and the code goes on and on
What's a "DRY-er" way of doing this?
Consolidate the logic in these tests and only check once. Assign a variable if instead of repeating the same calculations:
if (placement === "top" && trigger.top < 75 ) {
const triggerFromWidth = windowWidth - trigger.right;
if (triggerFromWidth > 75 && trigger.left > 175) {
placement = "bottom";
} else if (triggerFromWidth < 75 && windowHeight - trigger.bottom > 75) {
placement = "left-top";
}
}

How to programmatically tell if two absolutely positioned elements overlap?

I don't think there's any such method in the DOM API like element.doesOverlap(otherElement), so I think I have to calculate this by hand, right? Not sure if there are any shortcuts.
If not, what is the method for this? It seems like there's so many ways something could overlap....it would be so many conditionals. Is there a concise way of writing this?
In pseudo code, I have this:
if (
((A.top < B.bottom && A.top >= B.top)
|| (A.bottom > B.top && A.bottom <= B.bottom))
&&
((A.left < B.right && A.left >= B.left)
|| (A.right > B.left && A.right <= B.right))) {
// elements A and B do overlap
}
^Is this the simplest way?
This is essentially and x,y comparison problem. You essentially need to compare the two element by there x,y positions at all boundaries ( top, right, bottom and left ) if they overlap anywhere.
A simple method would be, to test that they don't overlap.
Two items could be considered to overlap if none of the following are true:
- box1.right < box2.left // too far left
- box1.left > box2.right // too far right
- box1.bottom < box2.top // too far above
- box1.top > box2.bottom // too far below
Only really a slight change to what you had.
function checkOverlap(elm1, elm2) {
e1 = elm1.getBoundingClientRect();
e2 = elm2.getBoundingClientRect();
return e1.x <= e2.x && e2.x < e1.x + e1.width &&
e1.y <= e2.y && e2.y < e1.y + e1.height;
}
window.onload = function() {
var a = document.getElementById('a');
var b = document.getElementById('b');
var c = document.getElementById('c');
console.log("a & b: "+checkOverlap(a,b));
console.log("a & c: "+checkOverlap(a,c));
console.log("b & c: "+checkOverlap(b,c));
}
<div id="a" style="width:120px;height:120px;background:rgba(12,21,12,0.5)">a</div>
<div id="b" style="position:relative;top:-30px;width:120px;height:120px;background:rgba(121,211,121,0.5)">b</div>
<div id="c" style="position:relative;top:-240px;left:120px;width:120px;height:120px;background:rgba(211,211,121,0.5)">c</div>
There isn't an easier way. The correct code is this, covering all possible ways two elements can overlap:
const doElementsOverlap = (elementA: any, elementB: any) => {
const A = elementA.getBoundingClientRect();
const B = elementB.getBoundingClientRect();
return (
((A.top < B.bottom && A.top >= B.top)
|| (A.bottom > B.top && A.bottom <= B.bottom)
|| (A.bottom >= B.bottom && A.top <= B.top))
&&
((A.left < B.right && A.left >= B.left)
|| (A.right > B.left && A.right <= B.right)
|| (A.left < B.left && A.right > B.right))
);
};

jQuery Run function only once on window resize

I have a function that i have to run only once if specific width is reached.
Function is used to transpose table (columns with rows) only on mobile
What I need:
1. ON LOAD
a. if width <992 run transposeTable (mobiles)
b. if width> 992 do nothing
2. ON RESIZE
a. if width <992 run transposeTable ONLY ONCE BUT if loaded page has a smaller width than 992px do nothing (see 1)
b. if width> 992 run transponseTable ONLY ONCE BUT if loaded page has a width greater than 992px to nothing (see 1)
here's solution (with some modifications) thanks to #Olaf Nankman
var transposed = "desktop";
$(document).ready(function(){
if($(window).width() < 992){
transposed = "mobile"
transposeTable();
}else{
transposed = "desktop"
}
})
$(window).resize(function(){
if($(window).width() < 992 && transposed != "mobile"){
transposed = "mobile"
transposeTable();
}
if($(window).width() > 992 && transposed != "desktop"){
transposed = "desktop"
transposeTable();
}
})
You must store that you've already called the transposeTable function, and you should transpose the table to desktop with another function...
For example:
// Create 2 apart functions, one for mobile, one for desktop
function transposeTableMobile(){
// Transpose to mobile
}
function transposeTableDesktop(){
// Transpose to desktop
}
// Create a variable to check if already transposed
var transposed = "desktop";
$(document).ready(function(){
// On page load
// Transpose the table
// Since this function runs only once,
// we don't need to check if the table
// is transposed
if($(window).width() < 992){
transposed = "mobile"
transposeTableMobile();
}else{
transposed = "desktop"
transposeTableDesktop();
}
})
$(window).resize(function(){
// On page resize
// We check if the table is transposed to mobile,
// if not, but should be, transpose it and store that
// we transposed the table
if($(window).width() < 992 && transposed != "mobile"){
transposed = "mobile"
transposeTableMobile();
}else if(transposed != "desktop"){
transposed = "desktop"
transposeTableDesktop();
}
})
If this can help, work fine for my needs
var x;
$(window).resize(function() {
if ($(this).width() <= 600 && (x === 2 || x === undefined)) {
if(x !== undefined){
//function here
$("body").append('size: small<br/>');
}
x = 1;
}
else if ($(this).width() > 600 && $(this).width() <= 1140 && (x === 1 || x === 3 || x === undefined)){
if(x !== undefined){
//function here
$("body").append('size: medium<br/>');
}
x = 2;
}
else if ($(this).width() > 1140 && (x === 2 || x === undefined)){
if(x !== undefined){
//function here
$("body").append('size: large<br/>');
}
x = 3;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

If I have the 4 corner's x and y positions of an element, how do I know if element A is in element B

I have code that (correctly) gets the 4 corner's x and y position. I want to know if element A is within the bounds of element B at all (even by 1px). I can't for the life of me figure out the right equation for this.
I have this, but this only checks if the top left of A is inside of B.
xIntersects = a.topLeft.x >= b.topLeft.x && a.topLeft.x <= b.topRight.x;
yIntersects = a.topLeft.y >= b.topLeft.y && a.topLeft.y <= b.bottomLeft.y;
console.log(xIntersects && yIntersects) // true only when topLeft of A is in B
I can write a statement like this for each of the four corners, but that seems really expensive and there's probably a much nicer way of handling this.
My code is in JS, but this answer could really be in any language.
Ended up using
function intersects (el1, el2) {
var a = el1.getCoordinates();
var b = el2.getCoordinates();
return (a.left <= b.right &&
b.left <= a.right &&
a.top <= b.bottom &&
b.top <= a.bottom)
}
If you use MooTools getCoordinates returns the top, left, bottom, and right. If not you need to figure that out manually.

javascript window.innerWidth conditional statement

I have a script which shows different content depending on the screen size, it looks like this:
if ((window.innerWidth < 1250 )) {
//Do something
}
I am trying to set a greater than value as well as a less than value. I thought the follwoing would work:
if ((window.innerWidth < 1250 && > 750)) {
//Do something
}
Can anyone help me out?
When using Boolean operators (&&, ||, etc), each side must be a completely valid Boolean expression on its own. && > 750 is not a valid expression, since > 750 cannot be evaluated as True or False.
What you want is :
if (window.innerWidth < 1250 && window.innerWidth > 750) {
As both window.innerWidth < 1250 and window.innerWidth > 750 are valid expressions and can be resolved independently.
Close:
if (window.innerWidth < 1250 && window.innerWidth > 750) {
You need to repeat the comparison argument after the && to check with new value.
Use like this:
if (window.innerWidth < 1250 && window.innerWidth > 750) {
function between(val, min, max)
{
return val >= min && val <= max;
}
if (between(window.innerWidth,750,1250)) {
//your code!!!
}

Categories