JavaScript setTimeout() Method on Animation - javascript

I have three yellow bars and each of them needs to come from left to right. For that, I have produced this code, but it only works on the last one. Can anyone correct this code; I need to work with pure JavaScript. I am not using any framework. Thanks.
window.onload = function(){
var yellowTitles = document.getElementById('magazine-brief').getElementsByTagName('h2');
for(i=0; i< yellowTitles.length; i++) {
var header = yellowTitles[i];
var timer = i*500;
var yellowBar = setTimeout(animeYellowBar,timer);
function animeYellowBar(){
header.style.left= "0";
}
}
}

Here's how I'd solve the problem:
var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
// this will force the header number to be bound correctly
// also animates the div across the page by tracking the current position of x
function createMotion(num){
var currPos = 0;//current x position
var delta = 10;//move by this amount
setInterval(function(){
currPos += delta
yellows[num].style.left = currPos;
}, num * 500);
}
for (var i = 1; i < yellows.length; i++)
{
createMotion(i);
}
Note the function "createMotion" - added so the number "i" is correctly reference in the setInterval function.

Shouldn't you be incrementing your CSS left value instead of just setting it to 0? Why have a timeout at all if you're just going to set the value without gradually incrementing or decrementing?
If you do actually want to use a gradual animation, look at this tutorial : http://www.schillmania.com/content/projects/javascript-animation-1/
Very descriptive and possibly what you want.

By the time your timeout function runs, header refers to your last h2.
Try editing your timeout function to this:
function animeYellowBar(){
var thisheader=header;
thisheader.style.left= "0";
}

var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
for (var i = 0; i < yellows.length; i++)
{
(function(idx, el){
window.setTimeout(function(){
var interval = window.setInterval(function(){
el.style.left = parseInt(el.style.left) + 10; // adjust this movement step
if (parseInt(el.style.left) >= 0)
{
el.style.left = 0;
window.clearInterval(interval);
}
}, 100); // adjust this number for animation speed
}, (idx++) * 500);
})(i, yellows[i]);
}

Related

Svg object modified with setAttributeNS not updating until after while loop

I'm creating a small game in javascript and I'm using svg for the graphics. Right now I'm having a problem with updating the game in the middle of a game tick. If I exit my loop directly after I update the fill attribute with "setAttributeNS", it's redrawn, but if I don't do that, it isn't updated until after "game_tick" is over. Even worse, if I call "game_tick" multiple times in a row, the svg objects aren't updated until after I've run all of the "game_tick"s instead of being updated after each one.
function game_tick(){
num_grid_copy = num_grid.slice();
for (var x = 0; x < num_squares_x; x += 1) {
for (var y = 0; y < num_squares_x; y += 1) {
var n = get_neighbors(x,y);
var isAliveInNextGen = next_gen(n, num_grid[x*num_squares_x+y]);
num_grid_copy[x*num_squares_x+y] = isAliveInNextGen;
if (isAliveInNextGen == 1){
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#0099ff');
}
else {
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#fff');
}
}
}
num_grid = num_grid_copy;
}
Thanks to valuable input from Robert I realized that javascript execution and page rendering are done in the same thread. I changed the function to the following:
function start() {
var inc = 0,
max = 25;
delay = 100; // 100 milliseconds
var repeat = setInterval(function() {
game_tick();
if (++inc >= max)
clearInterval(repeat);
},
delay);
}
This works fine. I can set the delay and the number of times it repeats.

How do I delay this code running in JavaScript?

