The output from SetTimeout function is inconsistent - javascript

I am trying to create something like a Grid-Image-Box-Slider. Now what I am trying to achieve is that after a period of time (e.g 5 seconds) one of the images will be changed randomly. So, my script follows:
var currentImages = [1, 2];
(function imgCarousel() {
var min = 1;
var max = 6;
currentImgSlot = pickImageSlot();
var pickedImage = pickImage();
setTimeout(function () {
console.log("Image Slot: " + currentImgSlot + "<br> Image: " + pickedImage);
//var bgImgElem = document.getElementsByClassName('bg1');
var sheet = new CSSStyleSheet();
sheet.replaceSync('.bg' + currentImgSlot + ' {background-image: url("assets/img/' + pickedImage + '.jpg") !important}');
document.adoptedStyleSheets = [sheet];
return imgCarousel();
}, 5000)
})()
function pickImageSlot() {
var min = 1;
var max = 2;
var generatedImgSlot = generateRandomNumber(max, min);
if (generatedImgSlot == currentImgSlot) {
return pickImageSlot();
}
return generatedImgSlot;
}
function pickImage() {
var min = 1;
var max = 6;
var generatedImg = generateRandomNumber(max, min);
if (currentImages[currentImgSlot] == generatedImg) {
return pickImage();
}
currentImages[currentImgSlot] = generatedImg;
return generatedImg;
}
function generateRandomNumber(max, min) {
return Math.round(Math.random() * (max - min) + min)
}
So, here you can see that inside the imgCarousel() function I am using the setTimeout to change the background-image randomly after 5 seconds and then calling the same function again recursively. So, according to this code after each five seconds only one image should be changed. But, in reality, sometimes both of the images get changed at the same time. I don't know what is causing this issue.
Any help would be much appreciated. For your convenience I am sharing my code repo here:
Git Repo
Live Demo

It's a bit difficult to notice, but if you pay attention, in your live demo you'll actually see that each time they both change, one returns to the default. This is because you're actually just overriding the adoptedStyleSheets property with a new array consisting only of the latest override, so your other image will simultaneously return to the primary style sheet's image (the default).
There is no problem with the setTimeout, the issue is just that you need to be able to support both images being different from the default, instead of exactly one. You already keep both images in currentImages, so each time the timeout runs you can iterate over them and set each one's image in the new adopted style sheet.
Naively, something like this might work:
setTimeout(function () {
console.log("Image Slot: " + currentImgSlot + "<br> Image: " + pickedImage);
//var bgImgElem = document.getElementsByClassName('bg1');
var sheet = new CSSStyleSheet();
for(var i = 1; i < 2; i++) {
sheet.replaceSync('.bg' + i + ' {background-image: url("assets/img/' + currentImages[i]+ '.jpg") !important}');
}
document.adoptedStyleSheets = [sheet];
return imgCarousel();
}, 5000)
Your currentImages seems to be used with a random number between 1 and 2, but arrays are 0-based, so I'm not sure what your intended usage is there, but this should get you on the right track.

Related

How to reduce number of computations during d3.js transition?

So right now, I'm trying to implement a search bar function into my d3.js plot. Right now it doesn't do anything, but that's not the issue at the moment. The problem is that when I type/delete something from the bar, there's visible lag/choppiness in the characters appearing/disappearing. I believe the issue is stemming from my plot. I have 140+ dots moving around the screen, and their position is being interpolated. So from the beginning to the end of the transition, my code has to compute 140 positions thousands of times over.
I've looked into trying to reduce the cardinality of the d3.interpolateNumber function, but it appears that there isn't a third argument to change the number of terms like in a linspace command. Right now I have an array of 1000 numbers for my function to run through, but I don't know how to pass the array to my other functions.
Below are the pertinent functions for this issue. The commented line in tweenPatch is the original code I had that made my code run, but gave my plot computational issues. Variables arr, curr, and step were my attempt to fix the situation, but I haven't been able to figure out how to pass the array into displayPatch().
function tweenPatch() {
var patch = d3.interpolateNumber(1, 26);
var arr = [];
var curr = 1;
var step = (26 - 1) / (1000 - 1);
for (var i = 0; i < 1000; i++) {
arr.push(curr + (step * i));
}
return arr.forEach(function(d) {
console.log(arr[d]);
displayPatch(arr[d]);
});
//return function(t) { displayPatch(t); };
}
function displayPatch(patch) {
dots.data(interpolateData(patch), function(d) { return d.name; }).call(position).sort(order);
var inter = Math.floor(patch);
var seas = 8;
var patc = 1;
if (inter > 24) {
seas = 9;
patc = inter - 24;
} else {
patc = inter;
}
label.text("Patch " + seas + "." + patc);
}
function interpolateValues(values, number) {
old = Math.floor(number);
upd = Math.ceil(number);
var old_data = values.filter(function(d) {return d.internal == old;});
var new_data = values.filter(function(d) {return d.internal == upd;});
var oobj = old_data[0];
var nobj = new_data[0];
var onum = oobj[Object.keys(oobj)[4]];
var nnum = nobj[Object.keys(nobj)[4]];
var difint = number - old;
var difdis = 0;
var newnum = nnum;
if (nnum > onum) {
difdis = nnum - onum;
newnum = ((difint) * difdis) + onum;
} else if (onum > nnum) {
difdis = onum - nnum;
newnum = onum - ((difint) * difdis);
}
return newnum;
}
I believe switching my SVG to a canvas may help things, but since I have no knowledge of canvas I'd rather leave that as a last resort.

