How can I set timers in slideshow to show as selected? - javascript

I have to create a slideshow, using an array of images and have that set on a timer. There is a drop-down menu with slow, medium, and fast options and the pictures need to transition with accordance to the drop down option selected. Whenever I execute this code in a web browser the code repeats itself, while doubling, as I read the value of i in the console.
I have tried using a while and a do-while loop to have the images on a rotation.
I have also tried putting the if-statements outside and below/above the function.
<script>
var i = 0;
function changeImg(){
if (x == 'slow'){
setInterval("changeImg()", 5000);
} else if (x == 'medium'){
setInterval("changeImg()", 3000);
} else if (x == 'fast') {
setInterval("changeImg()", 1000);
} else {}
while (i < 3){
console.log(i);
document.slide.src = sportsArray[i];
i++;
}
console.log(i);
console.log(sportsArray);
}
</sctipt>

First, I would read up on MDN's docs on setInterval() and clearInterval to fill in the knowledge gaps that lead you to approach the problem this way.
You are recursively calling changeImg() in your code which I believe is causing the issue you describe as:
the code repeats itself, while doubling, as I read the value of i in the console
Also, your while loop will run immediately when calling changeImg() which also does not appear to be desired in this situation.
setInterval() mimics a while loop by nature. There is no need for a while loop in this code. Below is a solution that I hope you can use as a reference. I separated the code to determine the interval into a function the getIntervalSpeed.
function changeImg(x) {
var getIntervalSpeed = function(x) {
if (x === 'slow') {
return 5000;
} else if (x === 'medium') {
return 3000;
} else if (x === 'fast') {
return 1000;
} else {
return 3000;
// return a default interval if x is not defined
}
};
var i = 0;
var slideShow = setInterval(function() {
if (i >= sportsArray.length) {
i = 0; // reset index
}
document.slide.src = sportsArray[i]; // set the slide.src to the current index
i++; // increment index
}, getIntervalSpeed(x));
// on click of ANY button on the page, stop the slideshow
document.querySelector('button').addEventListener('click', function() {
clearInterval(slideShow);
});
}

Related

Display a sequence of images in 1 position stored in an object js

I'd like to have an object of images and then loop through them to display each one with a certain interval of time between each one.
Store images in an object:
var images = [
{ name: 'image1', image: 'image1.jpg' },
{ name: 'image2', image: 'image2.jpg' },
{ name: 'image3', image: 'image3.jpg' }
]
Create a loop to go through each image in the object and each time it cycles through it changes the source of the div to the image.
Lastly i'd like the images to stop cycling through the loop of a button is clicked.
So far I have the above object setup along with a function containing a counter which loops through the items in the object.
var add = (function() {
var counter = images.length - 1;
return function() {
if(counter === images.length - 1) {
counter = 0;
} else {
counter+=1;
}
return counter;
}
})();
I then used setInterval to change the src every 0.5 seconds.
setInterval(
function() {
var imageDiv = document.getElementById('image');
var tester = images[add()];
imageDiv.src = tester.image;
}
, 500);
The above seems to console log the correct image OK, but its not changing the source and displaying one of the images once every 0.5 seconds.
Can anyone provide a pointer to help me update the src?
Thank you
A Loop is not necessary here, you can manually keep track of the Current Image like i did with the imgIndex variable and increment it each time the function changeImg() is called. I set that variable back to 0 after it reaches the last image, so it will repeat the Image-Order afterwards.
In the setInterval Function (2nd Argument) you can set the Time each Image should be displayed.
You dont need to worry about Images being loaded multiple times, since
we just replace the src attribute the Browser will handle it.
Any further questions?
images = [
{"name":"img1", "src":"https://phinest.com/wp-content/uploads/2017/02/Maya_Beano_Phinest_4-800x800.jpg"},
{"name":"img2", "src":"https://www.pixel-creation.com/wp-content/uploads/3d-nature-wallpapers-wallpaper-cave-800x800.jpg"},
{"name":"img3", "src":"https://img00.deviantart.net/5fdc/i/2009/162/9/0/nature_stock_14_by_dezzan_stock.jpg"},
{"name":"img4", "src":"https://www.secretescapes.com/inlombardia/img/content/link--nature.jpg"},
{"name":"img5", "src":"https://www.mappingmegan.com/wp-content/uploads/2017/04/sunset-2177324_1920-001.jpg"}
];
imgIndex = 0;
function changeImg(){
document.getElementById("slideshow").src = images[imgIndex].src;
if(images.length > imgIndex+1){
imgIndex++;
} else {
imgIndex = 0;
}
}
changeImg();
setInterval(changeImg, 2000)
<img id="slideshow" src=""/>
I think you have a problem with the counter fn. Please try this; it starts from 0, ends on images.length - 1 and then restarts to 0:
var add = (function(len) {
var counter = 0;
return function() {
if(counter === len) {
counter = 0;
}
return counter++;
}
})(images.length); // It's not required, but I also recommend you passing images.length as a parameter
Also, if you want to stop the interval, you just have to do something like this:
// Now myInterval is a numbered ID
var myInterval = setInterval(myFn, myTime);
// Something happens here and then..
// Your interval is stopped
clearInterval(myInterval);