I have written this code to change an image:
change = function(){
for (r=0; r<6; r++){
for (i = 0; i < 6 ; i++) {
setInterval(imgfile(number=i+1), 5000);
}
}
}
imgfile= function(number){
a = 'document.getElementById("imgdiv").src = "images/'+number+'.svg"';
eval(a);
}
The function change() is called when a button is clicked.
When I press the button the image changes straight to 6.svg, when I want it to go through the images 1, 2, 3, 4, 5, 6 and to repeat it 6 times. When I change setInterval to change.setInterval or imgfile.setInterval it doesn't work at all. How do I fix this?
change = function(i=0){
imgfile(i%6+1);//change image
if(i<36) setTimeout(change,5000,i+1);//next image in 5 seconds
}
imgfile= function(number){
document.getElementById("imgdiv").src = "images/"+number+".svg";//no need to use ev(i||a)l
}
Instead of loop/interval mess you can simply start a timeout that restarts itself after changing the image... This code will loop over 6 images with a delay of 5 seconds and that 6 times...
Something like this, perhaps?
var index, imgCount, loopCount, imgTag, countdown;
index = 0;
imgCount = 6;
loopCount = 6;
imgTag = document.getElementById('imgdiv');
countdown = function () {
if (index < imgCount * loopCount) {
imgTag.src = 'images/' + index % imgCount + '.svg';
index = index + 1;
setTimeout(countdown, 5000);
}
};
countdown();
Here we're avoiding the double loop and using modular math (index % imgCount) to get the right file number.
For another question I wrote a nice utility function that has quite a number of uses, but can also handle this scenario very easily. The main issue is that there is no time elapsing between the different delays being set. So you are setting 6 different actions to all happen within 5000ms, and all will occur at the same moment.
Here's my original answer
Here's the utility function for that answer, along with its application to your problem.
function doHeavyTask(params) {
var totalMillisAllotted = params.totalMillisAllotted;
var totalTasks = params.totalTasks;
var tasksPerTick = params.tasksPerTick;
var tasksCompleted = 0;
var totalTicks = Math.ceil(totalTasks / tasksPerTick);
var initialDelay = params.initialDelay;
var interval = null;
if (totalTicks === 0) return;
var doTick = function() {
var totalByEndOfTick = Math.min(tasksCompleted + tasksPerTick, totalTasks);
do {
params.task(tasksCompleted++);
} while(tasksCompleted < totalByEndOfTick);
if (tasksCompleted >= totalTasks) clearInterval(interval);
};
// Tick once immediately, and then as many times as needed using setInterval
if (!initialDelay) doTick();
if (tasksCompleted < totalTicks) interval = setInterval(doTick, totalMillisAllotted / totalTicks);
}
// Do 6 actions over the course of 5000 x 6 milliseconds
doHeavyTask({
totalMillisAllotted: 5000 * 6,
totalTasks: 6,
tasksPerTick: 1,
initialDelay: false, // Controls if the 1st tick should occur immediately
task: function(n) { console.log('Set image to "images/' + (n + 1) + '.svg"'); }
});
You want to do setTimeout().
setTimeout pauses for the millesecond value and then does the code. Where setInterval runs the code every whatever milleseconds.
Yeah, don't do change.setInterval or whatever, it is just setInterval.
An example for you would be this inside the for loop to replace the setInterval function.
setTimeout(imgfile(i+1), 5000);

JavaScript: setTimeout not updating value inside loop

I'm aware of closures, IIFE.
I've read the other answers (they all point to using IIFE).
So why is this not working?
my image should gradually fade-in (in 2s)
it seems like it's only rendering once (with final value)
var imgFade = document.getElementById('img-fade');
for(i = 0; i < 100; i++){
(function(step) {
setTimeout(function() {
imgFade.style.opacity = (step/100);
}, 20);
})(i);
}
here's the code: https://jsfiddle.net/warkentien2/Lh10phuv/1/
EDIT: for future readers
consider all answers transitioning from i = 1; to 1 <= 100, i++ so it won't stop rendering at 99%
A quick but dirty way is multiplying the 20 by step. You create all the timeouts at once, so the ones that are supposed to be executed later have higher delay:
var imgFade = document.getElementById('img-fade');
for(i = 0; i < 100; i++){
(function(step) {
setTimeout(function() {
imgFade.style.opacity = (step/100);
}, step * 20);
})(i);
}
Heres another solution, applying the fade in one after another:
var fade = function(step){
imgFade.style.opacity = (step/100);
if(step < 100){
setTimeout(function(){ fade(++step); }, 20);
}
};
fade(0);

