Loop to check last image in array - javascript

Thanks to a kind member I found a solution to a code problem of mine!
But I'm having struggle again with a loop.. I tried to find the solution in answered questions but nothing was working for me..
I want a loop to check if the last image in an array is loaded. I'm making a simple game where you click on a image, and it changes to the next image. The goal is that you have to click multiple times on the image, to get to the last image. If you are at the last image, you win. There needs to be a timer that checks after let's say 5 seconds, if you are at the last image. (I have multiple images that you have to click on, bet I'm showing just one right now)
So I made a for loop like this:
for (eiImg == 'img/ei4.png'){
alert("yay!");
}
It's probably very very wrong but I'm a very amateur programmer so I'm sorry! ;)
Well of course it wasn't working. And I am not even using a timer..
Can someone teach me how to successfully make a loop that checks after 5 seconds if the Image is the last image in the array. I've tried to google it but I just can't find the solution.
Here is my entire javascript code:
var eieren = 0;
var eieren = Math.floor((Math.random() * 4) + 1);
var imgArray = [ 'img/ei1.png' , 'img/ei2.png' , 'img/ei3.png', 'img/ei4.png' ];
imgArray.length;
var eiImg = imgArray[eieren - 1];
console.log( eiImg );
// thanks so much for the help Azzy Elvul!
document.getElementsByTagName( 'img' )[0].src = eiImg;
document.getElementsByTagName( 'img' )[0].addEventListener( "click", changeImage ());
var counter = eieren - 1;
function changeImage()
{
//Load new image if this is not the last image
if ( counter < imgArray.length - 1 )
{
document.getElementsByTagName( 'img' )[0].src = imgArray[ ++counter % imgArray.length];
}
};

Check this, its create alert of the last object from the array
var imgArray = [ 'img/ei1.png' , 'img/ei2.png' , 'img/ei3.png', 'img/ei4.png' ];
var alertIndex = imgArray.length-1; // the last index from the array
for(var i = 0; i<imgArray.length; i++) {
if(i == alertIndex) {
alert(imgArray[i]);
}
}
JSFiddle - look at this working example.

OK, so I was curious about this and about the solution you were working on and so I had a go at it myself just to see if I could get it to work. I think my solution is slightly different from your approach. The annotated code is below and there's a JSFiddle demonstration of the code at the end.
var imgArray = ['img/ei1.png', 'img/ei2.png', 'img/ei3.png', 'img/ei4.png'];
// get the body element and create an array to keep the image elements
var body = document.querySelector('body');
var imgs = [];
// loop over the list of images, creating new elements
// adding src attributes and click events to them, and then adding
// them to the imgs array we created
for (var i = 0, l = imgArray.length; i < l; i++) {
var img = document.createElement('img');
img.src = imgArray[i];
img.addEventListener('click', changeImage);
imgs.push(img);
}
function changeImage() {
// are there any image elements left in the img array
// if there are, continue
if (imgs.length > 0) {
// is the length of the img array less than the length
// of the imgArray - if so, remove the previous image from the page
if (imgArray.length !== imgs.length) {
body.removeChild(document.querySelector('img'));
}
// random number based on the number of image elements
// remaining in the imgs array
var random = Math.floor((Math.random() * imgs.length - 1) + 1);
// add that image to the body element
body.appendChild(imgs[random]);
// remove the image element from the imgs array
imgs.splice(random, 1);
}
}
function checkOnLastImage() {
// are you on the last image?
if (imgs.length === 0) {
console.log('congratulations')
} else {
console.log('try again');
}
}
// run changeImage for the first time
changeImage();
// use a setTimeout to check at 5 seconds whether
// the last image has been reached
setTimeout(checkOnLastImage, 5000);
DEMO

Why to iterate? Get the last object directly.
alert(arr[arr.length-1])

Related

Why first image in Array doesn't loop the first time around?

I am making a simple animation using javascript. Of course I could use the CSS keyframes, but that would not work for what I need this for, so no CSS solution please. I threw in a status div just so you see what I mean without actually having to see the images. JSfiddle below.
Anyway here is the HTML.
<div id="zero-walking"><img src="#" id="zeroImage"></div>
<div id="statusDiv"></div>
Here is the javascript
var index = 0;
var zero = document.getElementById("zeroImage");
var zeroArray = ["images/1.png", "images/2.png", "images/3.png", "images/4.png", "images/5.png", "images/6.png", "images/7.png", "images/8.png", "images/9.png", "images/10.png", "images/11.png"];
zeroAnimate();
function zeroAnimate() {
zero.setAttribute('src', zeroArray[index]);
index += 1;
if (index == zeroArray.length) {
index = 0;
}
var statusDiv = document.getElementById('statusDiv');
statusDiv.innerHTML = zeroArray[index];
}
setInterval(zeroAnimate, 700);
http://jsfiddle.net/r9zfg3jp/
This block:
index += 1;
if (index == zeroArray.length) {
index = 0;
}
Should be at the very end of the function.
Your problem is index += 1 is happening before you ever do statusDiv.innerHTML = zeroArray[index]; so it's 1 (not 0) the first time you get there...
Try moving the index assignment operator to the end of your method here. As it is, you are FIRST increment the index, then doing work, meaning you are skipping the 0 frame...
Sometimes I ask myself why I help. If you just want to loop over those images it's like:
function loopImages(elem, imgs, interval, loop){
var i = 0, loopy = setInterval(function(){
elem.src = imgs[i++];
if(i === imgs.length){
loop ? i = 0 : clearInterval(loopy);
}
}, interval);
}
loopImages(document.getElementById('zeroImage'), zeroArray, 700, true); // loops forever

Javascript Image slideshow doesn't work

I'm trying to get one image from this array to display every two seconds using Javascript, but I can't seem to get it to work. The id is correct and the image locations are correct and all spelt right. Not sure what's going wrong, any help would be greatly appreciated! Thanks in advance!
var images = new Array();
images[0] = "images/slideshowimage1.jpg";
images[1] = "images/slideshowimage2.jpg";
images[2] = "images/slideshowimage3.jpg";
images[3] = "images/slideshowimage4.jpg";
var counter = 0;
function ChangePic()
{
counter++;
document.getElementById('carpic').src = images[counter];
if(counter == images.length)
{
counter = 0;
}
setTimeout("ChangePic()",2000)
}
Well, first off you need to wrap the call in the setTimeout in a function, not a string.
Second, the counter never reaches the value 0 because you increase it's value by 1 from the start. You want to do something like this:
var images = new Array();
images[0] = "images/slideshowimage1.jpg";
images[1] = "images/slideshowimage2.jpg";
images[2] = "images/slideshowimage3.jpg";
images[3] = "images/slideshowimage4.jpg";
var counter = 0;
function ChangePic()
{
document.getElementById('carpic').src = images[counter];
// a more efficient if/else statement can be written like this:
// don't forget that the array starts with 0, so you need array length -1
(counter == images.length-1) ? counter = 0 : counter++;
}
// need to move this out of the ChangePic function
setTimeout(function() {ChangePic()}, 2000);
You should remove the double quotes and braces in the setTimeout function.
It should be:
setTimeout(ChangePic, 2000);
Hm, I think there are a couple of problems here. First is a syntax error, then a logic error.
The syntax error is your argument for setTimeout. It should be setTimeout(ChangePic, 2000), rather than setTimeout("ChangePic()", 2000).
The logic error is in the position of your increment, counter++ - in its present position, the values that will end up being used as an index for the array images[] will be 1, 2, and 3. Index 0 (the first item in images[]) will never be used, since counter always gets incremented before it is used as an index (making it impossible for it to be 0 when it is used). What you'll want to do is move counter++ after you use it as an index for images[].
Adjusting your code as little as possible, here's what it might look like:
var images = new Array();
images[0] = "images/slideshowimage1.jpg";
images[1] = "images/slideshowimage2.jpg";
images[2] = "images/slideshowimage3.jpg";
images[3] = "images/slideshowimage4.jpg";
var counter = 0;
function ChangePic() {
document.getElementById('carpic').src = images[counter];
counter++;
if (counter == images.length) {
counter = 0;
}
setTimeout(ChangePic, 2000)
}
// Call function at end to begin slideshow cycle
ChangePic();
Here's a JSFiddle to show you what this does. (Open your browser's debug console to view the output.) Hope this is what you were looking for! If not, let me know and I'll be happy to help further.

