Javascript Closure functions - javascript

So I'm new to javascript and I am looking for a way to count how many times a function is executed. The code randomly generates a square or circle and displays from the shape is shown to when you click it (reactionTime). That works fine and dandy.
But I'm looking for a way to keep track of the number of times a shape is clicked and then eventually the cumulative time to calculate average time per click. If it helps, I come from a pretty good C++ background.
To count number of clicks, I was thinking of adding a closure function.
From here: How do I find out how many times a function is called with javascript/jquery?
myFunction = (function(){
var count = 0;
return function(){
count++
alert( "I have been called " + count + " times");
}
})();
And from here: Function count calls
var increment = function() {
var i = 0;
return function() { return i += 1; };
};
var ob = increment();
But I tried a global variable and several variations of closure functions to no avail (look for the comments). I tried putting the closure function in other functions. And I also tried something like:
var increment = makeBox();
I'm wondering if anyone can guide me in the right direction. It would be much appreciated!
var clickedTime; var createdTime; var reactionTime;
var clicked; var avg = 0;
avg = (avg + reactionTime) / clicked;
document.getElementById("clicked").innerHTML = clicked;
document.getElementById("avg").innerHTML = avg;
function getRandomColor() {
....
}
function makeBox() { // This is the long function that makes box
createdTime = Date.now();
var time = Math.random();
time = time * 3000;
///////// var increment = function () {
var i = 0;
//return function() { return i += 1; };
i++;
return i;
///////// };
// clicked++; /////////// global variable returns NaN
// console.log(clicked);
// alert("Clicked: "+clicked);
setTimeout(function() {
if (Math.random() > 0.5) {
document.getElementById("box").style.borderRadius="75px"; }
else {
document.getElementById("box").style.borderRadius="0px"; }
var top = Math.random(); top = top * 300;
var left = Math.random(); left = left * 500;
document.getElementById("box").style.top = top+"px";
document.getElementById("box").style.left = left+"px";
document.getElementById("box").style.backgroundColor = getRandomColor();
document.getElementById("box").style.display = "block";
createdTime = Date.now();
}, time);
}
ob = increment(); //////////////////////// I think this gives me 1 every time
alert("Increment: "+ob); //////////////////
document.getElementById("box").onclick = function() {
clickedTime = Date.now();
reactionTime= (clickedTime - createdTime)/1000;
document.getElementById("time").innerHTML = reactionTime;
this.style.display = "none";
makeBox();
}
makeBox();

You have a few problems but to answer your question:
You're not defining clicked as a number (or any other type) so trying to perform an operation on undefined returns NaN...because well, it's not a number.
Your second attempt var i = 0; won't work because i is re-defined on each function call.
You should be able to use your gobal variable clicked as long as you set it to zero.

Here is an example that shows how a closure can count calls to a function:
function add5(y) {
//A totally normal function
return y + 5;
}
var counter = 0, /*a counter scoped outside of the function counter function*/
trackedAdd5 = (function (func) {
/*This anonymous function is incrementing a counter and then calling the function it is passed*/
return function () {
counter++;
/*The trick is this function returns the output of calling the passed in function (not that it is applying it by passing in the arguments)*/
return func.apply(this, arguments);
}
})(add5); /*calling this tracking function by passing the function to track*/
document.getElementById('run').addEventListener('click', function () {
/*Here we are treating this new trackedAdd5 as a normal function*/
var y = document.getElementById('y');
y.value = trackedAdd5(parseInt(y.value, 10));
/*Except the outer counter variable now represents the number of times this function has been called*/
document.getElementById('counter').value = counter;
});
<label> <code>y = </code>
<input id='y' value='0' />
<button id='run'>add5</button>
</label>
<br/>
<label><code>add5()</code> was called
<input readonly id='counter' value='0' />times</label>

makeBox.click = 0; // define the function's counter outside the function
makeBox.click++; // replace the `i` usage with this inside the function
About ob = increment();: it is used erroneously (redefines ob many times);
var ob = increment(); // define it once
ob(); // increments the counter
// another way to define `increment`:
var increment = (function () {
var i = 0;
return function () {
return i += 1;
};
})();
ob = increment(); // ob becomes 1 initially
ob = increment(); // ob becomes 2, etc.

Related

Why Parameter Stops Function When Added