Stop javascript increment at a certain value

I have coded this small script which increments a given value, in this case 200, by 1 every 3.2 seconds.
var i = 200;
function increment() {
i++;
document.getElementById('generated').innerHTML = Number(i).toLocaleString('en');
}
setInterval('increment()', 3200);
I'm trying to make the script stop increasing the value once it reaches a certain point (let's say 300 for example). I'm sure it's a simple fix but I can't think up of how to go about this.
You need to save the interval and then clear it:
var i = 200;
function increment() {
if (i >= 300) {
clearInterval(interval);
return;
}
i++;
document.getElementById('generated').innerHTML = Number(i).toLocaleString('en');
}
var interval = setInterval(increment, 3200);
Note that you can pass a function name instead of using the "interval()" string notation.
Here is a fiddle (I've sped up the time so that it doens't take forever to prove a point)
Hope it helps!
var i = 200;
function increment() {
if (i == 300) {
// stop when it hits 300
window.clearInterval(id);
return;
}
i++;
document.getElementById('generated').innerHTML = Number(i).toLocaleString('en');
}
var id = window.setInterval('increment()', 3200);
I think you could put it in IF statement as:
var i = 200;
function increment() {
if(i<300){
i++
}
}
increment();
You could use a for loop.
var i = 200;
var max = 300;
function increment() {
for (i < max; i++) {
document.getElementById('generated').innerHTML = Number(i).toLocaleString('en');
}
}
setInterval('increment()', 3200);
More info here: http://www.w3schools.com/js/js_loop_for.asp

for loop does not stop at each index

var switchTabs = function(index, el) {
//alert("Call SwitchTabs");
ribbon.slideTo(index);
ribbon.currentSlideIndex = parseInt(index, 10);
//console.log(ribbon.currentSlideIndex);
dojo.query('.ibm-slider-wrapper #ibm-thumb-slider-tabs li.ibm-active').removeClass('ibm-active');
dojo.query(el).addClass('ibm-active'); //applies class to current active li
//fixTabHeight(index == 4);
}
This below section of the auto scroll runs and does not stop 1 index at a time. It jumps straight to 6 and so my slider moves from 0 to 6th position. I want it to move 1 at a time after 8 seconds.
How can I make it stop each index and run the swapTabs(a, b); and then trigger an increment in the index variable inside autoScroll?
I tried using setInterval() but it still does function the way I want. Ideally I would like to use Switch statement for each index and trigger swapTabs inside setInterval so I can manage the timer for individual index key. Any help is highly appreciated.
var autoScroll = function(){
//alert("Inside AutoScroll");
//var tabCount = $('.ibm-slider-wrapper #ibm-thumb-slider-tabs li');
for(var i = 0; i < 6; i++) {
var tabsIndex = $('.ibm-slider-wrapper #ibm-thumb-slider-tabs li a');
switchTabs(parseInt(tabsIndex[i].getAttribute('rel'), 10), tabsIndex[i].parentNode);
console.log(tabsIndex[i]);
}
}
autoScroll();
Use setTimeout and have the function call itself:
var i = 0, interval = 8000, iterations = 6;
var autoScroll = function(){
// function body here
i++;
console.log("Iteration #" + i);
if (i < iterations) {
setTimeout(autoScroll, interval);
}
}
// start first run
autoScroll();
Your code just goes from index 0 to 5 in rapid succession (within ms of each other) and the browser probably doesn't display anything until your script finishes on index 6.
If you want it to stop and show each tab, then you need to use something like setTimeout() and advance one tab each time the timer fires.
(function() {
var indexCntr = 0;
var tabsIndex = $('.ibm-slider-wrapper #ibm-thumb-slider-tabs li a');
function autoScroll() {
if (indexCntr < 6) {
switchTabs(parseInt(tabsIndex[index].getAttribute('rel'), 10), tabsIndex[i].parentNode);
++indexCntr;
setTimeout(autoScroll, 5000); // set the proper delay time here
}
}
autoScroll();
})();

Categories

Resources