2 random images but not the same one - javascript

I have this function that shows two random images picked from a folder. Is there any chance I can modify the code so that I won't have the same image twice as result?
Thanks in advance.
var theImages = new Array()
theImages[0] = 'img/dyptichs/f-1.jpg'
theImages[1] = 'img/dyptichs/f-2.jpg'
theImages[2] = 'img/dyptichs/f-3.jpg'
theImages[3] = 'img/dyptichs/f-4.jpg'
theImages[4] = 'img/dyptichs/f-5.jpg'
var j = 0
var p = theImages.length;
var preBuffer = new Array()
for (i = 0; i < p; i++){
preBuffer[i] = new Image()
preBuffer[i].src = theImages[i]
}
var WI1 = Math.round(Math.random()*(p-1));
var WI2 = Math.round(Math.random()*(p-2));
function showImage1(){
document.write('<img src="'+theImages[WI1]+'">');
}
function showImage2(){
document.write('<img src="'+theImages[WI2]+'">');
}

You can do something like this:
var WI1 = Math.round(Math.random()*(p-1));
var WI2 = Math.round(Math.random()*(p-1));
while (WI2 === WI1) {
WI2 = Math.round(Math.random()*(p-1));
}
We keep generating a new number until it's different from WI1, ensuring it is unique.

The way I'd personally handle that is to randomise the array and then just grab the first 2 entries. That way you still pick 2 at random, but you guarantee not to get the same 2.
var theImages = new Array()
theImages[0] = 'img/dyptichs/f-1.jpg'
theImages[1] = 'img/dyptichs/f-2.jpg'
theImages[2] = 'img/dyptichs/f-3.jpg'
theImages[3] = 'img/dyptichs/f-4.jpg'
theImages[4] = 'img/dyptichs/f-5.jpg'
var randomImages = theImages
.concat()
.sort(function () {
return Math.random() > 0.5
? 1
: -1;
})
.slice(0, 2);
function showImage1() {
document.write('<img src="' + randomImages[0] + '">');
}
function showImage2() {
document.write('<img src="' + randomImages[1] + '">');
}
Edit: including the original array for a complete solution

var WI1 = Math.floor(Math.random()*p);
var WI2 = Math.floor(Math.random()*(p-1));
if (WI2 >= WI1) {
WI2 += 1;
}
Use floor instead of round and subtract 1, because with round you get twice less chance to get first or last element.
The if trick is slightly better than a loop in this case, though the loop is easier to apply to a more complex case.

Related

Display two images every X hours, Javascript

