create new element from array until array is empty every second - javascript

Trying to create an element using items from an array that are randomly selected every other second until array is empty. I am stumped why my function works when i don't append the element to the dom but as soon as i add to the dom the array just gets larger and ends up crashing the dom.
My plan is to eventually create a new object that has the image, css with random xy position and then append a new element to the dom using the object values.
Basically i am trying to add random images to the dom every second and have them animate in and out until the array is empty.
Any help would be greatly appreciated, thank you.
"load": function(){
var imgArray = ['brain', 'mitochondria', 'microscope', 'beaker', 'beaker-2', 'scientist', 'cell', 'atom', 'dropper'];
window.setInterval(function(){
var imgItem;
if( imgArray.length >= 1 ) {
var index = Math.floor( Math.random()*imgArray.length );
console.log( imgArray[index] ); // Log the item
imgItem = ( imgArray[index] ); // Log the item
imgArray.splice( index, 1 ); // Remove the item from the array
// $('form').append('<img class="img-animation" src="img/science/'+ imgItem +'.svg" alt="'+ imgItem +'">');
}
}, 1000);
},
This is the console when i don't append new image:
home.js:11 beaker
home.js:11 dropper
home.js:11 microscope
home.js:11 beaker-2
home.js:11 atom
home.js:11 brain
home.js:11 scientist
home.js:11 cell
home.js:11 mitochondria
If i add the new image to the dom it will eventually crash and the loop goes on forever which makes no sense to me.

Well, you are setting an interval, it will keep calling itself to check the if every second long after the array is empty, even if thats not the issue I recommend you to do something like this:
var imgArray = ['brain', 'mitochondria', 'microscope', 'beaker', 'beaker-2', 'scientist', 'cell', 'atom', 'dropper'];
var getAllRandomly = function(arr) {
if (arr.length) {
var index = Math.floor(Math.random() * arr.length);
console.log(arr[index]); // Log the item
imgItem = (arr[index]); // Log the item
imgArray.splice(index, 1); // Remove the item from the array
setTimeout(function() {
getAllRandomly(arr);
}, 1000);
}
else {
console.log('Array is empty');
}
};
getAllRandomly(imgArray);
This way, the function will call itself and return one result every second until the array is empty.
Now going to the real problem:
Your 'load' function is probably being called multiple times, setting a lot of intervals with the same array. If the loop is really infinite then it might be calling itself somehow.
Try leaving just a console log on your load function and run your script to see if the log appears multiple times.

Related

Get second element of array after removing elements and updating array

Task: I have var = array; in a function that can hold the following sample array - the items represent time (seconds):
["20.30", "30.55", "8.25", "32.74", "2.75", "39.24"]
A setInterval loop displays the third item (array[2]) when a timer exceeds or matches second item in array (array[1]). Currently, after that happens, the first two items of array (array[0] and array[1]) are removed and array variable is re-indexed like so, looping the process until done:
array = array.splice(2).filter(function(){return true;});
Dilemma: I thought it would be easiest to just remove the first two items and update the array this way so as to simply apply a condition like so: if ( array[1] <= timer ){ but the splice() and filter() methods - which apply after the conditional statement in the loop - don't seem to re-index array variable.
Is there a way to make sure the array variable is re-indexed by new length, or perhaps there is a better way by navigating through the array variable without having to mutate/update it? The latter would perhaps be best, but I am kind of noob in better array manipulation and would appreciate some help.
UPDATE
Below I summarize what I clearly wish to attain:
var array = ["20.30", "30.55", "8.25", "32.74", "2.75", "39.24", etc...]
Instead of programmatically fetching each and every item iteration (impossible since amount will dynamically change) like follows ...
timelinePolling = setInterval(function(e){
...
if ( array[1] <= timer ){
timeline(array[2]); // Apply 3rd item timeline value
} else if ( array[3] <= timer ){
timeline(array[4]); // Apply 5th item timeline value
}
// etc, for remaining determined/undetermined items.
}, 30);
... I wish to iterate and dynamically increment the index target of array item variable (what is in brackets) the moment array[index] <= timer is achieved, like so (pseudo):
timelinePolling = setInterval(function(e){
...
if ( array[end] <= timer ){
// [end] is always an odd-numbered 0-based indexed item
// in array list (see Note1 below).
timeline(array[start]);
// [start] is always an even-numbered 0-based indexed item
// in array list (see Note2 below).
// Note1: [end] must be swapped with next chronological
// odd-numbered indexed item in array list at this point in code.
/* Missing code here! */
// Note2: [start] must be swapped with next chronological
// even-numbered indexed item in array list at this point in code.
/* Missing code here! */
}
}}, 30);
So it's the dynamic index increment part that I wish to resolve, which would make my day to say the least. Perhaps my array should be constructed differently to facilitate the task? In this fashion the array must remain intact (no mutation). Any pointers/help will be appreciated.
Looks like you code in is in the right direction take a look at circular arrays:
https://www.geeksforgeeks.org/circular-array/
Possibly you are looking at something like this -
index = beg;
while (index < end) {
if( arr[index] < timer) {
// set beg and end appropriately
// swap the values you need from the notes
// Note1: [end] must be swapped with next chronological
// odd-numbered indexed item in array list at this point in code.
/* Missing code here! */
// Note2: [start] must be swapped with next chronological
// even-numbered indexed item in array list at this point in code.
/* Missing code here! */
timeline(arr[index+1]);
}
index += 2; // jump to the next even number.
index %= arr_len; //check here if there is something that needed to be done for even odd index
}
You could do this with setTimeout, and then you won't have to do the comparison yourself.
At the end of each timeout loop, you splice the array as you suggested, if there are still 3 or more entries in the array then recall the function that sets the timeout.
(The timer here is only to display the total time)
(I reduced your array of number to speed it up)
let timer = 0;
const times = ["4.30", "5.55", "6.25", "6.74", "5.75", "4.24"];
function test(array) {
const timeInMilliseconds = parseFloat(times[1]) * 1000;
setTimeout(() => {
document.querySelector('#ignore').innerHTML = array[0];
document.querySelector('#test').innerHTML = array[1];
document.querySelector('#display').innerHTML = array[2];
timer += timeInMilliseconds / 1000;
document.querySelector('#timer').innerHTML = timer;
document.querySelector('#array').innerHTML = array;
array = array.splice(2);
if (array.length >= 3) {
test(array);
}
}, timeInMilliseconds);
}
test(times);
<p>ignore: <span id="ignore">-</span></p>
<p>test: <span id="test">-</span></p>
<p>display: <span id="display">-</span></p>
<p>Timer: <span id="timer"></span></p>
<p>Array: <span id="array"></span></p>

