I need to animate something, but my statement has no effect. My code:
var movei=function(img){
img.setAttribute("src", "blank.png");
}
var comp=function() {
...
for(var k=0; k<i; k++) {
var img=document.getElementById(id(k,col));
img.setAttribute("src", "circ1.png");
timer=setTimeout(movei(img),1000);
...
}
}
I read another questions about setTimeout (setInterval) but I couldn`t find an answer.
try timer=setTimeout(function(){movei(img);},1000);
If you want to animate individual elements, you should use recursion instead of loops.
Following code depicts the same:
var count = 0;
function getId(count) {
return "div_" + count;
}
function initTimer() {
setTimeout(function() {
count++;
var _id = getId(count);
var _el = document.getElementById(_id);
show(_el);
if (count < 7)
initTimer();
}, 1000);
}
function show(el) {
el.style.display = "block";
}
initTimer();
div {
display: none;
}
<div id="div_1">1</div>
<div id="div_2">2</div>
<div id="div_3">3</div>
<div id="div_4">4</div>
<div id="div_5">5</div>
<div id="div_6">6</div>
As #deceze has also written, you need to change the call to setTimeout so that you do not call the movei function, but rather pass the function 'name'. Then you would of cause have to change the behavior the function movei so it either gets a simple string name of the image or can lookup the image itself.
timer=setTimeout(movei,1000);
or (in the not recommented way)
timer=setTimeout("movei(\"imgName\")",1000);
Related
If I write the html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<h1 id="message">
</h1>
and the JS:
messages = ["Here", "are", "some", "messages."]
$(function() {
for (var i = 0; i < messages.length; i++) {
$('#message').html(messages[i]).delay(1000);
}
});
and load the page, I expect to see each string in the array show up with a delay in between. However, all I see is "messages." appear. It seems that the for loop iterates immediately through each value in the array before performing any delay.
I have seen another method for getting the desired visual result (How can I change text after time using jQuery?), but I would like to know why the earlier method does not work. What is going on when this code is executed?
This is how i would delay my message changing.
function delayLoop(delay, messages) {
var time = 100;
$(messages).each(function(k, $this) {
setTimeout(function()
{
$("#message").html($this);
}, time)
time += delay;
});
}
delayLoop(1000, ["Here", "are", "some", "messages."]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message">
</div>
All I did was for each message delay by an additional delay time.
It works in async mode so its not ui blocking and the messages will display a second after one another.
EDIT:
Removed the .delay from the .html it is redundant.
Note that jQuery's delay is specifically for effects; methods like html do not use the effects queue and are therefore not affected by delay.
This is a problem better solved with JavaScript's native setTimeout function. There are many ways to do this; in fact, you don't even need jQuery!
let messages = ["Here", "are", "some", "messages."];
let delay = 1000;
let header = document.getElementById("message");
messages.forEach(function(message, i) {
setTimeout(function() {
header.innerText = message;
}, delay * i);
});
<h1 id="message" />
You would need something along the lines of
$(function() {
for (var i = 0; i < messages.length) {
var done=false;
$('#message').html(messages[i]).delay(1000).queue(function(){
done=true;
$(this).dequeue();
});
if(done==true){
i++;
}
}
});
Thank you for the answers and comments--very helpful.
I also found this post helpful: Node.js synchronous loop, and from it wrote this (which also works):
function changeText() {
var msg = messages.shift();
$('#message').html(msg).show(0).delay(1000).hide(0, function() {
if (messages.length > 0) {
changeText();
}
});
}
(I used .show and .hide because without them only one of the array values appeared. I'm not sure why that is, but that's a question for another time.)
I'm trying to create a simple slideshow effect. I have 10 images, and I've created a basic HTML page with 2 buttons to go to the right or left image. On clicking the button, the images change.
Now, I'm trying to add a basic fade functionality to the changing image. But the fade effect isn't getting displayed. When I put alerts, I notice that the fade is taking place, but without the alerts it is too fast to be visible. Also, it is happening on the previous image, instead of the next one.
<html>
<head>
<style>
.main {
text-align: center;
}
.centered {
display: inline-block;
}
#image {
border: solid 2px;
width: 500px;
height: 500px;
}
#number {
font-size: 30px;
}
</style>
<script>
function goLeft() {
var image = document.getElementById("image");
var pos = document.getElementById("number");
if(Number(pos.innerHTML)==1) {
image.src = "Images\\10.jpg"
pos.innerHTML = 10;
} else {
image.src = "Images\\" + (Number(pos.innerHTML)-1).toString() + ".jpg"
pos.innerHTML = (Number(pos.innerHTML)-1).toString();
}
for (var i=0; i<25; i++) {
setTimeout(changeOpacity(image, i), 1000);
}
}
function changeOpacity(image, i) {
alert(parseFloat(i*4/100).toString());
image.style.opacity = (parseFloat(i*4/100).toString()).toString();
}
function goRight() {
var image = document.getElementById("image");
var pos = document.getElementById("number");
if(Number(pos.innerHTML)==10) {
image.src = "Images\\1.jpg"
pos.innerHTML = 1;
} else {
image.src = "Images\\" + (Number(pos.innerHTML)+1).toString() + ".jpg"
pos.innerHTML = (Number(pos.innerHTML)+1).toString();
}
for (var i=0; i<25; i++) {
setTimeout(changeOpacity(image, i), 1000);
}
}
</script>
</head>
<body>
<div class="main">
<div class="centered">
<img id="image" src="Images\1.jpg">
</div>
</div>
<div class="main">
<div class="centered">
<span id="number">1</span>
</div>
</div>
<div class="main">
<div class="centered">
<button onclick="goLeft()" style="margin-right:50px;">Go Left</button>
<button onclick="goRight()" style="margin-left:50px;">Go Right</button>
</div>
</div>
</body>
The problem is this block of code that is in your goLeft method, and goRight method:
for (var i=0; i<25; i++) {
setTimeout(changeOpacity(image, i), 1000);
}
You are creating 25 timers that, and each timer will execute approximately 1 second later.
Creating animations is best left to the CSS.
In your CSS add:
#image {
transition: opacity 0.5s ease;
}
And then in your JavaScript, simply: image.style.opacity = 1.0;
When the opacity changes, CSS will automatically transition the opacity length at the speed defined in the css, e.g 0.5s. Feel free to experiment.
I also added a jsfiddle here: http://jsfiddle.net/dya7L8wq/
You misunderstood setTimeout and the for loop.
Norman's answer provides a good solution with CSS, but he doesn't talk too much about why your code is not working. So I'd like to explain.
for (var i=0; i<25; i++) {
setTimeout(changeOpacity(image, i), 1000);
}
You assumption is:
invoke changeOpacity(image, 0) after 1 second
invoke changeOpacity(image, 1) 1 second after step 1
invoke changeOpacity(image, 2) 1 second after step 2
invoke changeOpacity(image, 3) 1 second after step 3
....
And the last step is invoking changeOpacity(image, 24) 1 second after previous step.
What actually happens is:
The loop is finished almost immediately!
In each iteration, setTimeout queues an asynchronous function invocation, and it's done! That says, it will return right away, rather than wait until changeOpacity returns.
And then, after about 1 second, changeOpacity fires 25 times almost at the same time, because you queued it 25 times in the for loop.
Another problem here is: in changeOpacity invocations, passed-in parameter i are not 1, 2, 3...., they all have the same value that causes for loop to exit (1 second ago) - 25, because JS doesn't have a block scope prior to ES6 (in ES6 we have keyword let for it).
In a pure JS solution, to ensure the time sequence we'd usually queue next invocation at the end of every step:
function changeOpacity() {
// do something here
// before the function returns, set up a future invocation
setTimeout(changeOpacity, 1000)
}
Here's an example to print a list of numbers from 1 to 5:
var go = document.getElementById('go')
var op = document.getElementById('output')
var i = 0
function printNum() {
var p = document.createElement('p')
p.innerHTML = ++i
op.appendChild(p)
// next step
if(i < 5) {
setTimeout(printNum, 500)
}
}
go.onclick = printNum
<button id="go">GO</button>
<div id="output"></div>
Why use pure JavaScript?
Use jQuery.
It has a pretty neat fadeTo() function and a useful fadeIn() function.
Might wanna use that ;)
I'm programming an image slideshow and for some reason it isn't working. Below I have the HTML:
<div id = "images">
<img id = "imageSrc" />
</div>
Here is my JavaScript which is what I'm using to change my images:
var images = document.getElementById("imageSrc");
var x = 0;
var imagesArray = ["image.png", "anotherImage.png", "yetAnotherImage.png"];
function changeImages() {
images.src = imagesArray[x];
if (x < 2) {
x++;
} else {
x = 0;
}
alert(images.src);
}
setInterval(changeImages(), 3000);
Demo
Why am I not getting an alert every 3 seconds with my image code? The images aren't switching so where is my mistake?
Thanks in advance for your help!
When calling a function as an argument, don't use parentheses.
setInterval(changeImages, 3000);
Demo
If you did need to pass arguments in the function call, wrap it in an anonymous function:
setInterval(function() {
var myArg;
changeImages(myArg);
}, 3000);
Demo
Remove the curly braces when you are calling the function
Change
setInterval(changeImages(), 3000);
to
setInterval(changeImages, 3000);
Basically I need the thumbnails to rotate every time the user hovers over an image. Here is my failed attempt:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$('img').hover(function() {
theImage = $(this).attr('id');
otherImages = $(this).attr('class').split('#');
rotateThumbs(otherImages, theImage);
}, function() {
//
});
});
function rotateThumbs(otherImages, theImage) {
for (i=0; i < otherImages.length; i++) {
setInterval($('#'+theImage).attr('src', otherImages[i]), 1000);
}
}
</script>
<img id="myImage" src="http://www.google.com/images/logos/ps_logo2.png" class="http://www.google.com/images/logos/ps_logo2.png#http://l.yimg.com/a/i/ww/met/yahoo_logo_us_061509.png#http://dogandcat.com/images/cat2.jpg" width="174" height="130" />
Does anyone know how this may be accomplished?
Some issues here.
setInterval requires a function reference as it's first argument, but you are executing code that returns a jQuery object.
setInterval executes the first function repeatedly at the specified interval. Is that what you are trying to do? Swap images every second?
Depending on how you correct the first issue, you could run into an issue where i is otherImages.length and thus the src is set to undefined.
Assuming you worked around issue 3, you will have the problem that the image swaps will happen imperceptibly fast and it will appear as though the last image is always displayed.
Instead, don't use a loop. Increment a counter each time a new image is displayed. Try this:
function rotateThumbs(otherImages, theImage) {
var i = 0;
var interval = setInterval(function() {
$('#'+theImage).attr('src', otherImages[i++]);
if (i >= otherImages.length) {
clearInterval(interval);
}
}, 1000);
}
I've implemented a fully-functional example here. This addresses some of the issues that #gilly3 notes, but uses closures instead of an incrementing counter to keep track of the current image:
$(function() {
$('img').hover(function() {
// declaring these variables here will preserve
// the references in the function called by setInterval
var $img = $(this),
imageList = $img.attr('class').split('#'),
intervalId;
// start the cycle
intervalId = window.setInterval(function() {
var next = imageList.pop();
if (next) {
$img.attr('src', next);
} else {
// stop the cycle
intervalId = window.clearInterval(intervalId);
}
}, 1000);
}, function() {});
});
As you can see, using a closure is much easier when you declare the function passed to setInterval inline, rather than as a separate, named function. You could still have a rotateThumbs function if you wanted, but you might need to do some more work to ensure that the variables were being passed properly.
Edit: I made an updated version that continues to cycle as long as the mouse is hovering.
I have adjusted the answer for Sam, taking pre-loading the image into account, so that you won't have a possible deplay at the first rotation.
function rotateThumbs(otherImages, theImage) {
if(!$('#'+theImage).data('setup')){
$('#'+theImage).data('setup', true); // do not double pre-loading images
var $body = $('body');
for(var j = 0; j < otherImages.length; j++){
$body.append($('<img/>').attr('src', otherImages[j])
.css('display', 'none'));
}
}
var i= 0;
setInterval(function(){
$('#'+theImage).attr('src', otherImages[i++]);
if(i >= otherImages.length){i = 0}
}, 1000);
}
I am currently working on a experiment with RAW Javascript. I was wondering why it is not working. In fact I have scratched my head until there is no hair left... :P.
I am making a table with TR elements to be hovered over with some Javascript event. I think you will know exactly what I mean if you look at the code. The point is to get stuff to fade out first and then fade in afterwards when it reaches zero.
I am a beginner and maybe this can be done with the existing code. But of course if it is possible in another way of programming, I am open for suggestions.
THE CODE:
window.onload = changeColor;
var tableCells = document.getElementsByTagName("td");
function changeColor() {
for(var i = 0; i < tableCells.length; i++) {
var tableCell = tableCells[i];
createMouseOutFunction(tableCell, i);
createMouseOverFunction(tableCell, i);
}
}
function createMouseOverFunction(tableCell, i) {
tableCell.onmouseover = function() {
tableCell.style.opacity = 1;
createMouseOutFunction(tableCell, i);
}
}
function createMouseOutFunction(tableCell, i) {
var OpacitySpeed = .03;
var intervalSpeed = 10;
tableCell.onmouseout = function() {
tableCell.style.opacity = 1;
var fadeOut = setInterval(function() {
if(tableCell.style.opacity > 0) {
tableCell.style.opacity -= OpacitySpeed;
} else if (tableCell.style.opacity <= 0) {
clearInterval(fadeOut);
}
}, intervalSpeed);
var fadeIn = setInterval(function(){
if(tableCell.style.opacity <= 0){
tableCell.style.opacity += OpacitySpeed;
} else if(tableCell.style.opacity == 1){
clearInterval(fadeIn);
}
}, intervalSpeed);
}
}
Here is working example of your code (with some corrections)
http://www.jsfiddle.net/gaby/yVKud/
corrections include
Start the fadein once the fadeout is completed (right after you clear the fadeout)
ues the parseFloat() method, because the code failed when it reached negative values.
remove the createMouseOutFunction(tableCell, i); from the createMouseOverFunction because you assign it in the initial loop.
I think you'll probably need to use the this keyword in some of your event binding functions. However I haven't myself got your code to work.
I would recommend using a library such as jQuery. In particular .animate will probably be of use here.