Below is a code I am running to display a pair of images each day. I have been unable to have it display the images randomly, but instead each day it selects the next image in the Array (not at random). Javascript is not my specialty and I have been unsuccessful in making it select a new random image in both arrays each day.
I have also been unsuccessful in making it select them every 12 hours instead of each day, which is what I would prefer it to do. It must display the same ones for every person who views it for that period, until the timer resets, if possible.
<script type="text/javascript"><!--
var imlocation = "https://s31.postimg.org/";
function ImageArray (n) {
this.length = n;
for (var i =1; i <= n; i++) {
this[i] = ' '
}
}
function linkArray (n) {
this.length = n;
for (var i =1; i <= n; i++) {
this[i] = ' '
}
}
image = new ImageArray(4);
image[0] = 'v85buoebv/Day2.png';
image[1] = 'djdl322kr/Evening2.png';
image[2] = 'arubcg423/Night2.png';
image[3] = 'xf9kiljm3/Morning2.png';
link = new linkArray(11);
link[0] = 'q4xda5xdn/CLOUDY.png';
link[1] = '7141ttkjf/Heavyrain.png';
link[2] = 'gzp0gatyz/lightrain.png';
link[3] = 'xc3njrxob/Medium_Rain.png';
link[4] = 'x0m770h8b/NO_WEATHER.png';
link[5] = 's38mlwf97/omgrain.png';
link[6] = 'btigj04l7/Special_Weather.png';
link[7] = 'b59m025vf/WEREALLGONNADIErain.png';
link[8] = 'ubmt38md7/Windy.png';
link[9] = 'x0m770h8b/NO_WEATHER.png';
link[10] = 'x0m770h8b/NO_WEATHER.png';
var currentdate = new Date();
var imagenumber = currentdate.getDay();
document.write('<div id="NOTICEME"><center><img src="' + imlocation + image[imagenumber] + '"><img src="' + imlocation + link[imagenumber] + '"></center><br><div id="mowords">[center][img]' + imlocation + image[imagenumber] + '[/img][img]' + imlocation + link[imagenumber] + '[/img][/center]</div></div>');
//--></script>
I used this code as a base to go on. But no matter how I toy with it, it won't give me a random image from the array. Also, the div ID "mowords" and "NOTICEME" is an ID I am using for CSS reasons that has nothing to do with this code.
Edit:
Maybe going for random is the wrong way to do this. Is there a way to make the link = new linkArray select the date (as in 1 - 31) and the image = new ImageArray select the day (as in 1 - 7) like it is currently doing? It will create variance and the illusion of randomness in the long run.
If you know your arrays' indices, and they are integers, then you can use the following to get a pseudo-random integer between min and max:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
Now, however, your approach has been giving you certain "consistency" in your results, i.e. each day of the week giving you a certain image on every page show.
If you wish to implement randomness into it, you won't get such consistent results, meaning that on every page show, the image will be random independent of the day of the week or time of day.
To address this issue, you can take several approaches:
Have a server-side scripting language define the images (random or not) and save the "daily"/12-hour preferences into a .json/.js file, which then can be read by the JavaScript running in the browser. With this approach you would probably set the "refresh" rate via adding Expires headers on the .js file handling the parsing of the configuration file created by your server-side script -> https://gtmetrix.com/add-expires-headers.html
The other approach is to redefine your image selection logic based on the current date/time. However, the obvious downfall to that, is that you rely on the date and time of the user's computer, which can't always be trusted, so you have to work around that.
I would advise to look into a server-side scripting solution - PHP/Perl would do fine for this purpose.
UPDATED:
Have not tested, but try this (as per your comments):
<script type="text/javascript"><!--
var imlocation = "https://s31.postimg.org/";
function ImageArray (n) {
this.length = n;
for (var i = 0; i <= n; i++) {
this[i] = ''
}
}
function linkArray (n) {
this.length = n;
for (var i = 0; i <= n; i++) {
this[i] = ''
}
}
image = new ImageArray(6);
image[0] = 'v85buoebv/Day2.png';
image[1] = 'djdl322kr/Evening2.png';
image[2] = 'arubcg423/Night2.png';
image[3] = 'xf9kiljm3/Morning2.png';
image[4] = '';
image[5] = '';
image[6] = '';
link = new linkArray(30);
link[0] = 'q4xda5xdn/CLOUDY.png';
link[1] = '7141ttkjf/Heavyrain.png';
link[2] = 'gzp0gatyz/lightrain.png';
link[3] = 'xc3njrxob/Medium_Rain.png';
link[4] = 'x0m770h8b/NO_WEATHER.png';
link[5] = 's38mlwf97/omgrain.png';
link[6] = 'btigj04l7/Special_Weather.png';
link[7] = 'b59m025vf/WEREALLGONNADIErain.png';
link[8] = 'ubmt38md7/Windy.png';
link[9] = 'x0m770h8b/NO_WEATHER.png';
link[10] = 'x0m770h8b/NO_WEATHER.png';
link[11] = '';
link[12] = '';
link[13] = '';
link[14] = '';
link[15] = '';
link[16] = '';
link[17] = '';
link[18] = '';
link[19] = '';
link[20] = '';
link[21] = '';
link[22] = '';
link[23] = '';
link[24] = '';
link[25] = '';
link[26] = '';
link[27] = '';
link[28] = '';
link[29] = '';
link[30] = '';
var currentdate = new Date();
var dM = currentdate.getDate() - 1;
var dW = currentdate.getDay();
//var imagenumber = currentdate.getDay();
document.write('<div id="NOTICEME"><center><img src="' + imlocation + image[dW] + '"><img src="' + imlocation + link[dM] + '"></center><br><div id="mowords">[center][img]' + imlocation + image[dW] + '[/img][img]' + imlocation + link[dM] + '[/img][/center]</div></div>');
//--></script>
You use the function getDay() on the currentDate, therefore it will not change throughout a single day. Have a look at http://www.w3schools.com/jsref/jsref_getday.asp where you notice that its an integer from 0 to 6, and the week starts on sunday.
Therefore today (wednesday august 03 is 3) you should see image[3] and link[3]. Tomorrow you should get an error because you will reference outside of the image array i.e. image[4] will throw an index out of bounds exception.
Well, here goes my first answer here ever!
JavaScript is client-side code, so if the JavaScript code is what is determining the random number (rather than server-side code), you can't guarantee everyone accessing the site sees the same thing.
You could, however, use the date and time as a seed to generate what could appear random:
var btn = document.getElementById('btn');
btn.onclick = function () {
var d = new Date();
// getHours() results in an integer 0-23
var h = d.getUTCHours();
var chooser;
//Pick a multiplier based on the time of day.
if (h < 12) {
chooser = 1.15;
} else {
chooser = 1.87;
}
//Change upperLimit to whatever the upper limit of your array may end up being.
var upperLimit = 10;
//Generate the result
var pseudoRand = parseInt((d.getUTCFullYear() + d.getUTCMonth() + d.getUTCDay()) * chooser % upperLimit);
btn.textContent = pseudoRand;
}
Fiddle: https://jsfiddle.net/tapjzg94/
That code replaces the text of the button with an integer from 0 to upperLimit that should be the same for everyone who clicks on it, avoiding time zone issues with the UTC versions of the Date functions.
You could mix and match the date functions however you want, so long as they are all numbers that don't change on a rapid basis (year/month/date/day vs. minutes/seconds/milliseconds).