Using math.random in button to set a select option?

I'm trying to make a button that randomly sets a select option when clicked. I can't figure out what I am doing wrong though...
http://jsfiddle.net/GamerGorman20/nw8Ln6ha/25/
$('#rand').click(
function() {
randNum();
var num = "";
document.getElementById("mySelect").value.innerHTML = favWebComics[num];
});
var randNum = function() {
num = Math.round(Math.random() * 2) + 1;
return num;
};
The shown code is only a small part of the larger script housed in the linked jsfiddle.
I plan to add more selections later, but I want to get the code figured out before I spend time on those.
Worth mentioning, my understanding of this is very limited, so keeping the advice simple is GREATLY appreciated.
The relevant part of your code that you will need to change will look like this when complete (see the updated jsfiddle):
$('#rand').click(function() {
var $select = document.getElementById('mySelect'),
max = $select.getElementsByTagName('option').length - 1;
$select.selectedIndex = randNum(1, max);
myFunction();
});
var randNum = function(min, max) {
num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
};
var myFunction = function() {
var x = document.getElementById("mySelect").value;
document.getElementById("demo").innerHTML = "You selected: " + x;
document.getElementById("image").innerHTML = favWebComics[x][1];
document.getElementById("web").innerHTML = favWebComics[x][0];
document.getElementById("tags").innerHTML = "Tags: " + favWebComics[x][2];
};
I haven't changed the style or structure of your code, but just some of the basic properties.
The problem you have is with innerHTML. You cannot set innerHTML on an element's value.
Instead, what you can do is generate a random number and set the selectedIndex property of the select element to that random number.
Then, you'll call the function that displays the images and whatnot that you need.
You cannot change the select with innerHTML like this:
document.getElementById("mySelect").value.innerHTML = favWebComics[num];
You have to instead change the value, and apply the change like so
$("#mySelect").val("New text").change();
or
$("#mySelect").prop('selectedIndex', index).change();

Random Number with javascript or jquery

I am trying to make a script to pick random number between two numbers . but it picks same number sometimes. i donot want to repeat same number until array is finished .
Here is my code
$(document).ready(function () {
abc();
test = array();
function abc() {
res = randomXToY(1, 10, 0);
$('#img' + res).fadeTo(1200, 1);
//$(this).addClass('activeImg');
//});
setTimeout(function () {
removeClassImg(res)
}, 3000);
}
function removeClassImg(res) {
$('#img' + res).fadeTo(1200, 0.1);
//$('#img' + res).removeClass('activeImg');
abc();
}
function randomXToY(minVal, maxVal, floatVal) {
var randVal = minVal + (Math.random() * (maxVal - minVal));
return typeof floatVal == 'undefined' ? Math.round(randVal) : randVal.toFixed(floatVal);
}
});
Does Anybody have idea about this ...
You'll have to maintain a list of numbers that have already been generated, and check against this list. Re-generate a new number if you find a dupe.
If you do not want the random numbers repeating themselves you have to keep track of the some way.
If you have the range you are dealing with is relatively small, you can create an array with all possible results and simply randomly pick out of it.
function Randomizer(minVal, maxVal, floatVal){
var possible_results = []; // for larger arrays you can build this using a loop of course
var randomization_array = [];
var count = minVal;
var incrementor = floatVal || 1; // set the distance between possible values (if floatVal equals 0 we round to 1)
while (count <= maxVal) {
possible_results.push(count);
count += incrementor;
}
this.run = function(){
// if randomization_array is empty set posssible results into it
randomization_array = randomization_array.length ? randomization_array : $.merge(randomization_array, possible_results);
// pick a random element within the array
var rand = Math.floor(Math.random()*randomization_array.length);
// return the relevant element
return randomization_array.splice(rand,1)[0];
}
}
and in order to use it (it creates a specialized object for each possible range):
rand = new Randomizer(1,10,0);
rand.run();
note that this approach does not work well for very large ranges

How to hide/show multiple square at different time