I am trying to stop my function from displaying the same object twice when clicking a button

I have for quite some time now been trying to figure out how I can stop my code to print the same quote twice.
Also, when every single object in the array has been printed out, I'd like for it to reset somehow. So that you can browse through the quotes once you've gone through all of them.
This is the essential parts of my code:
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
The printQuote function simply contains information that's accessing information from my array:
var randomObjectNumber = getRandomQuote();
var html = "<p class='quote'>"
+ quotes[randomObjectNumber].quote +
"</p>";
document.getElementById('quote-box').innerHTML = html;
One random object is displayed each time you click the eventListener:
function getRandomQuote () {
var randomObjectNumber = Math.floor(Math.random() * quotes.length );
return randomObjectNumber;
}
I have some ideas on how to do this and I have tried them but without success. I tried giving each object a boolean property but I can't really seem to assign each property a boolean value without messing the printQuote function up.
I also tried assigning the object displayed to a different array but the same problem occurred there.
I feel like there is some concepts around the eventListener that I don't fully understand, because every time I try to manipulate a displayed object I just end up changing every single object.
This is what a typical object in the array looks like by the way:
{quote : "Darkness is merely the absence of light"}
(I also have other properties assigned to the object but i feel like presenting them would be redundant)
If someone could explain, or give me a hint, on how to solve this problem I've been struggling with for some time.
Some hints would be greatly appreciated!
Have a nice day.
Sebastian.
EDIT: All code: https://jsfiddle.net/fusqb7hz/
Basically what you need:
Create a separate array that will store all quotes that you've already used.
Remove quote from initial array.
Check if you still have quotes in initial array, if not, get them back from backup array.
The problem is that you call addEventListener twice:
//Let's developers create multiple eventListeners without being redundant.
function onClicking (printFunction) {
document.getElementById('loadQuote').addEventListener("click", printFunction, false);
}
onClicking(printColor);
onClicking(printQuote);
by calling onClicking twice you make the click happen twice, so addEventListener is added twice, meaning one click counts as two.
Change the above code for this:
//Let's developers create multiple eventListeners without being redundant.
document.getElementById('loadQuote').addEventListener("click", function(){
printColor();
printQuote();
});
Here is the jsfiddle:
https://jsfiddle.net/fusqb7hz/3/
I think the easiest approach is to shuffle your quote array and then go through them one by one. This gives you the next "random" as yet unseen quote. The only part I'm not keen on is this shuffler (a derivation of Fisher Yates) modifies the original quote array. You might not care about that though.
// --------------------------------
// A bunch of quotes
// --------------------------------
var quotes = [];
quotes.push({quote : "Darkness is merely the absence of light"});
quotes.push({quote : "quote 2"});
quotes.push({quote : "quote 3"});
quotes.push({quote : "quote 4"});
quotes.push({quote : "quote 5"});
// --------------------------------
// --------------------------------
// Your favorite array shuffle utility
// --------------------------------
var shuffle = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
// --------------------------------
// --------------------------------
// construct a function to get a random unseen quote until
// all quotes have been seen. Then reset...
// --------------------------------
var getQuote = (function(quotes, shuffle){
var current = 0;
var get = function(){
if ( !quotes || !quotes.length ) { return ""; }
if ( current >= quotes.length ){ current = 0; }
if ( current === 0 ){
console.log("randomizing quotes...");
shuffle(quotes);
}
return quotes[current++].quote;
};
return get;
})(quotes, shuffle);
// --------------------------------
var printQuote = function(){
document.getElementById('quote').innerText = getQuote();
};
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
<div id="quote"></div>
<button id="loadQuote">get quote</button>