Using shift() and push() to loop array values vs. using a counter variable, what is the best approach?

I'm looping through a set of images within an array of animation frames. There are 7 images, and looping from 1-7 completes the animation. I need this animation to loop indefinitely, but I was wondering which of these is the best approach:
Loop by modifying array
/* Pull image from start of array. */
var image = frames.shift();
/* Process image. */
...
/* Add image back to end of array. */
frames.push(image );
Loop using counter variable
/* Pull image by counter offset. */
var image = frames[counter];
/* Process image. */
...
/* Increment or reset counter value. */
counter + 1 === frames.length ? counter = 0 : counter = counter + 1;
Is there a reason I'd chose one over the other? Alternatively, is there a better approach to this?
Modifying the array is going to be more expensive than simply using a variable to keep track of your position in the array. The better way to do this, if you're looping indefinitely, seems to just be to use a while loop (rather than using a for loop where you reset the counter inside):
var i = 0;
while (true) {
doSomething to array[i];
i = (i+1) % array.length;
}
However if your goal really is having an animation proceed indefinitely every time a given interval elapses, a loop isn't ideal at all. Use setInterval instead.
var frames = ...; //your images
var i = 0;
function animate() {
do something to frames[i];
i = (i+1) % array.length;
}
setInterval(animate, time_between_runs);
where time_between_runs is how much time should elapse before the function is called again.
Alternatively a circular linked list also can be used I think. To turn an array of objects into a circular linked list:
frames.forEach(function(elem, index) {
elem.next = frames[index + 1] || frames[0];
});
And now you can do something like this:
setInterval(function() {
frame = frame.next;
....
}, delay);
One possibility is to ditch the array and use a linked list.
Make each frame an object that points to the next object. The last one then points to the first. Then all you need to do is reference the next object.
var curr = first; // reference to first frame object
setInterval(function() {
// process image
curr.image.doSomething();
// proceed to next
curr = curr.next;
}, 1000);
No counters to mess with this way.
Setting up the linked list is usually pretty simple, and can likely be done with just a little modification to the current code that's setting up the Array.
var first = new Frame(); // This is your entry point
var current = first; // This holds the current frame during setup
for (var i = 0; i < totalFrames; i++) {
current.next = new Frame(); // Make the current reference a new frame
current = current.next; // Make the new frame current
}
current.next = first; // circular reference back to the first.
function Frame() {
// set up this frame
}
Then first is your starting point.
Or the linking could be done within the Frame constructor.
var first = new Frame(null);
var current = first;
for (var i = 0; i < totalFrames; i++) {
current = new Frame(current);
}
current.next = first;
function Frame(currFrame) {
// link this frame to the given one
if (currFrame)
currFrame.next = this;
// set up the rest of this frame
}

