Why is my interval time is not get cleared? - javascript

This is my function, I wrote this for moving my div from left to right. After iter reach 5, the interval has to stop. But now it is keep on running. My interval is not clearing, what is wrong with my function?
var mydiv = document.getElementById('news-variety');
var iter = 0;
if (mydiv) {
var columns = mydiv.getElementsByTagName('DIV');
function animeColumn(index, col) {
var timerID = window.setInterval(function () {
var current = window.getComputedStyle(col);
var matrix = new WebKitCSSMatrix(current.webkitTransform);
col.style.webkitTransform = matrix.translate(10, 0);
if (iter++ == 5) {
window.clearInterval(timerID);
}
}, 50);
}
for (var i = 0; i < columns.length; i++) {
if (columns[i].className.toLowerCase() == "column") {
columns[i];
animeColumn(i, columns[i]);
}
}
}

There is a weird behavior (bug?) in firefox that requires you to specify the second parameter of getComputedStyle to 'null'. Try:
var current = window.getComputedStyle(col,null);
It is likely that in your current case, the code is throwing an 'argument count' error in the timeout handler, which prevents further execution and thus, never clears the timeout.
Alternatively, you may want to do your loop counting at the start of your loop, as such:
function animeColumn(index, col) {
var timerID = window.setInterval(function () {
if (iter++ == 5) {
window.clearInterval(timerID);
}
var current = window.getComputedStyle(col);
var matrix = new WebKitCSSMatrix(current.webkitTransform);
col.style.webkitTransform = matrix.translate(10, 0);
}, 50);
}

I think it is because your var timerID is not defined at window's level
var mydiv = document.getElementById('news-variety');
var iter = 0;
var timerID;
if (mydiv) {
var columns = mydiv.getElementsByTagName('DIV');
function animeColumn(index, col) {
timerID = window.setInterval(function () {
var current = window.getComputedStyle(col);
var matrix = new WebKitCSSMatrix(current.webkitTransform);
col.style.webkitTransform = matrix.translate(10, 0);
if (iter++ == 5) {
window.clearInterval(timerID);
}
}, 50);
}
for (var i = 0; i < columns.length; i++) {
if (columns[i].className.toLowerCase() == "column") {
columns[i];
animeColumn(i, columns[i]);
}
}
}

iter is global, so it will reach 5 for only one of multiple columns.
Try moving it into the function like this:
function animeColumn(index, col) {
var iter = 0;
var timerID = window.setInterval(function () {
// ...
if (iter++ == 5) {
window.clearInterval(timerID);
}
}, 50);
}

i have created a fiddle for this http://jsfiddle.net/DXSNp/

Related

setInterval Function does not execute

I am working on a game using HTML and Javascript. And I need a function to be called every 2 seconds. I tried using setInterval but the function is not being called. And the browser console does not show any errors.
function Apples() {
this.Apples = [];
this.indexCount = 0;
this.CurrentTime;
this.createApples = function() {
this.Apples[this.indexCount] = new Apple();
this.indexCount++;
}
this.updateApples = function() {
for (var i = 0; i < this.indexCount; i++) {
this.Apples[i].positionY += 1;
this.Apples[i].drawApple();
}
}
}
var apples = new Apples;
setInterval(apples.createApples, 200);
It does not work because of the context of this and your code is 200 milliseconds, not 2 seconds.
function Apple () {
return {
positionY: 0,
drawApple: function () {}
}
}
function Apples() {
this.Apples = [];
this.indexCount = 0;
this.CurrentTime;
this.createApples = function() {
this.Apples[this.indexCount] = new Apple();
this.indexCount++;
console.log("new index", this.indexCount);
}
this.updateApples = function() {
for (var i = 0; i < this.indexCount; i++) {
this.Apples[i].positionY += 1;
this.Apples[i].drawApple();
}
}
}
var apples = new Apples;
// use bind
// setInterval(apples.createApples.bind(apples), 2000);
// or use function
setInterval(() => apples.createApples(), 2000);
//setInterval(function () { apples.createApples(); }, 2000);

simon game doing a sequence of 3 in level 2

