Select a random index and modify it until all unique options have been exhausted, then restart the process

My image gallery has 6 slots for images, and I have an array with a certain number of image objects:

          "src" : {
            "1x" : "/clients/Logo-1.png",
            "2x" : "/clients/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="75391a121a584435470d5b051b12">[email protected]</a>",
            "3x" : "/clients/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="98ecd4f7fff7b5a9d8abe0b6e8f6ff">[email protected]</a>"
          },
          "alt" : "xyz"
        } 

I aim to display 6 random images from the array initially. Every 5 seconds, one slot should randomly change to show a new unique image that was not in the initial set of 6 images. This process should continue indefinitely.

This is what I have attempted so far:

           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);

The function randomNoRepeats is defined as follows:

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;
        };

The shuffleArray function used 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; 
      },

The this.ImageToShowList variable is utilized in the HTML section for display purposes. Any suggestions or improvements on the logic are welcomed.

Answer №1

https://i.sstatic.net/kzUP7.png

To illustrate the concept, you can view my example fiddle here. However, let's break it down:

Your data structure could resemble the following:

let galleryPool = [
    {
        "src" : {
            "1x" : "/clients/Logo-1.png",
            "2x" : "/clients/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="470b2820286a7607753f69372920">[email protected]</a>",
            "3x" : "/clients/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6511290a020a485425561d4b150b02">[email protected]</a>"
        },
        "alt" : "xyz",
        "color": "red"
    },
    ...
]

(I included a color property for illustration purposes since there are no actual images.)

The initial step is implementing the Fisher–Yates shuffle, as it effectively retrieves a random element from 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;
}

Firstly, I set up the gallery and establish a 5-second timeout to rotate images within 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 generates an img DOM element that can be added to the container. The code references your src, but modifications can be made to change how the gallery's images appear.

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

Subsequently, this function triggers every 5 seconds, selecting a random item from the gallery to exchange with another unseen item.

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

The magic happens here. A randomly chosen item from the displayed gallery is replaced with a new item from the available gallery pool, returning the previous item to the pool while adding the new one in its place.

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 full iteration through the array is preferred, keep track of when the galleryPool array is empty. Upon depletion, refill the array and run the initialization function again. Otherwise, the process will continue indefinitely.

Answer №2

Below is a straightforward script that requires the following components:

  • pool: This contains all the possible values you desire.
  • A single function to update the show array.

Test it out here

I've included as many comments as possible for clarity.

// Pool with all possible images (you can 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 array will store 6 unique elements to be displayed
let show = [];
while(show.length < 6){
    let pooled = pool.sort(() => 0.5 - Math.random())[0];
    if(!show.includes(pooled)){
        show.push(pooled);
    }
}

function after5Mins(){
    let newPoolItem = pool.sort(() => 0.5 - Math.random())[0];
    while(show.includes(newPoolItem)){
        newPoolItem = pool.sort(() => 0.5 - Math.random())[0];
    }  
    show[Math.floor(Math.random()*show.length)] = newPoolItem;
}

setTimeout(()=>{
    after5Mins();
}, 300000);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps should I follow to ensure that the processData function waits for the data returned by the getData function in Angular?

After calling the getData function, each object is stored in an array and returned. Now I need the processData function to await these results from getData and then further process them. However, when I try to console.log(cleaningData), I don't see an ...

Other Components take turns submitting the form in one Component

Two components, CreateCandidate and Technologies are being used. CreateCandidate requires technologies from the Technologies Component. When passing the technologies to CreateCandidate, the form within CreateCandidate is submitted. Below is the code: Crea ...

Guide to transferring a zip file from a server to a client in nodejs

After creating a zip file on the server side, I am trying to figure out how to transfer it to the client side in order to enable downloading using the saveAs() function and placing it within a new Blob() function. Any suggestions on how to accomplish this? ...

Tips on converting HTML code into a data image URI

My question may seem unconventional, but here is what I am trying to accomplish. I want to create a design similar to the one found at the following link: I would like to embed text with an image and retrieve the data image URL using Ajax. I know how to g ...

The dropdown menu is not appearing in the correct position when clicked

