I have a function which reveals a div in my nav when clicked, and you can toggle it, so it hides when you press it again.
The problem is, that you can spamclick it so the animation keeps going and breaks the div.
What I need is some kind of antispam click, I want it to wait until the first animation is done.
Here is the code:
$("#navDown").click(function(){
if($("#navExpand").height()===0){
$('#navArrow').animateRotate(0, -180);
$("#navExpand").animate({
height: 150
})
$(".navExCon").delay(300).fadeToggle(150);
}
else if($("#navExpand").height()===150)
{
$(".navExCon").fadeToggle(150);
$('#navArrow').animateRotate(180, 0);
$("#navExpand").delay(300).animate({
height: 0
});
};
});
UPDATE /solution
This is what I did:
note: it would be better with the use of color on this site, to see the changes.
$("#navDown").click("slow",function(){ // added time "slow": 600 u i think.
if($("#navExpand").height()===0){
$('#navArrow').animateRotate(0, -180);
$("#navExpand").animate({
height: 150
},200) // added some time
$(".navExCon").fadeToggle(100);
}
else if($("#navExpand").height()===150)
{
$(".navExCon").fadeToggle(250);
$('#navArrow').animateRotate(180, 0);
$("#navExpand").animate({
height: 0
},200); // added some time
};
});
You can have a callback function when animation is finished:
var animating = false;
$("#navDown").click(function(){
if (animating) {
return; // Don't start new animation
}
animating = true;
if($("#navExpand").height()===0){
$('#navArrow').animateRotate(0, -180);
$("#navExpand").animate({
height: 150
})
$(".navExCon").delay(300).fadeToggle(150, function() {
// Will be called after animation is finished
animating = false;
});
}
else if($("#navExpand").height()===150)
{
$(".navExCon").fadeToggle(150);
$('#navArrow').animateRotate(180, 0);
$("#navExpand").delay(300).animate({
height: 0
}, function() {
// Will be called after animation is finished
animating = false;
});
}
});
Related
I'm trying to make customize section-scroll where scroll event is disabled while animation is in motion.
I tried with overflow hidden and other similar functions to apply while scroll animation is in progress but no luck.
JS fiddle example
CSS
.stop-scrolling {
height: 100%;
overflow: hidden;
}
JS example:
$('html').on('wheel', function(event) {
if (event.originalEvent.deltaY > 0) {
//scroll down
counter++;
$('body').addClass('stop-scrolling');
console.log("Start animacije");
setTimeout(function () {
$('body.stop-scrolling').removeClass('stop-scrolling');
console.log("End animation");
}, 800);
if (!(counter > maxSections)) {
$('html, body').animate({
scrollTop: $( $("#sect-"+counter) ).offset().top
}, 800);
}
} else {
//scroll up
counter--;
$('body').addClass('stop-scrolling');
console.log("Start animation");
setTimeout(function () {
$('body.stop-scrolling').removeClass('stop-scrolling');
console.log("End animation");
}, 800);
if (!(counter < 1)) {
$('html, body').animate({
scrollTop: $( $("#sect-"+counter) ).offset().top
}, 800);
}
}
if (counter <= 0) {
counter = 1;
}
else if (counter >= 3) {
counter = maxSections;
}
console.log(counter);
});
If you scroll while animation is in progress, scroll will continue until you reach end of sections.
Is possible to disable scroll event while animation is in progress?
Here's simple fix with less code modification.
Just declare a variable that represents scrolling state. And using this state you can ignore incoming scroll events if currently scrolling.
let scrolling = false;
$('html').on('wheel', function(event) {
if (scrolling) {
return;
} else {
scrolling = true;
setTimeout(function () {
scrolling = false;
}, 800 /* animation duration */);
}
...
Here's final fiddle link.
Using setTimeout function you can reset scrolling state to false so, new events will be received.
Instead of using CSS, you can use your script to block scroll events.
You can use the onComplete parameter of the .animate method to run a callback after animation ends.
With this, you can use a flag variable to determine whether or not the page is scrolling.
The whole process would be something like:
Animation started.
Flag animating = true.
Block scrolling.
Animation ended.
Flag animating = false.
Unblock scrolling.
Here's a minimal and reproducible example. It may have some bugs, but it should solve your main problem.
$(document).ready(function(){
'use strict';
// Flag to decide whether or not scroll is allowed.
let animating = false;
$(window).on('scroll', (e) => {
if (animating){
// Block scroll
e.preventDefault();
}
});
$('.section').on('wheel', e => {
e.stopPropagation();
// Do not run this function again when animation is happening.
if (animating){
return;
}
const $target = $(e.target);
const isScrollDown = e.originalEvent.deltaY > 0;
// Choose whether to scroll to next or previous section.
const $targetSection = isScrollDown ? $target.next('.section') : $target.prev('.section');
// Check whether or not there is a target
const hasTargetSection = $targetSection.length > 0;
// Only animate when there is a target.
if (hasTargetSection){
// Flag animation start
animating = true;
$('html, body').animate(
// Animation properties
{
scrollTop: $targetSection.offset().top
},
// Animation duration
800,
// Function to run after animation ends
() => {
// Flag animation ended
animating = false;
}
);
}
});
});
html, body, #app {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.section {
width: 100%;
height: 100%;
font-size: 3em;
display: flex;
justify-content: center;
align-items: center;
}
.a {
background-color: #f008;
}
.b {
background-color: #0f08;
}
.c {
background-color: #00f8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app">
<div class="section a">Section A</div>
<div class="section b">Section B</div>
<div class="section c">Section C</div>
</div>
What you are asking for is called throttling. I recommend you read this link to understand it better.
So to fix your code, you only need to enable throttling for your wheel event listener.
Like this:
let throttle = (fn, timedelay) => {
let pass = true;
return function () {
if (pass) {
setTimeout(() => {
fn.apply(this, arguments);
pass = true;
}, timedelay);
pass = false;
}
};
};
let scrollFunction = throttle(function(event) {
// your code
}, 200); // 200 miliseconds sounds good
$('html').on('wheel', scrollFunction);
Here is a working code: https://jsfiddle.net/d1fcL5en/
I created an animation with TweenMax, that animate a div from 100% width of it's parent to zero. I have three divs next to each other, that are overlapping the image below. Now I would like that each preload div class will start some seconds after the previous one was triggered.
I try something like setTimeout, but I couldn't get it work.
How can I achieve above?
CodePen: https://codepen.io/anon/pen/aWVZXL
I have changed the script. Please refactor if you want.
$(document).ready(function() {
var toBeAnimated;
var currentAnimat = 0;
$('.link').click(function() {
toBeAnimated = $(".preloader");
console.log('lets start animation');
preload(toBeAnimated[currentAnimat]);
});
function preload(elem) {
var elem = $(elem);
var width = elem.outerWidth();
// Tween out preload div
TweenMax.to(elem, 1.4, {
width: 0,
right: 0,
onComplete: function() {
elem.remove();
currentAnimat++;
if(currentAnimat >= toBeAnimated.length) {
console.log('Animation done');
} else {
preload(toBeAnimated[currentAnimat]);
}
}
});
}
});
so i have this loading screen that displays information while the page is loading but because of faster internet speeds this can be displayed in a flash.. I would like to add a minimum display time! this is my current code
jQuery(window).load(function() {
jQuery('.pageLoad').animate({
opacity: 0
}, 800, function() {
jQuery('.pageLoad').css({
display: 'none'
});
});
});
How can i do this?
You could put your fade-out method in a function and call that after an xx number of seconds from $(document).ready():
var timeoutID;
jQuery(document).ready(function() {
// start hiding the message after 2 seconds
timeoutID = window.setTimeout(hideMessage, 2000);
});
function hideMessage() {
jQuery('.pageLoad').animate({
opacity: 0
}, 800, function() {
jQuery('.pageLoad').css({
display: 'none'
});
});
}
As mentioned by #Rayf, if that piece of info should be read, regardless of page loading speed, you should add some delay to it like this:
// time to read the message...adjust it to the time you feel is right
var msgDisplayTime = 5000,
interval = 0,
loaded = false,
delayed = false,
fadeLoader = function () {
jQuery('.pageLoad').animate({opacity: 0}, 800, function () {
jQuery('.pageLoad').css({display: 'none'});
});
};
//timeout for your desired delay time
//it will ask if it is already loaded after delay ends
//triggering the fading of loading overlay
timeout = setTimeout(function(){
delayed = true;
if(loaded){
fadeLoader();
}
},msgDisplayTime);
//when loaded, it will wait until delay happened
//if not, it will delegate the execution to the timeout
// so at the end, it will be triggered after the delay or
//loading time, in case it longer than desired delay
jQuery(window).load(function(){
loaded = true;
if(delayed){
fadeLoader();
}
});
Inside comments is the roughly explanation about how it works
I want to start and stop an animation when click on the same div.
$('div').click(function(){
//if is the first click -->do animation in loop
//if is the second click--->stop animation
});
How do u do it?
I had resolve only the animation start with loop:
var play = 0;
function myAnimateGreen(){
$('green').animate(
{left:'+250px'},
1000,
);
while(play==1) {myAnimateGreen();}
}
$('green').click(function(){
play = 1;
myAnimateGreen();}
});
But I can't resolve the stop!
You can use the :animated selector to detect if the animation is currently happening
$('div').click(function(){
if( !$(".green").is(':animated') ) {
//Do animation
} else {
//Stop animation
}
});
function animateGreen(el) {
var delay = 500,
time = 1000,
distance = 150;
el.animate({left:'+='+distance+'px'}, time, "linear");
el.data("anim_green", setTimeout(animateGreen, time+delay, el));
}
$('green').click(function() {
var self = $(this);
if (self.data("anim_green")) {
clearTimeout(self.data("anim_green"));
self.data("anim_green", false);
return;
}
animateGreen(self);
});
Should do it, just paste! Proof: http://jsbin.com/ajagij/3/edit
I am trying to have an animation run only when the mouse is over an object. I can get one iteration of the animation and then have it set back to normal on mouse out. But I'd like the animation to loop on mouseover. How would I do it, using setInterval? I'm a little stuck.
It could be done like this:
$.fn.loopingAnimation = function(props, dur, eas)
{
if (this.data('loop') == true)
{
this.animate( props, dur, eas, function() {
if( $(this).data('loop') == true ) $(this).loopingAnimation(props, dur, eas);
});
}
return this; // Don't break the chain
}
Now, you can do this:
$("div.animate").hover(function(){
$(this).data('loop', true).stop().loopingAnimation({ left: "+10px"}, 300);
}, function(){
$(this).data('loop', false);
// Now our animation will stop after fully completing its last cycle
});
If you wanted the animation immediately stop, you could change the hoverOut line to read:
$(this).data('loop', false).stop();
setInterval returns an id that can be passed to clearInterval to disable the timer.
You can write the following:
var timerId;
$(something).hover(
function() {
timerId = setInterval(function() { ... }, 100);
},
function() { clearInterval(timerId); }
);
I needed this to work for more then one object on the page so I modified a little Cletus's code :
var over = false;
$(function() {
$("#hovered-item").hover(function() {
$(this).css("position", "relative");
over = true;
swinger = this;
grow_anim();
}, function() {
over = false;
});
});
function grow_anim() {
if (over) {
$(swinger).animate({left: "5px"}, 200, 'linear', shrink_anim);
}
}
function shrink_anim() {
$(swinger).animate({left: "0"}, 200, 'linear', grow_anim);
}
Consider:
<div id="anim">This is a test</div>
with:
#anim { padding: 15px; background: yellow; }
and:
var over = false;
$(function() {
$("#anim").hover(function() {
over = true;
grow_anim();
}, function() {
over = false;
});
});
function grow_anim() {
if (over) {
$("#anim").animate({paddingLeft: "100px"}, 1000, shrink_anim);
}
}
function shrink_anim() {
$("#anim").animate({paddingLeft: "15px"}, 1000, grow_anim);
}
You can achieve this using timers too.