3

I'm creating a website with HTML, CSS, and JavaScript. I have a picture element on my page, among other elements.

What I want to achieve is to randomnly change the picture every hour. I am able to do this perfectly fine by running it in my browser.

My question is: how does one randomly change an element across the board (the entire internet) for all users?

The way I have it written, it only runs the random pic function within my browser, and resets every time I refresh the page.

I'm currently using setInterval() and checking the time constantly to see if the current date.getMinutes() === 0, then I figure it's a new hour, and i call a changePicHourly() function.

I have no problem getting this to work. However, obviously every visitor to my page will see a different picture. I do not want that. I want consistency across time and space! Haha.

I'm not asking for specific coding instructions, I'm more focused on trying to understand the concept. How does one change elements internet-wide?

Hopefully I am making this clear. Thank you!!

Gass
  • 7,536
  • 3
  • 37
  • 41
MissAri
  • 77
  • 2
  • 7
    You do it on your server so that everyone who loads a page from a particular URL gets the same thing. – isherwood Dec 21 '21 at 17:30
  • 1
    You can use to refresh the page. Or you could connect computers worldwide over websockets and send a refresh command over that. – ControlAltDel Dec 21 '21 at 17:33
  • Well.. The key here is to get a time that will be the same for every user across the world, and then code with this reference in mind.. You can do so by using `getTime()` https://www.w3schools.com/jsref/jsref_gettime.asp – Gass Dec 21 '21 at 17:44
  • @isherwood thank you! so this is achieved using PHP i assume? – MissAri Dec 21 '21 at 18:00
  • I would have no idea what's on your server. Please see [ask]. Your question is quite broad. – isherwood Dec 21 '21 at 18:00
  • @ControlAltDel thank you. can you elaborate on the meta http-equiv command? what exactly is that doing? – MissAri Dec 21 '21 at 18:01
  • 1
    There is more than just PHP as a serverside option, but it IS and option – Jon P Dec 21 '21 at 23:20
  • @JonP thanks! I am very new to coding. I thought that like JS, HTML, CSS are standard on the front end, PHP is the standard on the back end. I will look into serverside languages more. thanks :) – MissAri Dec 22 '21 at 16:53

2 Answers2

4

This would be one way of doing it without a back-end:

Using new Date.getTime() to retrieve the UTC time which is the same for all computers connected to the internet. Then convert this milliseconds to hours and create a pseudo-random number to shift the image every hour.

In the following code I'm using only ten images but the random number is meant to be used for up to 100 images.

const 
  hours = Math.round(new Date().getTime()/(1000*60*60)),
  numbers = [
    Number(hours.toString().slice(0,2)),
    Number(hours.toString().slice(2,4)),
    Number(hours.toString().slice(4,6))
  ],
  images = [
    'https://picsum.photos/id/237/200/300', 
    'https://picsum.photos/id/236/200/300', 
    'https://picsum.photos/id/235/200/300',
    'https://picsum.photos/id/234/200/300',
    'https://picsum.photos/id/233/200/300',
    'https://picsum.photos/id/232/200/300',
    'https://picsum.photos/id/231/200/300',
    'https://picsum.photos/id/230/200/300',
    'https://picsum.photos/id/229/200/300',
    'https://picsum.photos/id/228/200/300'
  ];

function hourlyRand(){
  const pseudoRandString = (numbersArr) => {
    let rand = 1
    numbersArr.forEach((n, i) => {
      if(n !== 0) rand = rand * n 
    })
    return rand.toString()
  }  
  
  // get a pseudo random number and convert to string
  let randString = pseudoRandString(numbers)

  // length of the pseudo random number string
  let L = randString.length

  // slice the string and convert to number
  let n = Number(randString.slice(L-3,L-1))
  
  // return the double digit hourly random number
  return n
}

// pseudo-random number between 0 and 99 
console.log('Hourly pseudo-random number: ' + hourlyRand())

// pseudo-random number between 0 and 9 
let n = Math.round(hourlyRand()/10)

document.getElementById('root').innerHTML = '<img src=' + images[n] + '/>'
<div id="root"/>

If it were my project I would build the logic in the back-end and then use an API in the front-end to render the images in whatever way I wish. This would allow all users to see the same changes occurring at a certain point in time.

Gass
  • 7,536
  • 3
  • 37
  • 41
  • 2
    This will be consistent, but not random (but perhaps the OP is ok with that). – jsejcksn Dec 21 '21 at 20:33
  • 1
    @jsejcksn thanks for pointing that out, I missed it.. I will update accordingly.. – Gass Dec 21 '21 at 20:46
  • What you want is seeded PRNG (e.g. https://github.com/davidbau/seedrandom) using UTC hour as input to derive the array index. – jsejcksn Dec 21 '21 at 20:57
  • 1
    @Gass thank you! So to clarify, if it's pseudo-random, then this approach works, but to truly grab a random picture from an array and have it consistent across the globe, it MUST be done on the back end, is this correct? – MissAri Dec 22 '21 at 16:41
  • From my point of view that would be the best way... – Gass Dec 22 '21 at 19:03
  • 1
    If you create a reproducible pseudo random number from a seed that is essentially the current hourly UTC time stamp - as this code does - then there is no reason why this needs to be done serverside. You will have the same hourly changing image on each client bowser worlwide. – Carsten Massmann Dec 22 '21 at 22:20
2

Here is a slightly different pseudo random number generator based on a seed value calculated from the current UTC hour:

const d = new Date(),
  imgs = [...Array(100)].map((c, i) => 'https://picsum.photos/id/X/200/300'.replace("X", 216 + i));

// define a seed-based random number generator (later: "rand()"), as suggested in
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript
function sfc32(a, b, c, d) {
  return function() {
    var t = (a + b) | 0;
    a = b ^ b >>> 9;
    b = c + (c << 3) | 0;
    c = (c << 21 | c >>> 11);
    d = d + 1 | 0;
    t = t + d | 0;
    c = c + t | 0;
    return (t >>> 0) / 4294967296;
  }
}
// create a seed, based on the current hour in UTC time:
const seed = Math.round(new Date().getTime() / (1000 * 60 * 60));
// initialise the number generator rand() with this seed:
const rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed ^ 0xDEADBEEF);
// carry out some initial "mixing" ... 
for (let n = 15; n--;) rand();
// now rand() will deliver a pseudo-random number that will be reproducible for identical seeds.

let src = `<img src="${imgs[Math.floor(rand()*100)]}">`;
document.getElementById("root").innerHTML = `<img src="${imgs[Math.floor(rand()*imgs.length)]}">`;
<div id="root"></div>

In the expression [...Array(100)] I limited the number of pictures to choose from to 100. You can of course use any number of pictures here.

Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43