I have a code which I am trying to execute using a parameter in the function, i.e -
function startFadeEffect(elem){ };
I have made the elem equal to a variable b in the global scope, where b is an array of images. Meaning -
var elem = b[imgNumb];
imgNumb is a variable which is globally "0" and inside a function is defined as
imgNumb = imgNumb + count;
Now, my current code "without" the parameter works perfect -
function startFadeEffect(){
var opacSetting = noOpac / 10;
b[imgNumb].style.opacity = opacSetting;
b[imgNumb].style.display = "block";
noOpac++;
if(noOpac < 0){
opacSetting = 0;
}
if(opacSetting == 1){
clearTimeout(timer);
b[imgNumb].style.opacity = 1;
noOpac = 0;
return false;
}
var timer = setTimeout(startFadeEffect, 75);
}
However, when I use the parameter like this it does not work for me :(
function startFadeEffect(elem){
var opacSetting = noOpac / 10;
elem.style.opacity = opacSetting;
elem.style.display = "block";
noOpac++;
if(noOpac < 0){
opacSetting = 0;
}
if(opacSetting == 1){
clearTimeout(timer);
elem.style.opacity = 1;
noOpac = 0;
return false;
}
var timer = setTimeout(startFadeEffect(elem), 75);
}
Please note I have already defined the elem variable in the global scope of the file. Also, I am only looking for a JS solution no library like JQuery! Thanks
This part is incorrect:
setTimeout(startFadeEffect(elem), 75);
It should be:
setTimeout(function () {
startFadeEffect(elem);
}, 75);
setTimeout expects a function as it's first argument. startFadeEffect(elem) is executed immediately (and doesn't return a function). So what happens is that startFadeEffect calls itself recursively until opacSetting == 1 which breaks the recursion.

Image animation with speed control

We have some problem with our image animation with speed control.
It make use of a timeout to change the image, but we want to change the timeout value with a slider, but for some sort of reason, it doesn't work. Can someone help us out ?
We have a Jfiddle here: http://jsfiddle.net/Kbroeren/fmd4xbew/
Thanks! Kevin
var jArray = ["http://www.parijsalacarte.nl/images/mickey-mouse.jpg", "http://www.startpagina.nl/athene/dochters/cliparts-disney/images/donad%20duck-106.jpg", "http://images2.proud2bme.nl/hsfile_203909.jpg"];
var image_count = 0;
function rollover(image_id, millisecs) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
rollover("img1", 200);
$(function () {
var value;
var $document = $(document),
$inputRange = $('input[type="range"]');
// Example functionality to demonstrate a value feedback
function valueOutput(element) {
var value = element.value,
output = element.parentNode.getElementsByTagName('output')[0];
output.innerHTML = value;
}
for (var i = $inputRange.length - 1; i >= 0; i--) {
valueOutput($inputRange[i]);
};
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
rollover("img1", 200);
});
// end
$inputRange.rangeslider({
polyfill: false
});
});
You keep creating more and more infinite function calls without stopping them.
After you call your function the first time, it keeps calling itself.
then you call it again with different interval (millisecs) and it will also start call itself....
You can try two different approach.
1.Use setInterval instead of setTimeout. Use clearInterval to clear the interval before setting it with a new value.
/// Call animation() every 200 ms
var timer = setInterval("Animation()",200);
function ChageSpeed(miliseces){
///Stop calling Animation()
clearInterval(timer);
/// Start calling Animation() every "miliseces" ms
timer = setInterval("Animation()",miliseces);
}
function Animation(){
/// Animation code goes here
}
2.Or, Instead, Set your interval as a global variable (not cool) and just change it value when the user want to change the animation speed.
var millisecs = 200;
function rollover(image_id) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
millisecs = YourNewValue;
});

Set count variable where it where

I have made this simple content rotator with jQuery which works fine, but as you can see I have made a mouseenter function so that the rotator stops if your mouse in on the rotator.
My problem is that if I mouseenter and leave the function rotateReview() is restarted and the count variable (number) is 1. So automatically my rotator starts at the beginning where he should continue to the next one.
HTML:
<div id="review_rotator">
<div class="rotator">
<article>Content</article>
<article>Content</article>
<article>Content</article>
<article>Content</article>
</div><!--End .rotator-->
</div><!--End #review_rotator-->
jQuery
function rotateReview() {
var turn = $('#review_rotator article');
var numbers = turn.length;
var number = 1;
intv = setInterval(function() {
number++;
turn.fadeOut(300);
$('#review_rotator article:nth-child('+number+')').fadeIn(200);
if(numbers == number)
number = 0;
}, 4500)
}
rotateReview();
$(document).on('mouseenter mouseleave', '#review_rotator article', function(e) {
var mEnt = e.type == 'mouseenter';
if(mEnt) {
clearInterval(intv);
} else {
rotateReview();
}
})
You could do it like this:
function rotateReview() {
var turn = $('#review_rotator article');
intv = setInterval(function() {
var next = ($('#review_rotator article[style*="display: block"]')).next()[0];
if(next == undefined)
next = turn[0];
console.log(next);
turn.fadeOut(300);
$(next).delay(300).fadeIn(200);
}, 1000)
}
Check it out: http://jsfiddle.net/b53t39u7/
Every time you run rotateReview, the variable number will be assigned value 1. So you should store it outside the function or somewhere else, so that the variable number won't be freed after the function rotateReview finished.
I'will give 2 solutions.
1. As a global variable
var number = 1;
function rotateReview() {
var turn = $('#review_rotator article');
var numbers = turn.length;
intv = setInterval(function() {
number++;
turn.fadeOut(300);
$('#review_rotator article:nth-child('+number+')').fadeIn(200);
if(numbers == number)
number = 0;
}, 4500)
}
2. Store in the closure
If you don't like global variable, you can store it in a closure, which is a immediately-invoked function.
var rotateReview = (function () {
var number = 1;
return function () {
var turn = $('#review_rotator article');
var numbers = turn.length;
intv = setInterval(function() {
number++;
turn.fadeOut(300);
$('#review_rotator article:nth-child('+number+')').fadeIn(200);
if(numbers == number)
number = 0;
}, 4500)
}
}());