New to JavaScript and think I need a loop for this.....?

I've got a 180 character string of numbers which needed to be broken down into 6 groups, separated into 2 character figures and then sorted into ascending order.
I've done this, but it looks dirty and I'm pretty sure with my gradual improvement of understanding of JavaScript, that a neat little loop would save me a huge amount of repetition.
<script type="text/javascript">
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var groupa = ticketString.slice (0,15);
groupa.sort();
var groupb = ticketString.slice (15,30);
groupb.sort();
var groupc = ticketString.slice (30,45);
groupc.sort();
var groupd = ticketString.slice(45,60);
groupd.sort();
var groupe = ticketString.slice(60,75);
groupe.sort();
var groupf = ticketString.slice(75,90);
groupf.sort();
function displayArray () {
document.getElementById('ticketOne').innerHTML = groupa;
document.getElementById('ticketTwo').innerHTML = groupb;
document.getElementById('ticketThree').innerHTML = groupc;
document.getElementById('ticketFour').innerHTML = groupd;
document.getElementById('ticketFive').innerHTML = groupe;
document.getElementById('ticketSix').innerHTML = groupf;
}
The outputs are placed into paragraphs for now, but I know this could be done easier than the way I have it. The function displayArray loads off the body tag.
If you could rename your elements from ticketOne, ticketTwo etc to ticket1, ticket2 etc:
<script type="text/javascript">
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
for (var i=0; i<ticketString.length/15; i++) {
var group = ticketString.slice(i*15, i*15+15);
group.sort();
document.getElementById('ticket'+(i+1)).innerHTML = group;
}
</script>
So here is what I think is the best solution:
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var group = [];
for (var i = 0; i < 180 / 15 / 2; i++) {
group[i] = ticketString.slice(i * 15, (i + 1) * 15);
group[i].sort();
document.getElementById('ticket[' + i + ']').innerHTML = group[i];
}
What I'm doing here is that I created a local array called group, which is in turn easier to handle within a loop than using a name like "group1" or "ticketFirst".
After that I practically did the same you did, but since I used the for loop I was able to short it down significantly.
The reason why I used i < 180 / 15 / 2 is because you're pairing them in character packs of 2. for (var i = 0; i < 180 / 15 / 2; i++) You ofcourse have to have an HTML like this:
<body>
<p id="ticket[0]"></p>
<p id="ticket[1]"></p>
<p id="ticket[2]"></p>
<p id="ticket[3]"></p>
<p id="ticket[4]"></p>
<p id="ticket[5]"></p>
</body>
You can reduce it to:
var groupArray = [];
for(var i=0;i<100;i+=15){
groupArray.push(ticketString.slice (i,15+i));
groupArray[groupArray.length-1].sort();
}
You could do something like this, if you changed your 'ticket' id's to a generic 'ticket' class;
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var tickElem = document.querySelectorAll('.ticket');
var strPoint = 0;
for(var i in tickElem)
{
var grp = ticketString.slice(strPoint, (strPoint += 15));
grp.sort();
tickElem[i].innerText = grp.join('');
}
How about this compact version:
var start = 0;
['ticketOne', 'ticketTwo', 'ticketThree', 'ticketFour', 'ticketFive', 'ticketSix']
.forEach(function (id) {
document.getElementById(id).innerHTML = ticketString.slice(start, start += 15).sort();
});
<script>
var ticketString ="011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
function loadTickets () {
var ticket = [];
for (var i = 0; i < ticketString.length / 15; i++) {
ticket[i] = ticketString.slice(i * 15, (i + 1) * 15).sort();
var tableCre = document.createElement("TABLE");
tableCre.setAttribute("id","ticketTable" + i)
document.body.appendChild(tableCre);
document.getElementById('ticketTable' + i).innerHTML = ticket[i];
}
console.log(ticketString);
console.log(ticket);
};
</script>
Got it fixed, #Quikers - given you the thumbs up; as this was the thinking I had - brought the .sort() function into the ticket[i] variable to trim it a little and based on the number of arrays, I have dynamically created 6 tables that hold the strings inside them. I have to develop the tables and set them up, but I am pretty much there now. Thanks for all your help.

