Hello I have tried to find a solution to this and am struggling. I am very new to Javascript! This code works to generate a random image on the button click but the images randomly repeat themselves. I want to show all the images but without repeating images already shown. I understand I should add a for loop and if statement but can't figure out how to write it. These are just a few example images in the array, I will actually have 55 images in the final thing. Can anyone help me!? Thank you! :)
Current code:
const imageArray = [
"https://images.unsplash.com/photo-1508185159346-bb1c5e93ebb4?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=55cf14db6ed80a0410e229368963e9d8&auto=format&fit=crop&w=1900&q=80",
"https://images.unsplash.com/photo-1495480393121-409eb65c7fbe?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=05ea43dbe96aba57d48b792c93752068&auto=format&fit=crop&w=1351&q=80",
"https://images.unsplash.com/photo-1501611724492-c09bebdba1ac?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ebdb0480ffed49bd075fd85c54dd3317&auto=format&fit=crop&w=1491&q=80",
"https://images.unsplash.com/photo-1417106338293-88a3c25ea0be?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=d1565ecb73a2b38784db60c3b68ab3b8&auto=format&fit=crop&w=1352&q=80",
"https://images.unsplash.com/photo-1500520198921-6d4704f98092?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ac4bc726064d0be43ba92476ccae1a75&auto=format&fit=crop&w=1225&q=80",
"https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9a1325446cbf9b56f6ee549623a50696&auto=format&fit=crop&w=1350&q=80"
];
const image = document.querySelector("img");
const button = document.querySelector("button");
window.onload = () => generateRandomPicture(imageArray);
button.addEventListener("click", () => generateRandomPicture(imageArray));
function generateRandomPicture(array){
let randomNum = Math.floor(Math.random() * array.length);
image.setAttribute("src", array[randomNum]);
}
CodePudding user response:
This should clearly explain how to do this using event listeners and the well-known Fisher-Yates shuffle algorithm. If the first item of the shuffled array matches the current image, the shuffle gets repeated (via a do-while loop) to avoid showing the same image twice in a row.
window.addEventListener('DOMContentLoaded', () => {
// Identifies DOM elements and other constants
const
changeButton = document.getElementById("change-button"),
displayDiv = document.getElementById("display-div"),
imageArray = ["image 1", "image 2", "image 3", "image 4", "image 5"],
HIGHEST_INDEX = imageArray.length - 1;
// Calls `changeImage` whenever changeButton is clicked
changeButton.addEventListener("click", changeImage);
// Forces shuffle on first click
let currentIndex = HIGHEST_INDEX;
// Defines listener for click events
function changeImage(){
// If we're at the end of the array, we need to shuffle...
if(currentIndex == HIGHEST_INDEX){
// Remembers the current image
const currentImage = imageArray[currentIndex];
// Keeps calling `shuffle` until next image ≠ current image
do { shuffle(imageArray); }
while (imageArray[0] === currentImage);
// Prepares to start from beginning of shuffled array
currentIndex = -1;
}
//Regardless, increments index and shows corresponding image
displayDiv.textContent = imageArray[ currentIndex];
}
// Implements Fisher-Yates shuffle
function shuffle(arr, randIndex=NaN, temp=null){
// Starts i at the highest index & works backwards through array
let i = arr.length - 1;
while(i-- > 0){
// Gets random index from remaining (unswapped) indexes
rand = Math.floor(Math.random() * (i 1));
// Swaps the value at the random index with the value at i
temp = arr[rand];
arr[rand] = arr[i];
arr[i] = temp;
}
}
});
#display-div {margin-top: 0.5em; }
<button id="change-button">CHANGE IMAGE</button>
<div id="display-div"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
I think this is more like what you were trying to do. (My other answer allowed for cycling through the same list repeatedly and randomizing it each time, but for bingo you don't need all that.)
The populateImgs
function takes a list of urls and loops through all the img elements on the page, setting each src attribute to a different url, or failing if there are too few urls to fill all the imgs. When the function gets called, the urls
argument is built on the fly from a shuffled list of partial urls. (The resulting urls are shorter than your original urls, which included a lot of parameters that I omited for brevity.)
The shuffle
function uses the same algorithm but implemented a bit differently (using the cleaner-looking while(--i > 0){ swap(array, i, randLessThan(i)); }
).
window.addEventListener('DOMContentLoaded', function(){
// Defines an array of strings that identify photos
const photoIds = [
"1508185159346-bb1c5e93ebb4", "1495480393121-409eb65c7fbe",
"1501611724492-c09bebdba1ac", "1417106338293-88a3c25ea0be",
"1500520198921-6d4704f98092", "1504966981333-1ac8809be1ca"
];
// Calls `populateImgs`, w/ a list of randomized urls based on photoIds
populateImgs(
shuffle(photoIds).map(id => `https://images.unsplash.com/photo-${id}`)
);
function populateImgs(urls){
// Shows one photo in each img element
const imgs = document.querySelectorAll("img");
if(urls.length < imgs.length){ return console.log("Not enough photos"); }
let index = -1;
while ( index < imgs.length){
imgs[index].setAttribute("src", urls[index]);
};
}
function shuffle(array){
// Uses helper functions to randomize array, returns randomized array
const
randLessThan = (num) => Math.floor(Math.random() * num),
swap = (arr, i, rand) => { let temp=arr[rand]; arr[rand]=arr[i]; arr[i]=temp; };
// Iterates backwards, swaps each item with a random earlier item, ignores i==0
let i = array.length;
while(--i > 0){ swap(array, i, randLessThan(i)); }
return array;
}
});
img{ width: 100px; height: 80px; object-fit: cover; margin: 15px; }
<div class="row">
<img/><img/>
</div>
<div class="row">
<img/><img/>
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>