Set and Clear interval slider jQuery - javascript

I'm trying to make a simple two image slider that auto slides up and down. When the user hovers into it it should stop and if he/she hovers out of it, it continues to function normally. I tried using set and clearInterval but the slider doesn't pause on hover. How should I write the code to make it work?
var $Slides = $("#EServices"); //Or var $Slides = $("#Serv-Slides");
var interval;
function StartSlider() {
interval = setInterval(function () {
$("#Serv-Slides").animate({ "marginTop": "0px" }, 200).delay(2000);
$("#Serv-Slides").animate({ "marginTop": "-150px" }, 200).delay(2000);
});
}
function StopSlider() {
clearInterval(interval);
}
$Slides.on('mouseenter', StopSlider).on('mouseleave', StartSlider);
StartSlider();

There is two main problems here:
clearInterval does not stop jquery's animation, it will just stop your setInterval calls so that no further animation are added in the queue. Every animations that you already piped and that are still pending will still be run. It will stop when all of them are finished.
You did not provided any given time for your setInterval. As a result, the provided function will be repeatedly called as fast as your browser can. This is a terrible mistake because you will end up with a massive amount of pending animations in the queue. You are piping new animations much much faster than they are actually consumed.
This should work:
var interval;
function startSlider() {
function animate(){
$("#Serv-Slides").animate({ "marginTop": "0px" }, 200).delay(2000)
.animate({ "marginTop": "-150px" }, 200); //.delay(2000);
// Last delay is useless, it is managed by the setInterval.
}
// Start the first animation right now.
animate();
// Set an interval that matches the animations and the delays duration.
interval = setInterval(animate, 200 + 2000 + 200 + 2000);
}
function stopSlider() {
// Avoid any further animation to be added.
clearInterval(interval);
// Stop the currently running animations.
$("#Serv-Slides").stop(true);
}
$("#Slides").on('mouseenter', stopSlider).on('mouseleave', startSlider);
startSlider();
#Slides{
background-color:yellow;
padding-top: 150px;
height: 20px;
}
#Serv-Slides{
background-color: red;
height: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="Slides">
<div id="Serv-Slides"></div>
</div>
You may also consider using css animations with #keyframes instead. Using the :hover pseudo-class you don't even need any JavaScript. This is likely to be more performant and I personally find it more elegant, easier and more flexible. Here is an example (you may need to add css prefixes for older browsers' support):
#Slides{
background-color:yellow;
padding-top: 150px;
height: 20px;
}
#Serv-Slides{
background-color: red;
height: 20px;
animation-duration: 4s;
animation-name: up-and-down;
animation-iteration-count: infinite;
}
#Slides:hover #Serv-Slides{
animation-play-state: paused;
}
#keyframes up-and-down {
0% { margin-top: 0px; }
45% { margin-top: 0px; }
50% { margin-top: -150px; }
95% { margin-top: -150px; }
}
<div id="Slides">
<div id="Serv-Slides"></div>
</div>

Related

Why do my css animations become exponentially smaller and eventually stop working?

I am making a small game where a block slides towards the character, and onclick of the main body of the game through a mouse, the character jumps to avoid the block. Whenever I refresh the page, it works normally, but after a few clicks the animation gets smaller and smaller (in the distance is jumps and the time it takes for the animation to complete) and eventually stops working completely. I have included a code snippet so you can see the problem.
let character = document.getElementById('character');
let obstacle = document.getElementById('obstacle');
function jump() {
if (character.classList != 'animate') {
character.classList.add('animate');
}
setInterval(function () {
character.classList.remove('animate');
}, 500);
}
* {
padding: 0;
margin: 0;
}
.game {
height: 200px;
width: 500px;
border: 5px solid black;
}
#keyframes jump{
0%{top: 150px;}
30%{top: 100px;}
70%{top: 100px;}
100%{top: 150;}
}
.character {
height: 50px;
width: 20px;
background-color: red;
position: relative;
top: 150px;
}
.animate {
animation: jump 0.5s;
}
#keyframes block{
0%{left: 480px;}
100%{left: -40px;}
}
.obstacle {
height: 20px;
width: 20px;
background-color: blue;
position: relative;
top: 130px;
left: 480px;
animation: block 2s infinite linear;
}
<!DOCTYPE html>
<html>
<head>
<title>Jumping Game</title>
<link rel="stylesheet" href="jump.css">
</head>
<div>
<body onclick="jump()">
<div class="game">
<div id="character" class="character">
</div>
<div id="obstacle" class="obstacle">
</div>
</div>
</body>
</div>
<script src="jump.js"></script>
</html>
Because you use setInterval, which executes the function provided to it repeatedly in 500ms intervals until you stop it with clearInterval (passing timeout id returned from initial setInterval call).
If you only want to execute the function once after 500ms, use setTimeout instead: https://jsfiddle.net/dp0n8Leh/ (making sure you first clearTimeout for the previous timeout, if you click early enough)
Also, to check if an element has a class, you should use !character.classList.contains('animate') instead of character.classList != 'animate'
just use setTimeout not setInterval to remove the class