Javascript gradual width increase

I'm trying to gradually increase the elements of 2 id's in javascript using a Timeout. I can get one working but when trying to call another element into the same function it only does one iteration then crashes after the first recursive call.
I'm passing two id's for the elements. and I want the left element to gradually increase while the right element gradually increases in width.
Heres what ive got
function grow(elementL, elementR)
{
var htL = parseInt(document.getElementById(elementL).style.width,10);
var htR = parseInt(document.getElementById(elementR).style.width,10);
var movementL = htL + 5;
var movementR = htR - 5;
document.getElementById(elementL).style.width = movementL + 'px';
document.getElementById(elementR).style.width = movementR + 'px';
if (movementL > 1000) {
clearTimeout(loopTimer);
return false;
}
var loopTimer = setTimeout('grow(\''+elementL+','+elementR+'\')',50);
}
You could simplify this (removing the script-generation) by using setInterval -- this repeats the function call until you cancel it.
function grow(elementL, elementR)
{
var loopTimer = setInterval(function() {
if (!growStep(elementL, elementR)) {
clearInterval(loopTimer);
}
}, 50);
}
function growStep(elementL, elementR) {
var htL = parseInt(document.getElementById(elementL).style.width,10);
var htR = parseInt(document.getElementById(elementR).style.width,10);
var movementL = htL + 5;
var movementR = htR - 5;
document.getElementById(elementL).style.width = movementL + 'px';
document.getElementById(elementR).style.width = movementR + 'px';
if (movementL > 1000) {
return false;
}
return true;
}
(Fiddle)
Edit
Yeah, I guess the only problem with the OP code is that it passes a string to setTimeout, rather than the function itself:
var loopTimer = setTimeout(function() {
grow(elementL, elementR);
},50);
setTimeout('grow(\''+elementL+','+elementR+'\')',50)
would need to be
setTimeout('grow(\''+elementL+'\',\''+elementR+'\')',50)
// ^^ ^^
to work. But don't do that. Pass a function expression to setTimeout:
setTimeout(function() {
grow(elementL, elementR);
}, 50)

Setting a time for flicker animation on img

I'm using this code to make my logo flicker on my website. But It becomes annoying when it continues to flicker while browsing, how can I set a time to allow it to flicker for something like the first 15seconds on page load, then stops?
JS code I'm using:
$(document).ready(
function(){
var t;
const fparam = 100;
const uparam = 100;
window.flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = setTimeout('window.unflickr()',uparam);
}
else
t = setTimeout('window.flickr()',fparam);
}
window.unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = setTimeout('window.flickr()',fparam);
}
else
t = setTimeout('window.unflickr()',uparam);
}
t = setTimeout('window.flickr()',fparam);
});
You could have a counter, which you then use to decide whether you want to set another timeout. As a side note, you should never add functions to window and then passing a string to setTimeout. Always just pass the function itself:
$(document).ready(function(){
var t;
var amount = 0;
const fparam = 100;
const uparam = 100;
function timeout(f, t) { // this function delegates setTimeout
if(amount++ < 150) { // and checks the amount already (un)flickered
setTimeout(f, t); // (150 * 100 ms = 15 s)
}
}
var flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = timeout(unflickr,uparam);
}
else
t = timeout(flickr,fparam);
};
var unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = timeout(flickr,fparam);
}
else
t = timeout(unflickr,uparam);
};
t = timeout(flickr,fparam);
});
I see you're using jquery, you could use the following, if I remember correctly, all the stuff I use below has been in jquery since 1.0, so you should be good:
counter = 1;
function hideOrShow(){
$(".classToSelect").animate({"opacity": "toggle"}, 100);
counter = counter +1;
if (counter >= 21) clearInterval(flickerInterval);
}
flickerInterval = setInterval(hideOrShow, 100);
Change the selector, animation duration, and variable names to whatever you fancy/need.

Categories

Resources