2

I have searched the forum thoroughly for a solution to this with no luck. Hoping someone can help me here.

I have an empty div with no background image. When a user clicks on it, I have a function that sets the background image like this:

function myAnimation(element) {

    var images = ["url(images/pig.png)", "url(images/cat.png)", "url(images/frog.png)", "url(images/dog.png)"];

    var random = Math.floor(Math.random() * 4);

    element.style.backgroundImage = images[random];
}

Although this works, the problem I'm having is finding the solution to when the user clicks on the image again. As there is only four possible numbers generated, I keep getting a repeating number from the var random method. I think I need a way to check the last number generated and if it's the same, it should try and generate a different number. This way there will be no repeating images. Hope this makes sense. Just so you know, I'm new to programming and only learning Javascript for the last 3 months. I think I may need a loop or another function inside this function, not sure.

Simon Revill
  • 117
  • 1
  • 13
  • 2
    Possible duplicate of [Generating non-repeating random numbers in JS](https://stackoverflow.com/questions/18806210/generating-non-repeating-random-numbers-in-js) – ASDFGerte Mar 29 '18 at 18:42
  • I think you are looking to shuffle the array. See: https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array – JonSG Mar 29 '18 at 19:06
  • I will look into shuffling the array, this makes sense. Thanks for the suggestion. – Simon Revill Mar 29 '18 at 19:24
  • @Sphinx I understand the Math.random function but just to clarify, so you mean I should create a new function getRandomInt(images.length) with images.length being the argument? – Simon Revill Mar 29 '18 at 19:29

4 Answers4

1

I am checking prevNo with generated random number. If both are same, then call the function again. Else assign the random number to prevNo and load the image.

var prevNo = -1;
function myAnimation(element) {
    var images = ["url(images/pig.png)", "url(images/cat.png)", "url(images/frog.png)", "url(images/dog.png)"];

    var random = Math.floor(Math.random() * 4);
    if( random == prevNo) { 
        myAnimation(element);
        return;
    } else {
        prevNo = random;
    }
    element.style.backgroundImage = images[random];
}
abbas-ak
  • 642
  • 3
  • 13
  • This is EXACTLY the solution I was looking for, thank you. I was trying something like this but I couldn't get it to work. I understand your code completely, however, can you please explain how the `return` works in the if/else statement? – Simon Revill Mar 29 '18 at 19:23
1

You can filter your images, considering all items except the current background element, and take a random element of the result.

This is a example of how you can accomplish this:

function myAnimation(element) {

    var currentBackgroundImage = element.style.backgroundImage;

    var images = [
      "url(https://place-hold.it/100x100&text=1)",
      "url(https://place-hold.it/100x100&text=2)",
      "url(https://place-hold.it/100x100&text=3)",
      "url(https://place-hold.it/100x100&text=4)",
    ];

    var restOfImages = images.filter(function (image) {
      return image !== currentBackgroundImage;
    })

    var random = Math.floor(Math.random() * restOfImages.length);

    element.style.backgroundImage = restOfImages[random];
}

Another way, without filter:

function myAnimation(element) {

    var currentBackgroundImage = element.style.backgroundImage;

    var images = [
      "url(https://place-hold.it/100x100&text=1)",
      "url(https://place-hold.it/100x100&text=2)",
      "url(https://place-hold.it/100x100&text=3)",
      "url(https://place-hold.it/100x100&text=4)",
    ];

    var restOfImages = [];

    for(var i = 0; i < images.length; i++) {
      if (images[i] !== currentBackgroundImage) {
        restOfImages.push(images[i]);
      }
    }

    var random = Math.floor(Math.random() * restOfImages.length);
    element.style.backgroundImage = restOfImages[random];
}

And here is a working snipplet:

function myAnimation(element) {

    var currentBackgroundImage = element.style.backgroundImage;

    var images = [
      "url(https://place-hold.it/100x100&text=1)",
      "url(https://place-hold.it/100x100&text=2)",
      "url(https://place-hold.it/100x100&text=3)",
      "url(https://place-hold.it/100x100&text=4)",
    ];
    
    var restOfImages = images.filter(function (image) {
      return image !== currentBackgroundImage;
    })

    var random = Math.floor(Math.random() * restOfImages.length);

    element.style.backgroundImage = restOfImages[random];
}

var el = document.getElementById('container');

el.onclick= function() { myAnimation(el); };
#container{
  width: 100px;
  height: 100px;
  background-color: red;
}
<div id="container"></div>
muZk
  • 2,908
  • 1
  • 21
  • 22
  • Okay!! Just in case, I added another alternative without using `filter` (it uses a `for`). `filter` is a bit more advanced stuff in JS – muZk Mar 29 '18 at 19:46
0

You can repeatedly use Array.splice to remove a random element.

var images = [...
var random = Math.floor(Math.random() * 4);

element.style.backgroundImage = images.splice(random, 1)[0];
Meghan
  • 1,215
  • 11
  • 17
0

I'm using the same function across the entire site so I'm using local storage with a window onload call to headerPic():

  const originalArr = ["image1.jpg", "image2.jpg", etc...];

  function headerPic() {
let headerImgArray = localStorage.getItem("headerList") ? JSON.parse(localStorage.getItem("headerList")) : originalArr;
if (headerImgArray.length < 1) {
    headerImgArray = originalArr;
}
const randomName = headerImgArray[Math.floor(Math.random() * headerImgArray.length)];
document.getElementById("headerImg").src = `imagesHeader/${randomName}`;
headerImgArray.splice(headerImgArray.indexOf(randomName), 1);
if (headerImgArray.length < 1) {
    headerImgArray = originalArr;
}
localStorage.setItem("headerList", JSON.stringify(headerImgArray));

}

Hogan
  • 149
  • 1
  • 2
  • 6