Pick random index and change till all unique are done then restart

Viewed 56

I have image gallery with 6 image slot and i have a array with n no of image object like this

          "src" : {
            "1x" : "/clients/Logo-1.png",
            "2x" : "/clients/Logo-1@2x.png",
            "3x" : "/clients/tLogo-1@3x.png"
          },
          "alt" : "xyz"
        } 

what i want is to show random 6 image from array and then every 5 sec randomly one slot need to be change and get update with a new unique image which must not be in first 6 slot and then after finishing all it should continue the 5 sec change with a new unique image which must not be in those 6 slot.

what i have tried

           let randomList = this.shuffleArray(this.LogosListObj);
           let FirstSixImg = randomList.slice(0, 6);
           let LeftAllImg = randomList.slice(6 + 1);
           let RandomIndex = this.randomNoRepeats([0,1,2,3,4,5])
           let RandomSecoundImg = this.randomNoRepeats(Array.apply(null, new Array(LeftAllImg.length)).map(function(el, i) {return i}))
           let RandomFirstImg = this.randomNoRepeats(Array.apply(null, new Array(FirstSixImg.length)).map(function(el, i) {return i}))
           this.ImageToShowList = [...FirstSixImg];
           let checkArr = [];
           let checkArr2 = [];
           let flag = false;
           let index,secndIndex,thirdIndex;
           const LogoChange = (arr) =>{
             if(!flag) {
                secndIndex = RandomSecoundImg();
                  console.log('1st',secndIndex)
                if(checkArr.indexOf(secndIndex) == -1) {
                    index = RandomIndex();
                    checkArr.push(secndIndex)
                    ctl.ImageToShowList[index] =  {};
                    ctl.ImageToShowList[index] = LeftAllImg[secndIndex];
                    Vue.set(ctl.ImageToShowList, index, LeftAllImg[secndIndex])
                    ctl.PreviousImgObj = {...LeftAllImg[secndIndex]};
                } else {
                  flag = true;
                  checkArr = [];
                }
             }
             if(flag) {
                 thirdIndex = RandomFirstImg();
                  console.log('2nd',thirdIndex)
               if(checkArr2.indexOf(thirdIndex) == -1) {
                  checkArr2.push(thirdIndex)
                  ctl.ImageToShowList[thirdIndex] =  {};
                  ctl.ImageToShowList[thirdIndex] = FirstSixImg[thirdIndex];
                  Vue.set(ctl.ImageToShowList, thirdIndex, FirstSixImg[thirdIndex])
                  ctl.PreviousImgObj = {...FirstSixImg[thirdIndex]};
                }else {
                  flag = false;
                  checkArr2 = [];
                  LogoChange();
                }
             }
            
            }
           
           setInterval(()=>{ 
             LogoChange();
          }, 1000);

where randomNoRepeats is

randomNoRepeats : (array) => {
        var copy = array.slice(0);
        return function() {
          if (copy.length < 1) { copy = array.slice(0); }
          var index = Math.floor(Math.random() * copy.length);
          var item = copy[index];
          copy.splice(index, 1);
          return item;
        };

and shuffleArray is

shuffleArray : (array) => {
          for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            const temp = array[i];
            array[i] = array[j];
            array[j] = temp;
          }
          return array; 
      },

this.ImageToShowList is used in html part to display Any help with logic or change will be appreciate.

2 Answers

here is a simple script. you will need the following

  • pool this will contain all possible values you would like
  • single function to update the show array

Test Here

I've tried to put as much comments as possible

// Pool with all possible images (you may use any type of text as long as each value is unique)
const pool = [
    "1.png",
    "2.png",
    "3.png",
    "4.png",
    "5.png",
    "6.png",
    "7.png",
    "8.png",
    "9.png",
    "10.png",
];