I'm working on a simon game and is doing a sequence of 3 at level 2 instead of doing just 2 at level 2. I've looked all over. and I've trying output to console, but I guess I've been staring at this for too long. If someone can find the bug, please share. thanks for the help.
here's the pen
https://codepen.io/zentech/pen/XaYygR
//variables
userSeq = [];
simonSeq = [];
const NUM_OF_LEVELS = 5;
var id, color, level = 0;
var strict = false;
var error = false;
var boardSound = [
"http://www.soundjay.com/button/sounds/button-4.mp3", //green
"http://www.soundjay.com/button/sounds/button-09.mp3", //red
"http://www.soundjay.com/button/sounds/button-10.mp3", //yellow
"http://www.soundjay.com/button/sounds/button-7.mp3" //blue
];
//1- start board sequence
$(document).ready(function() {
$(".start").click(function() {
strict = false;
error = false;
level++;
simonSeq = userSeq = [];
simonSequence();
})
//user pad listener
$(".pad").click(function() {
id = $(this).attr("id");
color = $(this).attr("class").split(" ")[1];
userSequence();
});
//strict mode listener
$(".strict").click(function() {
level = 0;
level++;
simonSeq = userSeq = [];
strict = true;
simonSequence();
})
})
//user sequence
function userSequence() {
userSeq.push(id);
console.log(id+" "+color);
addClassSound(id, color);
//check user sequence
if(!checkUserSeq()) {
//if playing strict mode reset everything lol
if(strict) {
console.log("strict");
simonSeq = [];
level = 1;
}
displayError();
userSeq = [];
error = true;
console.log("start simon error")
simonSequence();
}
//checking end of sequence
else if(userSeq.length == simonSeq.length && userSeq.length < NUM_OF_LEVELS) {
level++;
userSeq = [];
error = false;
console.log("start simon")
simonSequence();
}
//checking for winners
if(userSeq.length == NUM_OF_LEVELS) {
displayWinner();
resetGame();
}
}
/* simon sequence */
function simonSequence() {
console.log("level "+level);
$(".display").text(level);
if(!error) {
getRandomNum();
}
var i = 0;
var myInterval = setInterval(function() {
id = simonSeq[i];
color = $("#"+id).attr("class");
color = color.split(" ")[1];
console.log(id+" "+color);
addClassSound(id, color);
i++;
if(i == simonSeq.length) {
clearInterval(myInterval);
}
}, 1000);
}
//generate random number
function getRandomNum() {
var random = Math.floor(Math.random() * 4);
simonSeq.push(random);
}
/* add temporary class and sound */
function addClassSound(id, color) {
$("#"+id).addClass(color+"-active");
playSound(id)
setTimeout(function(){
$("#"+id).removeClass(color+"-active");
}, 500);
}
/* checking user seq against simon's */
function checkUserSeq() {
for(var i = 0; i < userSeq.length; i++) {
if(userSeq[i] != simonSeq[i]) {
return false;
}
}
return true;
}
/* display error */
function displayError() {
console.log("error");
var counter = 0;
var myError = setInterval(function() {
$(".display").text("Err");
counter++;
if(counter == 3) {
$(".display").text(level);
clearInterval(myError);
userSeq = [];
counter = 0;
}
}, 500);
}
//display winner
function displayWinner() {
var count = 0;
var winInterval = setInterval(function() {
count++;
$(".display").text("Win");
if(count == 5) {
clearInterval(winInterval);
$(".display").text("00");
count = 0;
}
}, 500);
}
/* play board sound */
function playSound(id) {
var sound = new Audio(boardSound[id]);
sound.play();
}
/* reset game */
function resetGame() {
userSeq = [];
simonSeq = [];
level = 0;
strict = false;
$(".display").text("00");
}
PROBLEM
You have a reference vs copy problem in your initialization code.
$(document).ready(function() {
$(".start").click(function() {
strict = false;
error = false;
level++;
simonSeq = userSeq = []; //PROBLEM !!!!
simonSequence();
})
Arrays are passed by reference, not value.
simonSeq = userSeq = [];
/* Any changes to 'userSeq' will affect 'simonSeq'.
'simonSeq' is referencing 'userSeq' */
SOLUTION
Change all instances of
simonSeq = userSeq = [];
To
simonSeq = [];
userSeq = [];
EXPLINATION
Values in JavaScript can be referred to in 2 ways; by reference and by value.
When you refer to something by value, you are copying it.
var numA = 5;
var numB = numA; //COPY numA over to numB
numA = 12; // Changes to numA will not affect numB because it was copied
console.log(numA); // 12
console.log(numB); // 5
When you refer to something by reference, your are referring/referencing it, not copying it. Any changes made to the original will affect everything that is referencing it.
var original = [1,2,3];
var ref = original; //Any changes made to 'original' will affect 'ref'
original.push('APPLES');
console.log(original); // [1,2,3,'APPLES']
console.log(ref); // [1,2,3,'APPLES']
In the above code ref does not actually contain any values. ref contains the memory location of original.
ref is referencing original.
Arrays and Objects are always passed/refereed to by reference.
Everything else is passed/refereed to by value (they are copied).

Put a number of spheres in an animation with the same distance

I have a code that performs animation. a sphere moves from the beginning of a line to the end of the line. When starts again ends the motion again. starts from the first vertex and ends at the last vertex of the line.
I want to put 20 or so spheres, doing the same animation, but at the same time and in the same distance.
How can I do it?
this is my code:
var vertices = mesh.geometry.vertices;
var duration = 10;
function startToEnd() {
var i = 0;
async.eachSeries(vertices, function(vertice, callback) {
if (i !== 0) {
sphere.position.copy(vertices[i - 1]);
new TWEEN.Tween(sphere.position).to(vertices[i], duration).delay(duration).onComplete(function() {
callback(null);
}).start();
} else {
callback(null);
}
i++;
}, startToEnd);
}
startToEnd();
this image is a example..
this is result of my code
I got something that I think is pretty close to what you want:
var vertices = mesh.geometry.vertices;
var duration = 20;
var spheres = [];
var amountOfSpheres = 20;
for (var i = 0; i < amountOfSpheres; i++) {
spheres.push(new THREE.Sprite(rttMaterial));
scene.add(spheres[i]);
}
function endlessArrayIndex(index, arrayLength) {
if (index >= arrayLength) {
return index % arrayLength;
}
return index;
}
function startToEnd() {
i = 0;
async.each(spheres, function(sphere, cb1) {
var j = 0;
var verticeIndex = endlessArrayIndex(i * Math.round(vertices.length / amountOfSpheres), vertices.length);
async.eachSeries(vertices, function(vertice, cb2) {
if (verticeIndex !== 0) {
var verticeToCopy = vertices[verticeIndex - 1];
sphere.position.copy(verticeToCopy);
new TWEEN.Tween(sphere.position).to(vertices[verticeIndex], duration).delay(duration).onComplete(function() {
cb2(null);
}).start();
} else {
cb2(null);
}
verticeIndex = endlessArrayIndex(verticeIndex + 1, vertices.length);
}, cb1);
i++;
}, startToEnd);
}
startToEnd();
Result of the above code:

Set delay time for a loop execution

I'm trying to delay the execution of a loop by 3000ms, this is my code so far, but I keep on getting an error, does anyone can tell me why I'm getting error? Thanks in advance.
function contrEmpty(x,y,ev) {
setTimeout(function () {for (var i=0; i<=4; i++) {
if ((table[x+i+1][y] != 'R') && (table[x+i+1][y] != 'Y')) {
table[x+i+1][y] = table[x+i][y];
table[x+i][y] = 0;
var ultPosX = x+i+1;
var ultPosY = y;
var data = ev.dataTransfer.getData("text");
var dest=document.getElementById((x+i).toString()+y.toString()).childNodes;
var dom=document.getElementById((x+i).toString()+y.toString());
dom.removeChild(dest[0]);
var newRR= document.getElementById((x+i+1).toString()+(y).toString()).appendChild(document.getElementById(data).cloneNode(true));
}
}
}, 3000);
var cell = ev;
}

setTimeout in a loop and pass variables to use later

Consider the following code:
function func() {
var totalWidths = 0;
for( var i = 0, count = arr.length; i < count; i++ ) {
var image = arr[i];
insertElemInDOM(image);
preloadImage(image,function(){
var w = image.width();
totalWidths += w;
});
}
// do something with the variable "totalWidths"
doSomething(totalWidths)
}
I have 2 problems here. The image will be always the same (first problem), which one can solve with an anonymous function:
for(...) {
(function(image) {
preload(image,function() {
// now image is the correct one
});
})(image);
}
But how do I manage the totalWidths variable in order to use it later on doSomething(totalWidths)? The previous code would have a value of 0 for totalWidths.
Thanks!
You could timeout the whole loop and the doSomething, that's much more performant than setting up so many timeouts:
setTimeout(function() {
var inc = 0;
for (var i = 0; i < count; i++) {
var w = arr[i].width();
inc++;
}
doSomething(inc);
}, 1000);
However, what you actually seem to want are nested timeouts, i.e. waiting 1s for each iteration step and doing something after all have finished:
var inc = 0, count;
function asyncLoop(i, callback) {
if (i < count) {
var w = arr[i].width();
inc++;
setTimeout(function() {
asyncLoop(i+1, callback);
}, 1000);
} else {
callback();
}
}
asyncLoop(0, function() {
doSomething(inc);
});
OK, now that we know what you need the solution is to check after each load event whether all images are loaded:
var totalWidths = 0,
count = arr.length,
loaded = 0;
for (var i = 0; i < count; i++)
(function (image) {
insertElemInDOM(image);
preload(image, function() {
totalWidths += image.width();
// counter:
loaded++;
if (loaded == count-1) // the expected value
doSomething(totalWidths); // call back
});
})(arr[i]);

Categories