Uneven intervals with setInterval function due to other code running between intervals;

I am trying to have a div do a simple slide into a parent div in a React project using pure JS and am having problems with the smoothness of the slide. When I console log, I can see that when the code (slideIn) runs, between setInterval calls, React runs other code which take up more time than the specified intervals. Therefore, the intervals are not even, which seems to be causing the jerkiness in the slide.
I have tried requestAnimationFrame also, but the result is the same.
The challenge seems to be to make the slideIn continuous without having react run other code while running it, but how does one do that?
<div className="outer-box">
<div className="sliding-box"></div>
</div>
.outer-box {
width: 300px;
height: 200px;
position: relative;
}
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
}
slideIn() {
const moveElemment = document.getElementById('sliding-box');
const pos = -100;
if (moveElemment) {
const id = setInterval(frame, 10);
function frame() {
if (pos == 0) {
clearInterval(id);
} else {
pos++;
moveElemment.setAttribute('style', `left: ${pos}%`);
}
}
}
}
Perphas you could take advantage of CSS transitions to achieve smoother animation that is decoupled from the JS thread, to resolve your problem? For example, you could update your CSS with a transition rule and additional selector as follows:
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: -100px; // Initial position of sliding-box
transition: left 1s linear; //Specify the animation behaviour
}
.sliding-box.in {
left: 0px; // Position of sliding-box after animation
}
with simplified JS to trigger the transition animation as follows:
slideIn() {
const moveElemment = document.getElementById('sliding-box');
if (moveElemment) {
// When this selector is added, it triggers the animation
// transition from left:-100px to left:0px over a 1 second
// interval
moveElemment.classList.add('in');
}
}

Making Infinite times animation in jquery

Guys i want to make infinite times animation in jquery.
I have tried with following code but that animation is occurring only 1 times but i want continues and also i want to change the images on every step.
$(document).ready(function(){
function animation(){
$("img").animate({
'top':'440px'
},'slow');
setTimeout(function(){
$("img").animate({
'top':'10px'
},'slow');
},3000);
}
animation();
});
</script>
You can do this by calling the last parameter in an .animate() function, as the name of the function that the animation is in.
See example below:
function animation() {
$('#element')
.animate({ //This moves the div down 90
marginTop: 90
}, 600)
.animate({ //This moves the div back to the top
marginTop: 0
}, 600, animation); //the 'animation' parameter calls this function from the start
}
animation();
#element {
width: 100px;
height: 100px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="element"></div>
Let me know if you need any other help.
I would use CSS for this
.img {
animation: bounce 5s infinite;
position: absolute;
}
#keyframes bounce {
0% {
top: 10px;
}
50% {
top: 200px;
}
100% {
top: 10px;
}
}
<img class="img" src="http://placehold.it/100x100" />

How to combine setTimeout() function with jquery stop() function?

I know to use stop() function to force queuing operations. For instance,
$(seletor).stop().fadeIn();
It prevents multiple fade effects when user triggers the mouseenter or mouseouter events.
Now I want to use stop() function with setTimeout() function or something else to prevents multiple mimic queuing effects.
Here is HTML:
<div class="container">
<div class="inner"></div>
<div class="inner2"></div>
</div>
CSS:
.container{
width: 200px;
height: 400px;
overflow: scroll;
background-color: #ccc;
position: relative;
}
.inner, .inner2{
width: 10px;
height: 500px;
background-color: red;
}
.inner{
display: none;
}
.inner2{
position: absolute;
left: 10px;
top: 0;
background-color: green;
}
JS:
$(function(){
//$(".container").stop().on("scroll", function(){
$(".container").on("scroll", function(){
$(".inner").stop().fadeIn();
setTimeout(function(){
$(".inner").stop().fadeOut();
}, 1000);
});
});
And jsfiddle ftw:)
My purpose is to trigger the setTimeout function to hide the red part when user scroll the div. But as I said before, I do not know how to combine stop() and setTimeout() function together. The red part would fadein and fadeout many times with a sequence when scroll multiple times.
Please help me, many thanks!
If you want it to keep fading in/out, you should chain the .fadeIn().fadeOut()
Something like this may be more what you're looking for...
$(function(){
var ref = null;
$(".container").on("scroll", function(){
clearTimeout(ref);
$(".inner").stop().fadeIn();
ref = setTimeout(function(){
$(".inner").stop().fadeOut();
}, 1000);
});
});
This will keep tacking on fadin/out events for animation, then when you stop scrolling for a second, the stop/fadeout takes hold.

