I have this function that when you click on the html it checks the width of a number of elements and compares it with the windows width. I can't get it to work with the resize function. I think I'm calling it wrong.
$(document).ready(function() {
$(window).resize(function() {
var conditionWidth = checkWidth()
});
function checkWidth() {
var elementWidth = 1;
$("div>div").each(function() {
if ($(this).width() > $("html").width() / 2) {
elementWidth = 2;
}
});
return elementWidth;
}
var conditionWidth = checkWidth()
$("body").off("click").click(function() {
alert(conditionWidth);
});
})
div div {
position: relative;
height: 100px;
width: 100px;
margin-top: 20px;
}
.rectangle1 {
background-color: black;
width: 100px;
}
.rectangle2 {
background-color: red;
width: 200px;
}
.rectangle3 {
background-color: black;
width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<div class="rectangle1"></div>
<div class="rectangle2"></div>
<div class="rectangle3"></div>
</div>
Since you are using var to declare the variable in the resize handler the the variable is local to the resize handler method and the value of the closure scope(dom ready handler) is not updated.
$(document).ready(function () {
var conditionWidth = checkWidth()
$(window).resize(function () {
//when you use var it becomes a local variable
conditionWidth = checkWidth()
});
function checkWidth() {
var elementWidth = 1;
$("div>div").each(function () {
if ($(this).width() > $("html").width() / 2) {
elementWidth = 2;
}
});
return elementWidth;
}
$("body").off("click").click(function () {
alert(conditionWidth);
});
})
Related
How to wait for my first function to end before I can click "Click me" button again. I have been searching for a way to let my function end first before I can let the new function run again.
document.getElementById("myBtn").addEventListener("click", myFunction);
setTimeout(function() {
myFunction();
}, 3000);
var id = null;
function myFunction() {
var elem = document.getElementById("myAnimation");
var pos = 0;
clearInterval(id);
id = setInterval(frame, 10);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#myAnimation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<h2>JavaScript addEventListener()</h2>
<button id="myBtn">Click Me</button>
<div id="myContainer">
<div id="myAnimation"></div>
If we disable and enable the button in the correct place, it will work quite nicely
I also cleaned up the code a bit to make it more contained.
window.addEventListener('DOMContentLoaded', () => {
const myBtn = document.getElementById("myBtn");
const elem = document.getElementById("myAnimation");
let id = null;
let pos = 0;
const frame = () => {
if (pos == 350) {
clearInterval(id);
myBtn.disabled = false;
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
const myFunction = () => {
pos = 0;
clearInterval(id);
id = setInterval(frame, 10);
myBtn.disabled = true;
}
id = setTimeout(myFunction, 3000);
myBtn.addEventListener("click", myFunction);
});
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#myAnimation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<h2>JavaScript addEventListener()</h2>
<button id="myBtn">Click Me</button>
<div id="myContainer">
<div id="myAnimation"></div>
</div>
As a first implementation you could disable the button before you start the animation, and you only enable it after you are done
var myBtn = document.getElementById("myBtn")
myBtn.addEventListener("click", myFunction);
setTimeout(function() {
myFunction();
}, 3000);
var id = null;
function myFunction() {
var elem = document.getElementById("myAnimation");
var pos = 0;
clearInterval(id);
id = setInterval(frame, 10);
// disable the button
myBtn.disabled = true;
function frame() {
if (pos == 350) {
clearInterval(id);
// enable the button again
myBtn.disabled = false;
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#myAnimation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<h2>JavaScript addEventListener()</h2>
<button id="myBtn">Click Me</button>
<div id="myContainer">
<div id="myAnimation"></div>
You should disable your button during your function.
edited: If you don't want to disable maybe with a lock.
document.getElementById("myBtn").addEventListener("click", myFunction);
setTimeout(function() {
myFunction();
}, 3000);
var id = null;
var lock = false;
function myFunction() {
if(!lock){
lock = true;
var elem = document.getElementById("myAnimation");
var pos = 0;
clearInterval(id);
id = setInterval(frame, 10);
function frame() {
if (pos == 350) {
clearInterval(id);
lock = false;
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
}
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#myAnimation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<h2>JavaScript addEventListener()</h2>
<button id="myBtn">Click Me</button>
<div id="myContainer">
<div id="myAnimation"></div>
edited: Try making your animation with CSS it's a better practice.
let sum = 0;
const x = 10;
async function firstFunction() {
for (i = 0; i < x; i++) {
sum = sum + i;
}
return sum;
}
async function secondFunction() {
await firstFunction();
console.log('After firstFunction executed sum is', sum);
}
secondFunction();
I have a lot of objects in the dom tree, on which i'm adding new class, when they appeat in the viewport. But my code is very slow - it causes page to slow down...
I have such dom:
...
<span class="animation"></span>
...
and such jquery:
$.each($('.animation'), function() {
$(this).data('offset-top', Math.round($(this).offset().top));
});
var wH = $(window).height();
$(window).on('scroll resize load touchmove', function () {
var windowScroll = $(this).scrollTop();
$.each($('.animation'), function() {
if (windowScroll > (($(this).data('offset-top') + 200) - wH)){
$(this).addClass('isShownClass');
}
});
});
maybe i can somehow speed up my scroll checking and class applying?
You can use the Intersection Observer API to detect when an element appears in the viewport. Here is an example that adds a class to an element that is scrolled into the viewport and animates the background color from red to blue:
var targetElement = document.querySelector('.block');
var observer = new IntersectionObserver(onChange);
observer.observe(targetElement);
function onChange(entries) {
entries.forEach(function (entry) {
entry.target.classList.add('in-viewport');
observer.unobserve(entry.target);
});
}
body {
margin: 0;
height: 9000px;
}
.block {
width: 100%;
height: 200px;
margin-top: 2000px;
background-color: red;
transition: background 1s linear;
}
.block.in-viewport {
background-color: blue;
}
<div class="block">
</div>
The Intersection Observer API method works on chrome only, but the performance faster by 100%. The code below loads in 3/1000 second
$(document).ready(function () {
'use strict';
var startTime, endTime, sum;
startTime = Date.now();
var anim = $('.animation');
anim.each(function (index, elem) {
var animoffset = $(elem).offset().top;
$(window).on('scroll resize touchmove', function() {
var winScTop = $(this).scrollTop();
var windowHeight = $(window).height();
var winBottom = winScTop + windowHeight;
if ( winBottom >= animoffset ) {
$(elem).addClass('showed');
}
});
});
endTime = Date.now();
sum = endTime - startTime;
console.log('loaded in: '+sum);
});
html {
height: 100%;
}
body {
margin: 0;
height: 9000px;
}
.animation {
display: block;
width: 400px;
height: 400px;
background-color: blue;
margin-top: 1000px;
}
.animation:not(:first-of-type) {
margin-top: 10px;
}
.animation.showed {
background-color: yellow;
transition: all 3s ease
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<span class="animation"></span>
<span class="animation"></span>
<span class="animation"></span>
<span class="animation"></span>
IntersectionObserver has a limited support in browsers, but it's improving.
I'm basically lazy loading the polyfill only if the browser user is loading my website in doesn't support IntersectionObserver API with the code bellow.
loadPolyfills()
.then(() => /* Render React application now that your Polyfills are
ready */)
/**
* Do feature detection, to figure out which polyfills needs to be imported.
**/
function loadPolyfills() {
const polyfills = []
if (!supportsIntersectionObserver()) {
polyfills.push(import('intersection-observer'))
}
return Promise.all(polyfills)
}
function supportsIntersectionObserver() {
return (
'IntersectionObserver' in global &&
'IntersectionObserverEntry' in global &&
'intersectionRatio' in IntersectionObserverEntry.prototype
)
}
I am trying to add a class to the header when an element reaches the top of the viewport but I cannot seem to find out why it is not working. I have no errors and I have checked to see that jquery is fetching the offsets and it is. Any help would be great. I would also like to know how to extend this code to any number of section's rather than stating just 6.
JS FIDDLE
$(document).ready(function () {
var project1 = $('section:nth-child(1)').offset();
var project2 = $('section:nth-child(2)').offset();
var project3 = $('section:nth-child(3)').offset();
var project4 = $('section:nth-child(4)').offset();
var project5 = $('section:nth-child(5)').offset();
var project6 = $('section:nth-child(6)').offset();
var $window = $(window);
$window.scroll(function () {
if ($window.scrollTop() >= project1) {
$("header").removeClass().addClass("project1");
}
if ($window.scrollTop() >= project2) {
$("header").removeClass().addClass("project2");
}
if ($window.scrollTop() >= project3) {
$("header").removeClass().addClass("project3");
}
if ($window.scrollTop() >= project4) {
$("header").removeClass().addClass("project4");
}
if ($window.scrollTop() >= project5) {
$("header").removeClass().addClass("project5");
}
if ($window.scrollTop() >= project6) {
$("header").removeClass().addClass("project6");
}
});
});
The method .offset(), returns an object containing the properties top and left:
{top: 1808, left: 8}
Therefore you need to access the top property in your conditional statements.
Change
if ($window.scrollTop() >= project1) { ... }
to:
if ($window.scrollTop() >= project1.top) { ... }
Updated Example
As a side note, $('section:nth-child(1)').offset() will be undefined because the section element isn't the first element (the <header> is). Use :nth-of-type rather than :nth-child. Since you're using jQuery, eq() would work too.
$(document).ready(function() {
var project1 = $('section:nth-of-type(1)').offset();
var project2 = $('section:nth-of-type(2)').offset();
var project3 = $('section:nth-of-type(3)').offset();
var project4 = $('section:nth-of-type(4)').offset();
var project5 = $('section:nth-of-type(5)').offset();
var project6 = $('section:nth-of-type(6)').offset();
var $window = $(window);
$window.scroll(function() {
if ( $window.scrollTop() >= project1.top) {
$("header").removeClass().addClass("project1");
}
if ( $window.scrollTop() >= project2.top ) {
$("header").removeClass().addClass("project2");
}
if ( $window.scrollTop() >= project3.top ) {
$("header").removeClass().addClass("project3");
}
if ( $window.scrollTop() >= project4.top ) {
$("header").removeClass().addClass("project4");
}
if ( $window.scrollTop() >= project5.top ) {
$("header").removeClass().addClass("project5");
}
if ( $window.scrollTop() >= project6.top ) {
$("header").removeClass().addClass("project6");
}
});
});
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100px;
background: #000;
}
header.project1 {
background: red;
}
header.project2 {
background: orange;
}
header.project3 {
background: blue;
}
header.project4 {
background: green;
}
header.project5 {
background: red;
}
header.project6 {
background: blue;
}
section {
height: 900px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header></header>
<section>Section 1</section>
<section>Section 2</section>
<section>Section 3</section>
<section>Section 4</section>
<section>Section 5</section>
<section>Section 6</section>
I'm trying to check when a div is reached from scrollbar with jquery.
I read some similar question on stackoverflow, but all are on one div only.
I have 4 div, with height: 100% and I want know when the scroll bar pass every div.
I tried, but only works with the first div.
HTML:
<body>
<div id="main"></div>
<div id="service"></div>
<div id="clients"></div>
<div id="about"></div>
</body>
CSS:
body, html {
height: 100%;
padding: 0px;
margin: 0px;
}
#main {
background: red;
height: 100%;
}
#service {
background: green;
height: 100%;
}
#clients {
background: blue;
height: 100%;
}
#about {
background: yellow;
height: 100%;
}
JS:
$(document).ready(function() {
var passed_service = false;
var passed_service = false;
$('body,html').bind('scroll mousedown wheel DOMMouseScroll mousewheel keyup', function(event){
if($(window).scrollTop() >= ($("#service").height())){
if(!passed_service){
alert("To #service");
passed_service = true;
}
}
if($(window).scrollTop() >= ($("#service").height() + $("#clients").height())){
if(!passed_clients){
alert("To #clients");
passed_clients = true;
}
}
});
});
SORRY TO ALL, WAS A MY STUPID ERROR, I CAN'T DELETE THE QUESTION :(
var passed_service = false;
var passed_service = false; /* should be 'passed_clients' */
^ There's your problem
Also, instead of adding up the divs' heights, use the top offset instead.
DEMO
$(window).scrollTop() >= $("#service").offset().top
$(window).scrollTop() >= $("#clients").offset().top
...
You never declare the passed_clients variable.
Change this:
var passed_service = false;
var passed_service = false;
to this:
var passed_service = false;
var passed_clients = false;
Working fiddle: http://jsfiddle.net/XUEfD/8/
Working Demo link
use this: (parseInt($("#service").height()) + parseInt($("#clients").height()))
$(document).ready(function() {
var passed_service = false;
var passed_clients = false;
$('body,html').bind('scroll mousedown wheel DOMMouseScroll mousewheel keyup', function(event){
if($(window).scrollTop() >= ($("#service").height())){
if(!passed_service){
alert("To #service");
passed_service = true;
}
}
//console.log($(window).scrollTop());
if($(window).scrollTop() >= (parseInt($("#service").height()) + parseInt($("#clients").height()))){
if(!passed_clients){
alert("To #clients");
passed_clients = true;
}
}
});
});
http://jsfiddle.net/xNnQ5/
I am trying to use JavaScript (and HTML) to create a collapsible menu (c_menu) for my website. I would like it to be opened when the user clicks on the div menu_open, and to close when the user clicks menu_close. However, when I load the page, all that happens is the menu simply scrolls up, as if I have clicked menu_close, which I haven't. What should I do?
Code:
index.html (Only a snippet)
<style type = "text/css">
#c_menu {
position: absolute;
width: 435px;
height: 250px;
z-index: 2;
left: 6px;
top: 294px;
background-color: #0099CC;
margin: auto;
</style>
<div id="menu_open"><img src="images/open.jpg" width="200" height="88" /></div>
<input type="button" name="menu_close" id="menu_close" value="Close"/>
<div id="c_menu"></div>
<script type = "text/javascript" src = "menu.js"> </script>
menu.js (Full code)
document.getElementById("c_menu").style.height = "0px";
document.getElementById("menu_open").onclick = menu_view(true);
document.getElementById("menu_close").onclick = menu_view(false);
function menu_view(toggle)
{
if(toggle == true)
{
document.getElementById("c_menu").style.height = "0px";
changeheight(5, 250, 0);
}
if(toggle == false)
{
document.getElementById("c_menu").height = "250px";
changeheight(-5, 0, 250);
}
}
function changeheight(incr, maxheight, init)
{
setTimeout(function () {
var total = init;
total += incr;
var h = total + "px";
document.getElementById("c_menu").style.height = h;
if (total != maxheight) {
changeheight(incr, maxheight, total);
}
}, 5)
}
Try this:
document.getElementById("menu_open").onclick = function() {menu_view(true)};
document.getElementById("menu_close").onclick = function() {menu_view(false)};
When you define the function with a parenthesis ( ...onclick = menu_view(true) ), the function is called automatically.
When you have a function with no parameters, you can use it like you did, but without the parenthesis:
document.getElementById("menu_open").onclick = menu_view;
document.getElementById("menu_close").onclick = menu_view;