Loop through array of images in javascript

I'm trying to loop through an array of images but can't seem to get past image 2.
The array should also loop back to 1 when the last image has passed...
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var nelements = WorkArray.length;
preload_image_object = new Image();
var i = 0;
for(i=0; i<=nelements; i++) {
preload_image_object.src = WorkArray[i];
}
function cC() {
var nelements = WorkArray.length;
var i = 0;
for(i=0; i<=nelements; i++) {
nelements = WorkArray[i];
}
document.getElementById("work").style.backgroundImage="url('"+WorkArray[i]+"')";
}
You can save the current file and use modulo to run in cyclic manner.
It will look something like that:
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var currentImage = 0
function nextImage(){
currentImage = (currentImage + 1) % WorkArray.length;
document.getElementById("work").style.backgroundImage="url('"+WorkArray[currentImage]+"')";
}
You are overwriting nelements with the current element of the loop:
nelements = WorkArray[i];
The following should fix your loops:
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var preload_image_object = new Image();
/* Lets get rid of `nelements`, as its just confusing. Get the length here.
* If, for performace reasons you want to use elements, the best way is to reverse
* aka for(var i = WorkArray.length-1; i >= 0 ; i--)
* Also, its simpler to declare the var in your for-loop itself instead of outside of it.
*/
for(var i = 0; i <= WorkArray.length; i++){
preload_image_object.src = WorkArray[i];
}
Also, again for simplifications sake, your application of the background-image could be done inside your for loop as well, and can be made to look cleaner with some spaces and omitting the ' inside your url():
document.getElementById("work").style.backgroundImage = "url(" + WorkArray[i] + ")";

Javascript: Random number out of 5, no repeat until all have been used