Adding increased count to the DOM for every pass

what I'm hoping to achieve is to increase a count and then append that to the DOM on every pass through using each(). What I have at the moment is the final count added at the end. For example.
Say I have 100 divs, for every pass through it should add the new count as it counts it, like so 1,2,3,4,5,6,7... and so on. But at the moment it counts all the objects and just appends 100 at the end. Please can someone point me in the direction to where I'm going wrong?
I've added a very basic version of what I'm hoping to achieve below... also here is a JSbin (I tried jsfiddle but it seems to be down for me) .
$(".toCount").each(function(i){
$("#count").text(i + 1);
});
$('input').on('click',function () {
var len = $(".toCount").length;
var arr = [];
for (var i = 0; i < len; i++ ) {
arr.push(i+1);
}
$('#count').text(arr.join());
});
I don't know what you mean by 1, 2, 3 ... in case that you want to count the elements step by step you can use setInterval function:
$('input').on('click',function () {
var l = $(".toCount").length,
$c = $('#count'),
i = 0;
var t = setInterval(function() {
i++;
$c.text(i);
if (i === l) clearInterval(t);
}, 10);
});
http://jsbin.com/eronel/17/edit
use append();
Insert content, specified by the parameter, to the end of each element in the set of matched elements.
in your case text() is replacing your div's text so u get 100 at the end ..
$("#count").append(i + 1);
Use append
$("#count").append(i + 1);

Displaying a Random div on Click