I'm still struggling with my simple javascript game. Here is my previous question: Simple javascript game, hide / show random square
Some square show and hide randomely for a few seconds and you have to click on them. I use RaphaelJS to draw the square and a few of JQuery ($.each() function)
I can't make the hide/show with the setInterval working for each square. The function made by Mishelle looks good but I get a "This is not a function" error.. I've test different stuff but it's not as obvious as I thought :/
window.onload = function() {
var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
// random function to for the x and y axis of the square
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var rectanglemain = paper.rect(0, 0, 500, 500).attr({fill: "white",});
var win_click = 0; // set the var to count the click on the square
var recs = [];
for(var i = 0; i < 50; i++) {
var x = random(1,450);
var y = random(1,450);
var rec = paper.rect(x, y, 50, 50).attr({fill: 'blue'});
recs.push(rec); // add the square in an array
recs[i].click(function () {
//counting the clicks
win_click = win_click + 1;
})
function hideSquare() {recs[i].hide();}
hideSquare();
}
rectanglemain.click(function () {
alert('you click on ' + win_click + ' squares');
});
/* here is a function made by Mishelle on my previous question, unfortunately I can't make it work (this is not a function error).
function showBriefly (timeFromNow, duration) {
window.setTimeout(this.rec.show, timeFromNow);
window.setTimeout(this.rec.hide, timeFromNow + duration);
}
recs[2].showBriefly(1000, 3000); to test the function
*/
}
Thanks for the help :)
try
window.setTimeout(function(){this.rec.show();}, timeFromNow )
Just came across your problem, just in case you read this and you want to know what was the problem. this is undefined within the callback, thus you need to store which rectangle you were referring to in a variable (I've called it square), see my code:
showBriefly: function(timeFromNow, duration) {
square = this.box;
setTimeout(function(){square.show();}, timeFromNow )
setTimeout(function(){square.hide();}, timeFromNow + duration )
}
Cheers

jQuery sort causing iOS Safari to freeze

I have a page that is using jQuery to load an XML file, which I'm then outputting the contents of to the page.
Recently I added a sorting function to the output which is causing a 1+ or 2+ minute hang on Safari on an iPod Touch (depending upon how many fields I sort by) and a less than 1 minute hang on an iPad. The same sort returns within a few seconds on Firefox 4.0.1.
I'm afraid it's just a limitation of the iOS, but before I removed the sort, perhaps there's an optimization that could be made.
Before the filter there's 357 items in the XML. After the filter there's 199 items that are sorted through.
var videoGames = $($.parseXML(videoGameXml)).find("game");
videoGames = videoGames.filter(function (a) {
return ($(this).attr('addOn') != "true" && $(this).find('own').text() == "yes");
});
videoGames.sort(function (a, b) {
var firstTitle = $(a).find('title').text().toLowerCase();
var secondTitle = $(b).find('title').text().toLowerCase();
var firstSystem = ($(a).find("console").text() + " " + $(a).find("version").text()).toLowerCase();
var secondSystem = ($(b).find("console").text() + " " + $(b).find("version").text()).toLowerCase();
if (firstSystem != secondSystem) {
if (firstSystem > secondSystem) {
return 1;
} else {
return -1;
}
} else {
if (firstTitle > secondTitle) {
return 1;
} else if (secondTitle < firstTitle) {
return -1;
}
}
return 0;
});
videoGames.each(function () {
// runs quickly, so removed
});
Note that if I remove the system check as an initial 'optimization' that cuts the time about in half on the iPod Touch, but still results in the 1+ minute hang mentioned above.
So, is it an iOS device limitation, or can I optimize my sort?
Every time you do $(a) it will perform a very complex set of operations, so you better cache it. Also, you don't need the Title if System is different. This version should speed it up a bit:
videoGames.sort(function (a, b) {
var first = $(a);
var second = $(b);
var firstSystem = (first.find("console").text() + " " + first.find("version").text()).toLowerCase();
var secondSystem = (second.find("console").text() + " " + second.find("version").text()).toLowerCase();
if (firstSystem != secondSystem) {
if (firstSystem > secondSystem) {
return 1;
} else {
return -1;
}
} else {
var firstTitle = first.find('title').text().toLowerCase();
var secondTitle = second.find('title').text().toLowerCase();
if (firstTitle > secondTitle) {
return 1;
} else if (secondTitle < firstTitle) {
return -1;
}
}
return 0;
});
You could also cache the values in the object
Then, instead of:
var firstSystem = (first.find("console").text() + " " + first.find("version").text()).toLowerCase();
Do:
var firstSystem = first.data('system');
if (!firstSystem) {
firstSystem = (first.find("console").text() + " " + first.find("version").text()).toLowerCase();
first.data('system') = firstSystem;
}
You should move any selectors calls like this:
var firstTitle = $(a).find('title').text().toLowerCase();
out from the comparator function. The comparator function is supposed to be lightweight.
Either use children(), next() and the like or
scan you set once and create an array of keys upfront and then sort it using those keys.
The comparator function will be called 2n * ln(n) times (depends on algorithm used) where n is a number of elements in a set. So your code does the same expensive calculations twice at least.

Categories

Resources