https://i.stack.imgur.com/fMyZQ.jpg Hello there, this link appears normal before clicking on it. But once clicked, it moves to the top of the page like so: https://i.stack.imgur.com/yZ0R0.jpg You can clearly see the difference. I have also provided the c ...

Selecting from a variety of options presented as an array of objects

I am currently working on a component that allows users to select roles: https://i.stack.imgur.com/bnb9Y.png export const MultipleSelectChip = ({ options, label, error, onRolesUpdate, }: Props) => { const theme = useTheme(); const [selected ...

"Implementing a dynamic loading effect in Highcharts triggered by a button

Take a look at this sample highchart fiddle: http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/highcharts/members/series-setdata/ $('#button').click(function () { var chart = $('#containe ...

Simulate a keyboard key being pressed and held for 5 seconds upon loading the page

Is it possible to create a script that automatically triggers an event to press and hold down the Space key for 5 seconds upon page load, without any user interaction? After the 5 seconds, the key should be released. It is important to emphasize that abso ...

Accessing the element within an ion-tab using document.getElementById

Within my ion-view, I have ion-tabs containing a canvas element. However, when attempting to retrieve the canvas using document.getElementById('photoCanvas'); I receive 'undefined'. Here is the code snippet: HTML: <ion-view ...

The express application's GET route is causing a "Cannot GET" error to be thrown

I am managing different types of pages: the main root page (/) today's chapter page (/929 OR /929/) which eventually redirects to /929/<CHAPTER> where <CHAPTER> is a natural number between 1 to 929 individual chapter pages (/929/<CHAP ...

What are the steps for running app.js deployed on a remote server using the local bash terminal?

After launching my web application on GoDaddy, which is built in Node.js, I have encountered a dilemma. In order to run app.js, I currently rely on my computer's bash command prompt. However, this poses an issue - if I were to shut down my laptop, the ...

Can you distinguish between these two plunkers - one using AngularJS and the other using Angular-UI?

I'm currently facing a challenge while trying to incorporate the ui-bootstrap project into my own project. Despite having successfully used ui-bootstrap before, I seem to be making mistakes this time around. The Plunkers linked below showcase the issu ...

Issue with Angular filter not being effective within ng-repeat

For all code regarding this issue, please visit: Filter: <input type="text" ng-model="search"> <tr ng-repeat="(id, group) in groups | filter:search" class="editing-{{group.editing}}"> The goal is to have the rows filtered out based on the in ...

Assist in troubleshooting and pinpointing the solution to this issue

function generateRandomString(length) { var result = ""; var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters ...

Adjust the size of the image to fit within the div container following

<div id="homePage" style="position: relative; margin: 0px; width: 320px; height: 420px;"> <img id="userImg" src="images/5.jpg" width="100%" height="100%" onclick="imageClick()" style=" z-index: -1; margin: 0 ...

Encountering issues in transmitting form data to a Node server from Angular

In my Angular application, I am working on creating a registration page with validation. Once the user fills out the form and submits it, the data is sent to the server and saved in MongoDB. This is the approach I have taken: register_user() { const ...

Encountering issues retrieving data using Vuex in combination with axios

I have undertaken the task of creating 2 projects - one for the backend and one for the frontend using a combination of Laravel and VueJS. In Laravel, I have set up an API endpoint to cater to all users: Laravel routes/api.php Route::prefix('users&ap ...

What is the best way to transform an Object {} into an Array [] of objects with varying structures?

Within my javascript code, I am working with an object structure like this: let obj= { a: { a1: [5,5], a2: [6,6] }, b: { a1: [7,7], a2: [8,8] }, c: { a1: [9,9], a2: [3,3] } } The goal is to ...

React Error: "SharedArrayBuffer is not defined" Firefox encountered a problem

I am encountering an issue with my React app that was created using 'create-react-app' along with the jsdom NPM package. Strangely, the application is throwing an error upon loading exclusively in Firefox, as it works perfectly fine in Chrome and ...

Utilizing a feature module imported from a separate Angular4 project

I have a question about setting up an Angular 4 project. Can feature modules be loaded from another Angular 4 project? I am currently attempting to maintain separate project repositories and dynamically load feature modules into the main project. This wa ...