Javascript Click Event Pushing Multiple Duplicates to Array

In recreating the Simon game, I am trying to push a click event to an array and then immediately test that Array in a nested function. On the first pass it seems to work.
However, on the third run the array does not seem to clear.
The screen shot below also shows that each input is printed multiple times to the console.
Full code pen here - https://codepen.io/jhc1982/pen/NwQZRw?editors=1010
Quick example:
function userMoves() {
var userInput = [];
document.getElementById("red").addEventListener("click", function(){
userInput.push("red");
testington();
});
$(".red").mousedown(function(event){
redAudio.play();
$(".red").css("background-color", "red");
});
$(".red").mouseup(function(){
$(".red").css("background-color", "#990000");
});
function testington(){
if (userInput.length == pattern.length) {
for (var i = 0; i < userInput.length; i++) {
if (userInput[i] !== pattern[i]) {
alert("Game Over");
} else if (i === userInput.length -1 && userInput[i] === pattern[i]) {
userInput = emptyArr;
simonMoves();
console.log("user input is ",userInput);
} else {
continue;
}
}
}
}
}
I am sure it is something really obvious but have been stuck for hours.
I think the problem may be that you are assigning the click events every time the userMoves execute. That means every time the function is called the event is added to the elements, so after two calls to userMoves() when you click on red the event is executed twice, after three calls it is executed three times, etc.
The code that adds the event listener should be out of the userMoves function. The testington function should also be out of userMoves, which would get much simpler:
function userMoves() {
$("#score-text").text(level);
userInput = [];
}
Here's a Pen with working code: https://codepen.io/anon/pen/ppzqyY
You need to add the break; keyword to after alert("Game over");
function testington(){
if (userInput.length == pattern.length) {
for (var i = 0; i < userInput.length; i++) {
if (userInput[i] !== pattern[i]) {
alert("Game Over");
break; // Break the loop
} else if (i === userInput.length -1 && userInput[i] === pattern[i]) {
userInput = emptyArr;
simonMoves();
console.log("user input is ",userInput);
} else {
continue;
}
}
}
}

How to wait until an animation is completed before re-calling a function