// this will store the "6" unique elements which you will be displaying
let show = [];
// get the first 6 random but unique elements. we will monitor the length of the `show` array
while(show.length < 6){
    // randomly sort the pool and get the first element of the sorted array and store it into a `pooled` variable.
    let pooled = pool.sort(() => 0.5 - Math.random())[0];
    // check if the pooled value exists in the `show` array if it doesnt then add it and repeat the loop till all 6 slots are filled with unique values
    if(!show.includes(pooled)){
        // add `pooled` item to the `show` array
        show.push(pooled);
    }
}

// do the same as the above with a slight change, of only replacing one till all are unique.
function after5Mins(){
    // get a new random item from the pool
    let newPoolItem = pool.sort(() => 0.5 - Math.random())[0];
    // using a while loop check if the new `pool item` is in the show array, if not then skip and add it
    while(show.includes(newPoolItem)){
        newPoolItem = pool.sort(() => 0.5 - Math.random())[0]; // set the pool item to a random one, then loop and check, follow previous comment
    }  
    // once a new un used item is found, then assign it to a random position
    show[Math.floor(Math.random()*show.length)] = newPoolItem;
}


// call the after 5 mintes using 
setTimeout(()=>{
    after5Mins();
}, 300000);

fiddle preview

I have my example fiddle here, but this is the breakdown:

Your data would look something like this:

let galleryPool = [
    {
        "src" : {
            "1x" : "/clients/Logo-1.png",
            "2x" : "/clients/Logo-1@2x.png",
            "3x" : "/clients/tLogo-1@3x.png"
        },
        "alt" : "xyz",
        "color": "red"
    },
    ...
]

(I added a color property so you could see the changes since I don't actually have any images.)

The first thing I do is drop in my handy-dandy Fisher–Yates shuffle, since this is a great way to get a random element out of an array.

Array.prototype.shuffle = function() {
    let currentIndex = this.length,  randomIndex;
  while (currentIndex != 0) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;
    [this[currentIndex], this[randomIndex]] = [this[randomIndex], this[currentIndex]];
  }

  return this;
}

I initialize the gallery first, and set up the 5-second timeout to change images in the gallery.

let displayedGallery = []
initialGallerySetup();

function initialGallerySetup() {
    let galleryContainer = document.getElementById("gallery-container")
  galleryPool.shuffle()
  displayedGallery = galleryPool.splice(0, 6)
  for(let index = 0; index < displayedGallery.length; index++) {
    let data = displayedGallery[index]
    galleryContainer.appendChild(generateGalleryItem(data))
  }
  galleryTickUpdate()
}

this function makes an img dom element I can then add to the container. I'm using your src here but you can change whatever values in here to alter how all of the images in the gallery are displayed.

function generateGalleryItem(data) {
  let item = document.createElement("img")
  item.style.backgroundColor = data.color
  item.src = data.src[0]
  item.className = "gallery-item"
  return item
}

This function calls itself every 5 seconds, and will pick a random item from the gallery to swap with another item not currently displayed.

function galleryTickUpdate() {
  setTimeout(() => {
    let randomIndex = Math.floor(displayedGallery.length * Math.random())
    swapItemAtIndex(randomIndex)
    galleryTickUpdate()
  },5000)
}

Here's the magic. I grab the randomly chosen item out of the displayed gallery items, pick a new item from the unused gallery pool items, put the old one back in the pool and the new one gets pushed back into the gallery display in the same spot.

function swapItemAtIndex(index) {
    let galleryContainer = document.getElementById("gallery-container")
    let displaySlot = galleryContainer.children[index]
    let returning = displayedGallery[index]
    galleryPool.shuffle()
    let newDisplay = galleryPool.pop();
    displayedGallery[index] = newDisplay
    galleryPool.push(returning)
    galleryContainer.insertBefore(generateGalleryItem(newDisplay), displaySlot)
    galleryContainer.removeChild(displaySlot)
}

If you want to enforce running through the whole array, just check when the galleryPool array is empty, then repopulate it and re-run the init function. Otherwise, this will happily run forever.

Related