I am using the below code to assign a random class (out of five) to each individual image on my page.
$(this).addClass('color-' + (Math.floor(Math.random() * 5) + 1));
It's working great but I want to make it so that there are never two of the same class in a row.
Even better would be if there were never two of the same in a row, and it also did not use any class more than once until all 5 had been used... As in, remove each used class from the array until all of them have been used, then start again, not allowing the last of the previous 5 and the first of the next 5 to be the same color.
Hope that makes sense, and thanks in advance for any help.
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.
Here's a general purpose random function that will not repeat until all values have been used. You can call this and then just add this index onto the end of your class name.
var uniqueRandoms = [];
var numRandoms = 5;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
Working demo: http://jsfiddle.net/jfriend00/H9bLH/
So, your code would just be this:
$(this).addClass('color-' + (makeUniqueRandom() + 1));
Here's an object oriented form that will allow more than one of these to be used in different places in your app:
// if only one argument is passed, it will assume that is the high
// limit and the low limit will be set to zero
// so you can use either r = new randomeGenerator(9);
// or r = new randomGenerator(0, 9);
function randomGenerator(low, high) {
if (arguments.length < 2) {
high = low;
low = 0;
}
this.low = low;
this.high = high;
this.reset();
}
randomGenerator.prototype = {
reset: function() {
this.remaining = [];
for (var i = this.low; i <= this.high; i++) {
this.remaining.push(i);
}
},
get: function() {
if (!this.remaining.length) {
this.reset();
}
var index = Math.floor(Math.random() * this.remaining.length);
var val = this.remaining[index];
this.remaining.splice(index, 1);
return val;
}
}
Sample Usage:
var r = new randomGenerator(1, 9);
var rand1 = r.get();
var rand2 = r.get();
Working demo: http://jsfiddle.net/jfriend00/q36Lk4hk/
You can do something like this using an array and the splice method:
var classes = ["color-1", "color-2", "color-3", "color-4", "color-5"];
for(i = 0;i < 5; i++){
var randomPosition = Math.floor(Math.random() * classes.length);
var selected = classes.splice(randomPosition,1);
console.log(selected);
alert(selected);
}
var used = [];
var range = [0, 5];
var generateColors = (function() {
var current;
for ( var i = range[0]; i < range[5]; i++ ) {
while ( used.indexOf(current = (Math.floor(Math.random() * 5) + 1)) != -1 ) ;
used.push(current);
$(" SELECTOR ").addClass('color-' + current);
}
});
Just to explain my comment to jfriend00's excellent answer, you can have a function that returns the members of a set in random order until all have been returned, then starts again, e.g.:
function RandomList(list) {
var original = list;
this.getOriginal = function() {
return original;
}
}
RandomList.prototype.getRandom = function() {
if (!(this.remainder && this.remainder.length)) {
this.remainder = this.getOriginal().slice();
}
return this.remainder.splice(Math.random() * this.remainder.length | 0,1);
}
var list = new RandomList([1,2,3]);
list.getRandom(); // returns a random member of list without repeating until all
// members have been returned.
If the list can be hard coded, you can keep the original in a closure, e.g.
var randomItem = (function() {
var original = [1,2,3];
var remainder;
return function() {
if (!(remainder && remainder.length)) {
remainder = original.slice();
}
return remainder.splice(Math.random() * remainder.length | 0, 1);
};
}());

Get a sequence of images into an array

I was wondering if it's possible to get a sequence of pictures into an array. I'd like to use plain JavaScript, because I have zero experience in PHP or any other language to achieve this.
So I created a map called "images", which contains 50 images. The first one is called: "1", the second one is called: "2" and so on. They all are the same type (.jpg).
I can do this manually like:
var pictures = new Array();
pictures[0] = "images/1.jpg";
pictures[1] = "images/2.jpg";
//and so on
But only a mad man would do this. also when I upload a new picture to the "images" folder, I have to manually add the new image to the array, so I was thinking about a while loop which checks if each image in the folder is stored into the array.
You could try:
var pictures = new Array();
for(var x=1; x<51; x++ ) {
pictures[x-1] = "images/"+x+".jpg";
}
var numberOfImages = 50; // or whatever
var im, pictures = new Array();
for (var i = 0; i < numberOfImages ; i++) {
im = "images/" + i + ".jpg";
pictures.push(im);
}
var arr = [];
for (var i = 0, max = 50; i < max; i += 1) {
arr[i] = "images/" + i + ".jpg";
}
If you want a change number of images, try this:
function bar (numberOfImages) {
var arr = [];
for (var i = 0; i < numberOfImages; i += 1) {
arr[i] = "images/" + i + ".jpg";
}

Categories

Resources