I have the following snippet of code that loops through the jQuery animate function endlessly. It works fine on Chrome, but fails after the first animate call on IE. My questions are:
How can I make this work in IE (9)?
How can I add a delay after the first loop? I want there to be a delay between consecutive pulses.
#container {
position : relative;
width : 500px;
height : 200px;
overflow : hidden;
opacity: 1;
}
.
#container > img {
position : absolute;
top : 0;
left : 0;
}
.
$(window).load(function(){
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else {console.log('2');
$image.animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
});
.
<div id="container">
<img src="blah.jpg" width="500" height="375" />
</div>
Remove the console.log() statement from the else branch and it should work in IE - IE doesn't like console.log() unless the console is actually open, whereas (most) other browsers either ignore it or log in a way you can see if you open the console later. (I don't have IE9, but that's all it took to fix it when I tested it in IE8.)
Also it doesn't make sense to have a document ready handler inside a $(window).load() handler, so you should remove one or the other.
As far as adding a delay between consecutive pulses, just use jQuery's .delay() function before calling .animate() in the else branch, like this:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else { // console.log removed from this spot
$image.delay(500).animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
P.S. Given that the anonymous functions you've got for the .animate() complete callbacks don't do anything except call animate_img() you can remove the anonymous functions and just pass animate_img directly. So you can make the function much shorter if you wish:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
var fade = $image.css('opacity') == '1';
$image.delay(fade?1:500).animate({opacity:fade?'0.4':'1'},2000,animate_img);
}
animate_img();
});
After a deleted discussion about if setTimeout() or setInterval() should be used, a different solution using setInterval()
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == 1) {
$image.animate({opacity: 0.4},{ queue:false, duration:2000});
} else {
$image.animate({opacity: 1},{ queue:false, duration:2000});
}
}
setInterval(animate_img, 4000);
});
Notice that interval time should have a minimum of 4000ms, which the sum of the animation time (2000ms each) back and forth. If the interval is less than that, the animations won't be completed.
I insisted in the previous (deleted) discussion that the correct syntax for setInterval should be setInterval("animate_img()", 4000) ... my bad, because I missed that setInterval was within a function ... so the function animate_img should be called as a pointer rather than a string.
The advantage of this solution (I think) is less lines of code but also that we don't need to call the function animate_img() 3 times in the loop and from within itself.
This should work fine in Chrome as well as in IE.
Related
I want to make a one pager website, without using any third party libraries, like FullPage.js.
when scroll starts --> instead of waiting for the end of the natural scrolling, I want it to take no effect (so no visible scroll caused by the mouse) and to run my code instead. (so it could always go to next section, or previous one, without relying on the amount of the users scroll)
Do you have any idea how could I achieve this? My code snippet waits for the end of scroll, and then jumps to where it should, so it's not working as intended.
(the first section has a "current" class and then the code snippet works by manipulating the 100vh sections by adding/removing this class)
You can see the code snippet I am using below or here:
https://codepen.io/makiwara/pen/PoqjdNZ
Thank you very much for your help, have a nice day!
var script = document.createElement('script');script.src = "https://code.jquery.com/jquery-3.4.1.min.js";document.getElementsByTagName('head')[0].appendChild(script);
var timerId;
var scrollableElement = document.body; //document.getElementById('scrollableElement');
scrollableElement.addEventListener('wheel', checkScrollDirection);
function checkScrollDirection(event) {
var $current = $('.current');
if (checkScrollDirectionIsUp(event)) {
console.log('UP');
$prev = $current.prev();
if ($prev.length) {
clearTimeout(timerId);
timerId = setTimeout(function(){
$current.removeClass('current');
$prev.addClass('current');
$('body,html').animate({
scrollTop: $('.current').offset().top
}, 100);
}, 100)
}
} else {
console.log('Down');
$next = $current.next();
if ($next.length) {
clearTimeout(timerId);
timerId = setTimeout(function(){
$current.removeClass('current');
$next.addClass('current');
$('body,html').animate({
scrollTop: $('.current').offset().top
}, 100);
} , 100)
}
}
}
function checkScrollDirectionIsUp(event) {
if (event.wheelDelta) {
return event.wheelDelta > 0;
}
return event.deltaY < 0;
}
What you need is throttling the event listener, i.e. limit a function call only once per a time period.
What your code is doing is essentially debouncing i.e limit a function call only after a wait time period has passed.
Firstly ditch the timers you're using. You need to somehow block scrolling from happening more than once. The JavaScript part can be easy if you use Underscore.js's throttle function with one caveat though: It passes through subsequent events after the time period has passed. Luckily, its debouncing method accepts a third argument that gives the behavior you'd want:
scrollableElement.addEventListener(
"wheel",
_.debounce(checkScrollDirection, 200, true) // immediately call the function _once_
);
This third argument makes the debounced function behave like a throttled one, that is it will fire only once and at the same time it will fire immediately.
So assuming that your event handler is now free from the original timeout
function checkScrollDirection(event) {
var $current = $(".current");
if (checkScrollDirectionIsUp(event)) {
console.log("UP");
$prev = $current.prev("section");
if ($prev.length) {
$current.removeClass("current");
$prev.addClass("current");
$("body,html").animate(
{
scrollTop: $prev.offset().top
},
100
);
}
} else {
console.log("Down");
$next = $current.next("section");
if ($next.length) {
$current.removeClass("current");
$next.addClass("current");
$("body,html").animate(
{
scrollTop: $next.offset().top
},
100
);
}
}
}
btw, try to get into the habit of specifying selectors inside .next() and .prev() since jQuery will match all possible siblings, which most likely you don't want. In this case, codepen appends additional <script> elements and jQuery will match those as well.
Now if you try this, you'll notice that the window still responds to every scroll event. Scroll events are one of those events that cannot be cancelled so you need to disable it via CSS
The easiest way is to hide the overflow of the body
body { max-height: 100vh; overflow: hidden; }
And that's it. You may need to adjust the throttle waiting time period to match your preferences.
You can find a working version of the codepen here: https://codepen.io/vassiliskrikonis/pen/XWbgxLj
I have a testimonial scroller that shows one testimonial, fades out, shows the next, fades out, and returns to the first.
My issue is that after the fade in animation, the fade out animation begins immediately. It doesn't give enough time for someone to read it.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
$("#one").fadeOut(6000).delay(3000);
setTimeout(fadeTwo,6000);
});
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
$("#two").fadeOut(6000).delay(3000);
setTimeout(fadeThree,6000);
});
}
function fadeThree() {
$("#three").fadeIn(4000,function() {
$("#three").fadeOut(6000).delay(3000);
setTimeout(doFade,6000);
});
}
doFade();
});
jQuery's delay function will only delay functions that are called after it in the chain, so it is having no effect on your code. Delay docs
You need to use it before the call to fadeOut, e.g.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
setTimeout(fadeTwo,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
setTimeout(fadeThree,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeThree() {
$("#three").fadeIn(6000,function() {
setTimeout(doFade,6000);
})
.delay(3000)
.fadeOut(6000);
}
doFade();
});
Edit:
You are currently setting a timeout to execute the next function, within the complete callback of fadeIn. This is a bit confusing to my mind, and I think it is simpler and clearer to do something like the following. In addition, there is no reason to define the three functions within the ready function - it is personal preference but I like to keep the amount of code within a callback to a minimum, such as...
$(document).ready(function() {
doFade();
});
function doFade() {
setTimeout(fadeTwo,12000);
$("#one").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeTwo() {
setTimeout(fadeThree,12000);
$("#two").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeThree() {
setTimeout(doFade,12000);
$("#three").fadeIn(6000).delay(3000).fadeOut(6000);
}
Edit 2:
In further effort to reduce the amount we repeat ourselves, we can extract the whole animation sequence into a function:
$(document).ready(function() {
doFade();
});
function fadeInThenOut(element) {
element.fadeIn(6000).delay(3000).fadeOut(6000);
}
function doFade() {
setTimeout(fadeTwo,12000);
fadeInThenOut($("#one"));
}
function fadeTwo() {
setTimeout(fadeThree,12000);
fadeInThenOut($("#two"));
}
function fadeThree() {
setTimeout(doFade,12000);
fadeInThenOut($("#three"));
}
Edit 3:
At this point we probably notice how similar our three functions are, and want some way to reduce that repetitiveness. So we could use recursion, and just change which element we pass in each time.
$(document).ready(function() {
doFade();
});
function doFade(elementNumber) {
const elementNumber = elementNumber < testimonialElements.length ? elementNumber : 0;
setTimeout(doFade(elementNumber + 1),12000);
$('#' + testimonialElements[elementNumber]).fadeIn(6000).delay(3000).fadeOut(6000);
}
var testimonialElements = ["one","two","three"];
While this solution may lose something in readability and simplicity, the great advantage is that when you add a fourth testimonial, you don't need to write a function to handle it. All you would do is change the testimonialElements array to include the new element id.
I'm struggling to get an animated gif to run in IE. Works in all other browsers, but in IE it just freezes. I've researched this and looks like a delay using setTimeout might work. Not too sure how I add this to the following function:
<script type="text/javascript">
$(function(){
$('#photo_form').on("submit", function () {
$('#loading').show();
});
});
</script>
The gif is inside a div called 'loading' which is hidden. Would I add the timeout to onClick of the button or within the function itself?
Why does IE make things so difficult!?
Any help with solving this problem would be very helpful.
You mean something like this?
$(function() {
$('#photo_form').on("submit", function () {
setTimeout(function () {
$('#loading').show();
}, 100);
});
});
Try this curde, untested psedo-code:
var startTime;
var thread;
$(function(){
$('#photo_form').on("submit", function () {
$('#loading').show();
startTime = time();
thread = setInterval("showLoadingGif", 1);
});
function showLoadingGif() {
var timeToWait = 5; //change interval as needed
if(timeToWait + startTime <= currentTime) {
//show the gif
clearInterval(thread);
}
}
It's been a long time since I've worked with javascript, so this almost certainly needs adjustment; but the principle is the same: keep calling that function, and let that function decide when to stop being called.
setTimeout() will cause your page to freeze while you wait. setInterval will run your code asyncronously.
I building website using following script. Sometime this javascript crash sometimes not. Weird thing is when I add alert box at third line after sliderLeft define, script never crash. Someone please help with this.
I am using same function twice for different output.
Even I remove Second similar function I am still getting error. Please help me with this.
$(window).load(function() {
var sliderLeft=$('#thumbScroller .container').position();
//alert(sliderLeft);
// padding=$('#outer_container').css('paddingRight').replace("px", "");
var sliderWidth=$(window).width()
$('#thumbScroller').css('width',sliderWidth);
var totalContent=0;
$('#thumbScroller .content').each(function () {
totalContent+=$(this).innerWidth();
$('#thumbScroller .container').css('width',totalContent);
});
//alert(sliderLeft);
$('#thumbScroller').mousemove(function(e){
if($('#thumbScroller .container').width()>sliderWidth){
var mouseCoords=(e.pageX - this.offsetLeft);
var mousePercentX=mouseCoords/sliderWidth;
var destX=-(((totalContent-(sliderWidth))-sliderWidth)*(mousePercentX));
var thePosA=mouseCoords-destX;
var thePosB=destX-mouseCoords;
var animSpeed=600; //ease amount
var easeType='easeOutCirc';
if(mouseCoords==destX){
$('#thumbScroller .container').stop();
}
else if(mouseCoords>destX){
//$('#thumbScroller .container').css('left',-thePosA); //without easing
$('#thumbScroller .container').stop().animate({left: -thePosA}, animSpeed,easeType); //with easing
}
else if(mouseCoords<destX){
//$('#thumbScroller .container').css('left',thePosB); //without easing
$('#thumbScroller .container').stop().animate({left: thePosB}, animSpeed,easeType); //with easing
}
}
});
$('#thumbScroller .thumb').each(function () {
$(this).fadeTo(fadeSpeed, 0.6);
});
var fadeSpeed=200;
$('#thumbScroller .thumb').hover(
function(){ //mouse over
$(this).fadeTo(fadeSpeed, 1);
},
function(){ //mouse out
$(this).fadeTo(fadeSpeed, 0.6);
}
);
});
$(window).resize(function() {
//$('#thumbScroller .container').css('left',sliderLeft); //without easing
$('#thumbScroller .container').stop().animate({left: sliderLeft}, 400,'easeOutCirc'); //with easing
$('#thumbScroller').css('width',$(window).width());
sliderWidth=$(window).width();
});
I just remove second function as per suggestion, but still not work
removed few lines and script crash and doesn't display any error
You have 2 $(window).load(function() {...}); function definitions.
Try combing them into 1 $(window).load(function() {...}); call.
Just an idea...
Hard to say without seeing the problem (as said by 3dgoo try put your code into jsfiddle.net) but Are you sure your code executes when dom is ready ?
It'd explained that the 'alert' you put in your code 'solve' the problem by giving it time to finish loading.
I have this line of code, but it doesn't work, and I'm guessing that my function is the cause of the problem here. Here's my JavaScript:
$(document).ready(function () {
var interval;
function move(ele) {
$(ele).animate({
'background-position-y': '0px'
}, 200, function () {
$(ele).animate({
'background-position-y': '3px'
}, 200, function () {
interval = setTimeout(function () {
move(ele)
}, 3);
});
});
};
$(".up").hover(function () {
move(this), function () {
clearTimeout(interval);
interval = null;
$(this).css("background-position", "80px 3px ");
};
});
Can someone explain me what I'm doing wrong here?
Even with the proper closing braces as suggested by David there is still a problem which keeps the animation going. Clearing the timer (interval) doesn't stop the callback functions passed to .animate() from executing. So interval = setTimeout(...) will still get executed and perpetuated the animation cycle.
I reworked the code a bit for a working example, though there could be some improvements (like getting rid of a global variable). http://jsfiddle.net/aKKRk/
err, it looks like your actual problem is that you're only passing one function to hover, not two. You've got ….hover(function() { move(…), function() { … } }) instead of ….hover(function() { move(…); }, function() { … }).
In the future, this kind of error will be much easier to spot if you make a habit of consistently indenting your code.