I have the following code on my website....
At the moment, when "Test 1" is clicked the animation starts. After that, when "Test 2" or "Test 3" is clicked the animation does not restart...
How would I restart the animation when any of the links are clicked ?
And is it possible to have a Fade out and Fade In, after a link has been clicked ?
HTML Markup:
<div id="anim"></div>
</br>
</br>
<li id="item1"><span></span>Test 1</li>
<li id="item2"><span></span>Test 2</li>
<li id="item3"><span></span>Test 3</li>
CSS:
#anim {
width: 14px; height: 14px;
background-image: url(http://mail.google.com/mail/im/emotisprites/wink2.png);
background-repeat: no-repeat;
}
Javascript:
var scrollUp = (function () {
var timerId, height, times ,i = 0 , element;
return {
stop : function(){
clearInterval( timerId );
},
init :function( h, t, el ){
height = h;
times = t;
element =el ;
},
start : function ( ) {
timerId = setInterval(function () {
if (i > times) // if the last frame is reached, set counter to zero
clearInterval(timerId);
element.style.backgroundPosition = "0px -" + i * height + 'px'; //scroll up
i++;
}, 100); // every 100 milliseconds
}
};
})();
scrollUp.init(14, 40, document.getElementById('anim'));
// start animation:
document.getElementById('item1').addEventListener('click', function(){
scrollUp.start();
}, false );
Here's a Fiddle : http://jsfiddle.net/ctF4t/3/
As far as I understand, you want the animation (whatever state it is currently) to restart if one of the buttons is clicked?
Well, if so, first you should call the stop function everytime before the start:
document.getElementById('item1').addEventListener('click', function(){
scrollUp.stop();
scrollUp.start();
}, false );
Additionally, the index has to be reset in the stop:
stop : function(){
clearInterval( timerId );
i = 0;
},
This will do the job for the button #item1. Here is a demo. Applying this to the others should not be the big trouble now. For example bind the event to the <body/> and read the target:
function startAnimation(e) {
e = e || window.event;
var target = e.target || e.srcElement;
target = target.parentNode;
if (!target.id.match(/item[0-3]/)) {
return e;
}
scrollUp.stop();
scrollUp.start();
}
document.body.addEventListener('click',startAnimation,false);
Here is the complete demo.
How would I restart the animation when any of the links are clicked ?
To define a restart, you'll want to stop any still-running intervals, reset i to 0 since that marks the "beginning," and start a new interval:
return {
// ...
restart: function () {
this.stop();
i = 0;
this.start();
}
};
You then need to bind to each li so they can all perform a restart():
var items = document.querySelectorAll('#item1, #item2, #item3');
for (var i = 0, l = items.length; i < l; i++) {
items[i].addEventListener('click', function () {
scrollUp.restart();
}, false);
}
I changed your fiddle to this: http://jsfiddle.net/M5pe8/1/
It seems you didn't reset the "i" var, so the animation couldn't restart from the beginning (i.e., from "zero"); i left the alert line (but is commented out), to show you how i got to my conclusions:
if (i > times) // if the last frame is reached, set counter to zero
{
//alert(i + ' > ' + times);
clearInterval(timerId);
i = 0;
}
else
{
element.style.backgroundPosition = "0px -" + i * height + 'px'; //scroll up
i++;
}
And, of course, i added the lines to bind the click event that starts the animation to the other two links (just for completeness). Now, clicking the second time the animation restarts. Is that what you needed?
EDIT: Link to fiddle corrected
Related
I have a setInterval function going trough some div classes, if it finds a div with a particular class it should stop for 3 seconds and then continue running. Notice how I am using:
clearInterval(myInterval);
but I need something else, to start the sequence again or make it to continue running from there.
e.g:
var myInterval = setInterval(function() {
move.removeClass( "girlFromRight" );
runFromRight -= 9;
move = $("#grid"+ runFromRight);
move.addClass("girlFromRight");
if (move.hasClass("man") === true ||
move.hasClass("man-right") === true ||
move.hasClass("man-left") === true )
{
clearInterval(myInterval);
move.addClass('inLove');
move.removeClass('girlFromRight');
setTimeout(function() {
move.removeClass('inLove');
move.addClass('man');
}, 3000);
}
if (c == 9){
clearInterval(myInterval);
}
}, 300);
keyPressed = false;
}, randomTime);
}
Consider using setTimeout and setting the interval (300 or 3000) after each run based on a test. That way you don't have to start and stop setInterval.
A quick example is below, it highlights each div in sequence, pausing longer on any where the text content is evenly divisible by 3 (as an example test).
function doLoop(){
var divs = document.querySelectorAll('div');
var i = 0;
function loop(){
var selected = document.querySelectorAll('.selected');
[].forEach.call(selected,function(el) {
el.className = 'notSelected';
});
divs[i].className = 'selected';
setTimeout(loop, divs[i].textContent % 3? 300 : 3000);
i = ++i % (divs.length - 2);
}
loop();
}
window.onload = doLoop;
.notSelected{}
.selected{
background-color: blue;
}
<div class="notSelected">0</div>
<div class="notSelected">1</div>
<div class="notSelected">2</div>
<div class="notSelected">3</div>
<div class="notSelected">4</div>
<div class="notSelected">5</div>
I am using the following as a content slider but unsure as to instead have the click the button to play the slides through but wanting to take that away and for the slides to go go through on load?
DEMO
$(document).ready(function() {
var height = 300,
width = 600,
tabs = 3,
$tabs = $('.tab'),
contentNum = 1,
delay = 2000, // time in milliseconds to pause between tabs
timer;
$('.play').click(function(){
var $t = $(this);
if ($t.hasClass('playing')) {
// stop
clearTimeout(timer);
$t.removeClass('playing').html('play');
} else {
// play
timer = setInterval(function(){
contentNum++; // change to contentNum--; to go left
if (contentNum > tabs){ contentNum = 1; } // loop right
if (contentNum < 1) { contentNum = tabs; } // loop left
$tabs.eq(contentNum-1).find('a').trigger('click');
}, delay);
$t.addClass('playing').html('stop');
}
});
$('.main_inner').css({
width: tabs * width
});
$('a.tab_link').click(function() {
$tabs.filter('.active').removeClass('active');
$(this).parent().addClass('active');
// make sure contentNum is a number and not a string
contentNum = parseInt( $(this).attr('rel'), 10 );
$('.main_inner').animate({
marginLeft: '-' + (width * contentNum - width)
}, 600);
return false;
});
});
No really sure what you mean.
If you wan't to autoplay on page load and keep the Play button use
$('.play').trigger('click');
If you wan't to autoplay without play/stop button replace
$('.play').click(function(){
// you current play/pause button code
});
simply by
// play
setInterval(function(){
contentNum++; // change to contentNum--; to go left
if (contentNum > tabs){ contentNum = 1; } // loop right
if (contentNum < 1) { contentNum = tabs; } // loop left
$tabs.eq(contentNum-1).find('a').trigger('click');
}, delay);
I am using this script to hide and show text however, I want to make the transition smoother but I am not sure how to. Here's a demo of it: http://jsfiddle.net/LnE5U/.
Please help me change it to make it smoother.
hide/show text
<div id="showOrHideDiv" style="display: none">hidden text</div>
<script language="javascript">
function showOrHide()
{
var div = document.getElementById("showOrHideDiv");
if (div.style.display == "block")
{
div.style.display = "none";
}
else
{
div.style.display = "block";
}
}
</script>
Here is an example using jQuery's fadeToggle (a shortcut for a more complicated animate)
// assuming jQuery
$(function () { // on document ready
var div = $('#showOrHideDiv'); // cache <div>
$('#action').click(function () { // on click on the `<a>`
div.fadeToggle(1000); // toggle div visibility over 1 second
});
});
HTML
<a id="action" href="#">hide/show text</a>
<div id="showOrHideDiv" style="display: none;">hidden text</div>
DEMO
An example of a pure JavaScript fader. It looks complicated because I wrote it to support changing direction and duration mid-fade. I'm sure there are still improvements that could be made to it, though.
function generateFader(elem) {
var t = null, goal, current = 0, inProgress = 0;
if (!elem || elem.nodeType !== 1) throw new TypeError('Expecting input of Element');
function visible(e) {
var s = window.getComputedStyle(e);
return +!(s.display === 'none' || s.opacity === '0');
}
function fader(duration) {
var step, aStep, fn, thisID = ++current, vis = visible(elem);
window.clearTimeout(t);
if (inProgress) goal = 1 - goal; // reverse direction if there is one running
else goal = 1 - vis; // else decide direction
if (goal) { // make sure visibility settings correct if hidden
if (!vis) elem.style.opacity = '0';
elem.style.display = 'block';
}
step = goal - +window.getComputedStyle(elem).opacity;
step = 20 * step / duration; // calculate how much to change by every 20ms
if (step >= 0) { // prevent rounding issues
if (step < 0.0001) step = 0.0001;
} else if (step > -0.0001) step = -0.0001;
aStep = Math.abs(step); // cache
fn = function () {
// console.log(step, goal, thisID, current); // debug here
var o = +window.getComputedStyle(elem).opacity;
if (thisID !== current) return;
if (Math.abs(goal - o) < aStep) { // finished
elem.style.opacity = goal;
if (!goal) elem.style.display = 'none';
inProgress = 0;
return;
}
elem.style.opacity = (o + step).toFixed(5);
t = window.setTimeout(fn, 20);
}
inProgress = 1; // mark started
fn(); // start
}
return fader;
}
And using it
window.addEventListener( // this section matches the code above
'load',
function () {
var fader = generateFader(document.getElementById('showOrHideDiv'));
document.getElementById('action').addEventListener(
'click',
function () {
fader(1000);
}
);
}
);
DEMO of this
This is quite simple. I have just made a demo and i used setInterval
Here's how it works
var fadeout = function( element ) { // 1
element.style.opacity = 1; // 2
window.setInterval(function() { // 3
if(element.style.opacity > 0) { // 4
element.style.opacity = parseFloat(element.style.opacity - 0.01).toFixed(2); // 5
} else {
element.style.display = 'none'; // 6
}
}, 50);
};
JSFiddle Demo Link
Steps
Create a function that accepts a DOM element
Set the opacity of the element to 1
Create a function that loops every 50ms
If the opacity is greater than 0 -> continue
Take away 0.01 from the opacity
if it's less than 0 the animation is complete and hide it completely
Note this is a really simple example and will need a bit of work
You can use somthing like this
$('.showOrHideDiv').toggle(function() {
$('showOrHideDiv').fadeIn('slow', function() {
//fadeIn or fadeOut, slow or fast, all the stuffs you want to trigger, "a function to execute every odd time the element is clicked," says the [jquery doc][1]
});
}, function() {
//here comes "additional handlers to cycle through after clicks," says the [jquery doc][1]
});
I used OPACITY to make it show/hide. See this Example, Full code (without jQuery):
Click here
<div id="MyMesage" style="display:none; background-color:pink; margin:0 0 0 100px;width:200px;">
blablabla
</div>
<script>
function ShowDiv(name){
//duration of transition (1000 miliseconds equals 1 second)
var duration = 1000;
// how many times should it should be changed in delay duration
var AmountOfActions=100;
var diiv= document.getElementById(name);
diiv.style.opacity = '0'; diiv.style.display = 'block'; var counte=0;
setInterval(function(){counte ++;
if ( counte<AmountOfActions) { diiv.style.opacity = counte/AmountOfActions;}
},
duration / AmountOfActions);
}
</script>
I followed iConnor solution and works fine but it had a small issue setInterval will not stop after the element be hidden I added stop interval to make it better performance
var fadeout = function( element ) { // 1
element.style.opacity = 1; // 2
let hidden_process = window.setInterval(function() { // 3
if(element.style.opacity > 0) { // 4
element.style.opacity = parseFloat(element.style.opacity - 0.01).toFixed(2); // 5
} else {
element.style.display = 'none'; // 6
console.log('1');
clearInterval(hidden_process);
}
}, 50);
};
I have a bug in Javascript where I am animating the margin left property of a parent container to show its child divs in a sort of next/previous fashion. Problem is if clicking 'next' at a high frequency the if statement seems to be ignored (i.e. only works if click, wait for animation, then click again) :
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
//roll margin back to 0
}
An example can be seen on jsFiddle - http://jsfiddle.net/ZQg5V/
Any help would be appreciated.
Try the below code which will basically check if the container is being animated just return from the function.
Working demo
$next.click(function (e) {
e.preventDefault();
if($contain.is(":animated")){
return;
}
var marLeft = $contain.css('margin-left'),
$this = $(this);
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
$contain.animate({
marginLeft: 0
}, function () {
$back.fadeOut('fast');
});
} else {
$back.fadeIn(function () {
$contain.animate({
marginLeft: "-=" + regWidth + "px"
});
});
}
if (marLeft > -combinedWidth) {
$contain.animate({
marginLeft: 0
});
}
});
Sometimes is better if you create a function to take care of the animation, instead of writting animation code on every event handler (next, back). Also, users won't have to wait for the animation to finish in order to go the nth page/box.
Maybe this will help you:
if (jQuery) {
var $next = $(".next"),
$back = $(".back"),
$box = $(".box"),
regWidth = $box.width(),
$contain = $(".wrap")
len = $box.length;
var combinedWidth = regWidth*len;
$contain.width(combinedWidth);
var currentBox = 0; // Keeps track of current box
var goTo = function(n) {
$contain.animate({
marginLeft: -n*regWidth
}, {
queue: false, // We don't want animations to queue
duration: 600
});
if (n == 0) $back.fadeOut('fast');
else $back.fadeIn('fast');
currentBox = n;
};
$next.click(function(e) {
e.preventDefault();
var go = currentBox + 1;
if (go >= len) go = 0; // Index based, instead of margin based...
goTo(go);
});
$back.click(function(e) {
e.preventDefault();
var go = currentBox - 1;
if (go <= 0) go = 0; //In case back is pressed while fading...
goTo(go);
});
}
Here's an updated version of your jsFiddle: http://jsfiddle.net/victmo/ZQg5V/5/
Cheers!
Use a variable to track if the animation is taking place. Pseudocode:
var animating = false;
function myAnimation() {
if (animating) return;
animating = true;
$(this).animate({what:'ever'}, function() {
animating = false;
});
}
Crude, but it should give you the idea.
Edit: Your current code works fine for me as well, even if I jam out on the button. On firefox.
I have a jQuery/JS function that is using setInterval to loop through some image slides I have. It just flips through every 5 seconds...
Now I want it to pause if my mouse is hovered over it. How do I go about doing that on the setInterval function?
var current = 1;
function autoAdvance() {
if (current == -1) return false;
jQuery('#slide_menu ul li a').eq(current % jQuery('#slide_menu ul li a').length).trigger('click', [true]);
current++;
}
// The number of seconds that the slider will auto-advance in:
var changeEvery = jQuery(".interval").val();
if (changeEvery <= 0) {
changeEvery = 10;
}
var itvl = setInterval(function () {
autoAdvance()
}, changeEvery * 1000);
Something like this would work assuming interval is defined in an outer scope:
$('.slideshow img').hover(function() {
interval = clearInterval(interval);
}, function() {
interval = setInterval(flip, 5000);
});
(function () {
var imgs = $('#your_div img'), index = 0, interval,
interval_function = function () {
imgs.eq(index).hide();
index = (index + 1) % imgs.length;
imgs.eq(index).show();
};
imgs.eq(0).show();
interval = setInterval(interval_function, 5000);
$('#your_div').hover(function () {
clearInterval(interval);
}, function () {
interval = setInterval(interval_function, 5000);
});
}());
Example: http://jsfiddle.net/Zq7KB/3/
I reused some old code I wrote for a question the other day, but I figured it didn't matter that much. The trick is to store your interval in a variable that you keep in the background. Then, when you hover over the container, clear the interval. When you hover out of the container, re-set the interval. To get a better feel of how this works, change those 5000s to 1000s so it passes more quickly for testing.
Hope this helps.