Destroy an object after set time

I have been looking around for this but have turned up a blank
is it possible in javascript to create an instance of an object which has a set time to live, after which it would be destroyed?
a case would be where a item is added to an array every 5 seconds and shown in the visual, each item then should be removed after it have been in view for a minute. I hesitate to run a timeout function checking the array every second to clear them..
OOP FTW. Why not create some sort of self removing object?
function SelfRemover(){//constructor
};
SelfRemover.prototype.addTo = function(arr) {
var me = this;
arr.push(me); //adding current instance to array
setTimeout(function() { //setting timeout to remove it later
console.log("Time to die for " + me);
arr.shift();
console.log(arr);
}, 60*1000)
}
Usage
var a = [];
setInterval(function(){new SelfRemover().addTo(a); console.log(a);}, 5*1000);

Play functionality in nested loops Javascript

I am trying to build play functionality using JavaScript to play different colors for my attribute values on map. The basic logic, I am building using simple for loop does not work for me as the loop is played so fast and I only get display last value on Map.
Example:
//Hash of my Values
var myHash = {};
myHash['1'] = [10,100];
myHash['2'] = [20,200, 30];
myHash['3'] = [40,300, 4, 5];
function startPlaying() {
for (item in myHash) {
var myValues= myHash[item];
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000);
}
}
function animate(myValues,item) {
for(i in myValues) {
//calling my function for each value to play on map with different styles.
playMyMap();
}
}
I was expecting here that my function startPlaying will fire timeout function three times(for number of items with 1 sec delay) with corresponding myValues and item and It will keep on iterating over myValues individually for three items.
But this doesn't work for me beacuse the myValues gets messed up while each call of setTime out function.
Could anyone please give me an idea here, how can I build such functionality?
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000);
}
Will trigger 3 times, but all after 1 second. If you keep a counter you have to do the 1000*counter to have 1 animate function each second.
The below example uses the item as the multiplyer because you start your index with 1. Normally array's start at index 0. If you change your first item to index 0, just do 1000 * (item + 1) to start with 1 second.
Try this:
function startPlaying() {
for (item in myHash) {
var myValues= myHash[item];
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000 * item );
}
}

Extract array values with last extraction memory on callback in javascript

Let's say I have a dynamic array that is populated on page load with various amounts of strings inside:
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
I then have a function that is called on each event (let's say a click) that needs to bring back 3 strings of the array consecutively while remembering which value it left off at, the last time it was called. So:
First time function is called, it returns:
string1, string2, string3
Second time it is called, it returns:
string4, string5, string6
and so on...
I don't the need the code for the click event or the callback function, rather the code for the function that would generate the extraction each time and bring it back. Something simple like being able to call:
arr.runExtraction();
on each callback and having it bring back the desired data.
What should happen if the array is exhausted? Start from the beginning?
You could do something like this:
function get_iterator(values, steps, start) {
steps = steps || 1;
var current = start || 0,
max = values.length;
return function() {
var end = current+steps,
end = end > max ? max : end,
t = values.slice(current, end);
current = end % max;
// or if you don't want to wrap around:
// current = end;
return t;
}
}
Edit: Added start parameter.
As current will be the same as values.length in the end, splice will return an empty array if you don't wrap around.
Using slice won't change the original array.
And then
var extract = get_iterator(arr, 3);
var arr1 = extract(); // gives you the first three elements
var arr2 = extract(); // gives you the next three elements etc.
DEMO
It might give you less elements in the "last" extraction if the number of elements is not divisible by number of extracted elements. The next call will let it start from the beginning again. You could also modify it that it wraps around and takes elements from the beginning so that it will always return as many elements as you have specified.
Reference: Array.prototype.slice
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
var runExtraction = function () {
return arr.splice(0, 3);
}

Categories