Is it possible to loop changing opacity values in HTML5 or css?

This is the code I'm currently working with. It works to my purposes of layering the two images. What I am trying to do is have the layer0 opacity lower to 0 as the layer1 opacity increases to 100 over a few seconds. {and then on to layer1 with layer2 and so on eventually looping back to layer0}
Any help would be appreciated.
<head>
<style>
div.layer0
{
width: 371px;
height: 345px;
background:url(image2.jpg);
opacity:1;
filter:alpha(opacity=100); /* For IE8 and earlier */
}
div.layer1
{
width: 371px;
height: 345px;
background:url(image3.jpg);
opacity:0;
filter:alpha(opacity=0); /* For IE8 and earlier */
}
</style>
</head>
<body>
<div class="layer0">
<div class="layer1">
</div>
</div>
</body>
To continually do this in a loop, you'll need some javascript to add an appropriate active class to the image you want displayed. Then using CSS transitions you can achieve the fading between images that you require.
I created a jsfiddle to give you an example of this working: http://jsfiddle.net/pacso/H6dqq/
The basics are as follows.
Some simple HTML divs which you'll be fading:
<div class='red square active'></div>
<div class='yellow square'></div>
<div class='green square'></div>
<div class='blue square'></div>
These are just going to be coloured squares, but yours could contain images.
Next, some CSS markup:
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.square {
width: 200px;
height: 200px;
position: absolute;
top: 20px;
left: 20px;
opacity: 0;
transition: opacity 2s;
-webkit-transition: opacity 2s; /* Safari */
}
.active {
opacity: 1;
}
Note that my transition will alter the opacity of the div itself. You may need to change this as needed.
Now the javascript to make it work on an endless loop:
jQuery(function() {
window.setInterval(function () {
activeSquare = $('.active');
nextSquare = activeSquare.next()
if (nextSquare.length == 0) {
nextSquare = activeSquare.siblings().first();
}
nextSquare.addClass('active');
activeSquare.removeClass('active');
}, 3000);
});
Fairly straightforward. Click the link to my fiddle and hit the run button if you want to see a working demo.
Short answer: not easily.
You're probably better off with javascript for the looping. You could make a delayed keyframe animation, but that won't allow you to loop from the start again: jsfiddle.net/G4PTM (firefox/ie10) -- You could make a lot of keyframes with different timings and you can make it work, but it would require quite a bit of code and not scale well (say you wanted to add another layer/image the code would quickly become unmanagable)
With some javascript, you can just loop through the divs and add and remove a classname to trigger the transitions, like Jon mentioned. Here is a working demo (using jQuery for simplicity, let me know if you need vanilla js)
html
<div class="layer0">
</div>
<div class="layer1">
</div>
<div class="layer2">
</div>
css
div {
width: 371px;
height: 345px;
opacity: 0;
position: absolute;
transition: opacity 2s;
}
div.active {
opacity: 1;
}
div.layer0 {
background:url(http://lorempixel.com/373/345);
}
div.layer1 {
background:url(http://lorempixel.com/372/345);
}
div.layer2 {
background:url(http://lorempixel.com/374/345);
}
js+jquery
var firstDiv = $(".layer0");
var current;
function loopsie() {
// if first iteration or reached end, use first div
if (!current || !current.length) current = firstDiv;
current.addClass("active");
setTimeout(function() {
current.removeClass("active");
setTimeout(function() {
current = current.next();
loopsie(); // recurse
}, 2000);
}, 2000);
}
//initialize
loopsie();
Working demo at http://jsfiddle.net/G4PTM/2/
Plain JavaScript (Without jQuery):
var firstDiv = document.querySelector(".layer0"); // IE 8+
var current;
function loopsie() {
// if first iteration, use first div
if (!current) current = firstDiv;
current.classList.add("active"); // IE 10+, shim at https://developer.mozilla.org/en-US/docs/Web/API/Element.classList
setTimeout(function() {
current.classList.remove("active");
// account for text node (if there is whitespace in html)
if (current.nextSibling && current.nextSibling.nodeName == "DIV") {
current = current.nextSibling;
} else if (current.nextSibling && current.nextSibling.nextSibling && current.nextSibling.nextSibling.nodeName == "DIV") {
current = current.nextSibling.nextSibling;
} else {
// reached end
current = firstDiv;
}
loopsie(); // recurse
}, 2000);
}
//initialize
loopsie();
http://jsfiddle.net/G4PTM/6/
You can use CSS transitions. The example below fades .layer0 in and out in a timespan of 500 ms:
div.layer0 {
opacity: 1;
-webkit-transition:opacity 500ms ease-out;
-moz-transition:opacity 500ms ease-out;
-o-transition:opacity 500ms ease-out;
transition:opacity 500ms ease-out;
}
div.layer0:hover {
opacity: 0;
}

Categories