I am using the Colorbox Lightbox script to call a hidden div on a page. It works great but there is a catch. I have 15 hidden divs. When a link is clicked I would like a new lightbox to show each time without repeating until all have been shown. I do not know how to do this.
Here is my code to call the lightbox:
$(".colorbox").colorbox({
inline:true
});
Here is the HTML of the hidden divs
<div class="hide">
<div id="lightbox1">
<!-- Content -->
</div>
<div id="lightbox2">
<!-- Content -->
</div>
<!-- etc -->
</div>
How would I call each div at random until all have been shown then start over?
Also is there a way that once divs 1 - 15 have been shown to then show one last div (id="last-div") before restarting?
Note: All divs would be called on a click and I am using jQuery 1.8.2.
I do not know where to start, I have seen scripts using Math.random() but I do not understand enough to make that work.
UPDATE
I have tried Ian's answer but the lightbox is not showing (but I can see in the console log that the script is working)
Originally he has this in his script:
$(selector).show();
which I changed to this:
$(selector).colorbox({inline:true });
What do I need to do to call the lightbox?
Note: No errors are thrown.
So my idea was similar to Eric's, but I wanted to make it work "completely". So instead of storing references to all the divs in an array, I just decided to store an array of ints representing each div. The way I eventually select them with jQuery is "#lightbox + i", so if you don't have this exact structure (where the divs have an id like "lightbox" and an int - from 1 to the last count), then you can use .eq() or nth-child. It won't be the exact same results, but it will have the same random effect, just done in a different way. I found a function that "randomizes" an array - I'm guessing like what Eric's Shuffle does. But here's where I got it from - How to randomize (shuffle) a JavaScript array? . I had to modify it to return a new array instead of modify the one passed to the function. Also, I kept everything in the document.ready scope, instead of the global scope, so things are passed/returned a lot. It worked fine before when I had all and randomed declared globally and didn't pass them around, I just thought this would be "better" since they weren't global.
Here's the fiddle:
http://jsfiddle.net/6qYCL/1/
And here's the Javascript:
$(document).ready(function () {
var all,
randomed;
all = generateAll();
randomed = generateRandomed(all);
$("#generator").on("click", function (evt) {
evt.preventDefault();
randomed = doNext(all, randomed);
});
});
function generateAll() {
// Generates the array of "all" divs to work on
var a = [];
var divs = $(".hide > div.lightbox");
for (var i = 1; i <= divs.length; i++) {
a.push(i);
}
console.log("List of divs available to toggle: " + a);
return a;
}
function generateRandomed(all) {
// Randomizes the original array
randomed = fisherYates(all);
console.log("Setting randomized array: " + randomed);
return randomed;
}
function doNext(all, randomed) {
$(".lightbox, #last-div").hide();
if (randomed.length < 1) {
console.log("All lightboxes toggled, showing last, then starting over");
$("#last-div").show();
randomed = generateRandomed(all);
} else {
var next = randomed.shift();
var selector = "#lightbox" + next;
console.log("Showing " + selector);
$(selector).show();
console.log("What's left: " + randomed);
}
return randomed;
}
// Randomizes an array and returns the new one (doesn't modify original)
function fisherYates ( myArray ) {
var return_arr = myArray.slice(0);
var i = return_arr.length;
if ( i == 0 ) return false;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = return_arr[i];
var tempj = return_arr[j];
return_arr[i] = tempj;
return_arr[j] = tempi;
}
return return_arr;
}
It accounts for getting to the end of the list and display #new-div like you mentioned, then starting the process over. If you look in your browser's console, you can "watch" what's happening during initialization and when clicking the link.
I think this is close to what you were looking for. I'm not sure which is a better solution - storing references to the elements or just an array of ints to loop through and eventually find. I know there are many variations on how to do this - when/how to store the counting stuff, when/how to randomize the array or retrieve a random value (and how to keep track of which has been used), where to store all references, and plenty more. I hope this at least helps!
Create an array of all of them, then shuffle that array, then pull the next one each time you get a click. When you run out, you can repopulate the array if necessary.
Something like this (using the Shuffle method from this source):
Fiddle
var array = $(".hide div").toArray(); // Add all divs within the hide div to an array
var randomArray = Shuffle(array); // Shuffle the array
$("a").click(function() {
if (randomArray.length > 0)
alert(randomArray.shift().innerHTML); // Show contents of div, as an example
else
alert("None left!");
return false;
});
The solution below works by passing an array of elements to a function. As each div is displayed it is taken out of the array. Then from the divs left in the array the next one is picked at random.
// call this function on page load
function begin( ) {
var arr = $(".hide div").toArray();
// further elements can be added to arr i.e. last-div
showDivs( arr.length, arr );
}
// begin displaying divs
function showDivs( numberOfDivs, divArray ) {
var i, lastDiv;
function nextDiv( ) {
// depending on number of slides left get random number
i = randomInt( numberOfDivs );
if( lastDiv ) { $(lastDiv).hide() };
$( divArray[ i ] ).fadeIn( 3000 );
// now that this div has been displayed
// remove from array and cache
lastDiv = divArray.splice( i, 1 );
numberOfDivs--;
// no more divs to display
if( numberOfDivs == 0 ) { return };
setTimeout( nextDiv, 4000);
}
setTimeout( nextDiv, 1000);
}
// calculate next random index
function randomInt( divsLeft ) {
var i = Math.random() * divsLeft;
return Math.round( i );
}
Fiddle here

Categories

Resources