I'm using recursion to repeat a function multiple times. Each time the function is run, an animation lasting 600 milliseconds will occur, so I'm trying to use setTimeout to delay re-calling the function so that it won't be re-called until the animation has completed. For some reason what I have is resulting in some weird stuff: Using my inspector I can see that the function is running and all the appropriate values are changing, but the new values never get rendered.
If anyone has any other suggestions for how to wait until an animation is completed before repeating the function, that would also do! Thanks in advance!
var run_program = function() {
for (var j=0; j< program.length; j++) { //loops through the different lines of turingcode
if (reader.state === program[j].state && reader.scanning === program[j].scanning) { //if there is a line of turingcode for the readers current state and scanning values.
cellArray[reader.location].content = program[j].print; //change the content of the current cell to the new value
reader.location += 1; //increase the value of the reader's location
$(".reader").animate({"left":"+=50px"}, 600); //move the div to the right so it appears to be under the next cell
reader.scanning = cellArray[reader.location].content; //update the readers scanning value to be the value of the new cell
reader.state = program[j].next_state; // update the state of the reader to that specified by the line of turingcode
break;
}
else if (j === $scope.program.length-1) { //if there is no line of turingcode for the readers current state and scanning values, and j has looped through the entire list of turingcode lines
return; //halt the function
}
}
setTimeout(run_program, 600);
}
You should use the function callback offered by jQuery's .animate() http://api.jquery.com/animate/
var run_program = function() {
$( ".reader" ).animate({
left: "+=50"
}, 600, function() {
// Do something after the Animation is complete.
});
}
Another method would be to get rid of the for loop all together, and in your recursive call just increment the index.
var run_program = function(var index) {
if(typeof index === "undefined") {
//this means it is the first time the function is being run (ie run_program())
index = 0;
}
if (index < program.length) {
//haven't reached the bounds of the initial for loop
//run your other function checks
$('.reader').animate({
left: "+=50"
}, 600, function() {
run_program(index+1);
});
}
}

Repeating a for loop by re-setting variable to 0

Why won't the below make the var i = 0 again and re-run through the loop?
for (var i = 0; i < menuitems.length; i++){
if (i == menuitems.length){
i = 0;
};
$(menuitems[i]).delay(3000*i).queue(function() {
$(this).trigger('click');
});
};
Because "i" will never be == to menuitems.length (in the body of the loop; it will be after the loop, of course). Your loop terminates as soon as "i" is not less than menuitems.length.
Because when i becomes menuitems.length, the for loop condition (i < menuitems.length) becomes false, so the loop stops.
Try this instead:
if (i == menuitems.length - 1){
But then, you'll need some way to make the loop stop; otherwise it will just keep going and freeze your browser.
This cannot work, because JavaScript code is not interruptible. Events like timer expirations will not be executed while you're inside the loop, so nobody from the outside will set an exit condition for you.
for (var i = 0;;i++)
{
i %= menuitems.length; // loops i when it exceeds list length
// the expiration of these delays will not interrupt the loop
$(menuitems[i]).delay(3000*i).queue(function() {
$(this).trigger('click');
});
// if you don't compute a break condition from within the loop, you're toast
if (some_break_condition) break;
}
Now if you want a scroller, the way to go is something like:
var timer;
var period = 1000; // milliseconds
function startScroll ()
{
stopScroll();
timer = window.setInterval(
move_something_around (), // do you scroll here
period);
}
function stopScroll ()
{
if (timer)
{
window.clearInterval(timer);
timer = null;
}
}
// html
<button type="button" onclick="startScroll()">Start</button>
<button type="button" onclick="stopScroll()" >Stop </button>
I ended up getting around this issue using the below code:
$('#scroll').click(function(){
setInterval(function(){
var u = 0;
document.getElementById('maps').setAttribute('src',myUrlArray[u]);
if(u < myUrlArray.length){
++u;
}else{
u = 0;
}
},3000);
});
My question ended up being very similar to this one:
JavaScript: Change iFrame src from Array

simplifying a multi-function in javascript

Hey I'm trying to figure out a way I might be able to simplify my code so that I will not have to have 38 of these functions but only have one that can run 38 different id's at separate times. This is a randomized script that tells the id element to land on a specific letter.
var randlet = 0;
var timesrun = 0;
function randomizer() {
randlet = Math.floor(Math.random() * 26);
timesrun += 1;
if (master[randlet] == letter[0]) {
$('#L1').css('background-position', master[randlet]);
clearInterval(interval);
} else {
if (timesrun == 100) {
master[randlet] = letter[0];
$('#L1').css('background-position', master[randlet]);
clearInterval(interval);
} else {
$('#L1').css('background-position', master[randlet]);
}
}
}
var interval = setInterval(function() {
randomizer();
}, 10);
For each element, set a class called 'randomise'. In the function, use the jquery .each method to iterate over each randomised element. If that element needs to have its value fixed, simp,y remove the 'randomise' class. When no more elements have the randomise class anymore, clear the timer.

Categories

Resources