Recursion prevents function from being clicked more times in a row - javascript

I have created a simple script using recursion, to change the position of images.
It loop throught them and adjust their position , the script is relative easy code :
var img = document.getElementsByClassName("container")[0];
var X = 0;
var Y = 0;
var check;
function all() {
var decko = img.children;
for (var i = 0; i < decko.length; i++) {
if (i !== 0 && i % 3 === 0) {
X = 0;
Y++;
}
decko[i].style.transform = "translate3d(" + X * 100 + "px," + Y * 100 + "px,0)";
X++;
}
X = 0;
Y = 0;
check = false;
}
all()
window.onclick = function() {
pushIt(img.length, img.children, 0, 0)
}
function pushIt(max, target, index, count) {
if (count == max) {
return;
}
var tmp = target[index];
var matrix =window.getComputedStyle(tmp).getPropertyValue("transform");
var translate_left=matrix.split(",")[4];
var translate_top=matrix.split(",")[5].split(")")[0]-100;
tmp.style.transform = "translate3d(" + translate_left + "px," + translate_top + "px,0)";
setTimeout(function(){
pushIt(max, target, index + 1, count + 1);
},150)
}
Here you can see how it works. The problem is when there are a lot of images.
When i click which invokes the function , it loops throught all images ( 30 + in my case ). If i click two times in a sec , it will loop throught the all images , and THEN it will execute the function 2 nd time which is in my case unwanted behavior ( looks laggy ). Is there any way to prevent this behavior? I have chosen recursion , bcs it seems like easiest choice for this.

You had a couple if issues with your JavaScript that were throwing some errors, namely max was undefined in your function. I got this working HERE
var img = document.getElementsByClassName("container")[0];
var decko = img.children;
var X = 0;
var Y = 0;
var check;
var running = false;
function all() {
for (var i = 0; i < decko.length; i++) {
if (i !== 0 && i % 3 === 0) {
X = 0;
Y++;
}
decko[i].style.transform = "translate3d(" + X * 100 + "px," + Y * 100 + "px,0)";
X++;
}
X = 0;
Y = 0;
check = false;
}
all()
window.onclick = function () {
if (!running) {
running = true;
pushIt(decko.length, img.children, 0, 0);
}
}
var pushIt = function (max, target, index, count) {
if (count == max) {
running = false;
return;
}
var tmp = target[index];
var matrix = window.getComputedStyle(tmp).getPropertyValue("transform");
var translate_left = matrix.split(",")[4];
var translate_top = matrix.split(",")[5].split(")")[0] - 100;
tmp.style.transform = "translate3d(" + translate_left + "px," + translate_top + "px,0)";
setTimeout(function () {
console.log(running);
pushIt(max, target, index + 1, count + 1);
}, 150)
}

Related

Uncaught TypeError: current.distance is not a function

I'm developing a little game of nothing at all more commonly called "Pathfinding"; and I am crashing on a small error that I have never encountered (I am young dev);
I have searched everywhere but I do not understand why this error appears.
I am experiencing this error:
Uncaught TypeError: current.distance is not a function
at search_min_distance (pathfinding.js:127)
at game (pathfinding.js:151)
at HTMLDocument. (pathfinding.js:173)
document.addEventListener("DOMContentLoaded", function() {
const NBR_POINT = 10;
const MIN_SPACING = 100;
const HEIGHT = window.innerHeight;
const WIDTH = window.innerWidth;
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
function random(mode) {
if (!mode)
return Math.random() * ((WIDTH - 100) - 100) + 100;
else
return Math.random() * ((HEIGHT - 100) - 100) + 100;
}
function printPoint(stk, crt) {
var block = 0;
do {
block = 0;
var x = random(0);
var y = random(1);
if (stk.length != 0) {
for (let i = 0; i < stk.length; i++) {
if (x < (stk[i].x + MIN_SPACING) && x > (stk[i].x - MIN_SPACING) && y < (stk[i].y + MIN_SPACING) && y > (stk[i].y - MIN_SPACING)) {
block = 1;
break;
}
}
}
} while (block == 1);
var ids = stk.length + 1;
if (crt == "current")
var p = new point(x, y, "point courant", ids);
else
var p = new point(x, y, "point", ids);
p.part.style.bottom = p.y + "px";
p.part.style.left = p.x + "px";
document.body.appendChild(p.part);
return p;
}
function polyPoint() {
var stk = new Array();
for (let i = 0; i < NBR_POINT - 1; i++) {
stk.push(printPoint(stk, null));
}
printPoint(stk, "current");
return stk;
}
function imp_session() {
var dark_status = sessionStorage.getItem('dark_mode');
if (dark_status == 1)
document.body.classList.add("darkmode");
if (dark_status == 0)
document.body.classList.remove("darkmode");
}
function srv_DarkMode() {
document.addEventListener("keypress", function(event) {
let keypress = event.key;
var dark_status = sessionStorage.getItem('dark_mode');
if (keypress == "d") {
if (dark_status == null) {
dark_status = 0;
sessionStorage.setItem('dark_mode', dark_status);
}
if (dark_status == 1) {
this.body.classList.remove("darkmode");
dark_status = 0;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
} else {
this.body.classList.add("darkmode");
dark_status = 1;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
}
}
});
}
function search_min_distance(stk, current) {
let min = current.distance(stk[0]);
let tmp;
let real = min;
for (let i = 1; i < stk.length; i++) {
if (stk[i].id = current.id)
continue;
tmp = current.distance(stk[i]);
if (tmp < min)
real = i;
}
return real;
}
function game(stk) {
var cp = document.getElementsByClassName('courant');
cp[0].addEventListener("click", function(event) {
alert("txt");
});
var distId = search_min_distance(stk, cp[0]);
var p = document.getElementsByClassName('point');
for (let i = 0; i < p.length; i++) {
if (p[i].id != cp[0].id || p[i].id != distId) {
p[i].addEventListener("click", function(event) {
alert("txt");
});
}
}
}
function init() {
imp_session();
srv_DarkMode();
return polyPoint();
}
game(init());
});
-> current and stk [0] are indeed of "type" point.
All the remaining code does not seem important to me, but if necessary I will provide it.
I thank you in advance ! Be indulgent...
The point you are getting using the getElement function just returns
the js object, it does not contain any functions from the class.
You need to create a new class instance from this obtained point as follows inside the search_min_distance function
const { x, y, name, id } = current;
const currentPoint = new Point(x, y, name, id);
let min = currentPoint.distance(stk[0]);
I suggest you write a util function to calculate the distance between two points, passing the two points as arguments. It will be a cleaner approach.
Bind distance function to this inside constructor
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
// bind distance method
this.distance = this.distance.bind(this);
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
The name of error is "TypeError". And That's not just for fun. Possible problems in search_min_distance:
stk is not defined or its length is 0
stk is not array of points (typeof point[])
point is not defined or it's not point (typeof point)
Sure problems:
point.id is not defined, it's only in point.part
if (stk[i].id = current.id)
to
if (stk[i].part.id = current.part.id)
Your code is only errors.
Finally all this for a simple mistake of inattention; I took dom for my array and put an assignment where there should have been an equal .. thanks everyone.
if (stk[i].id = current.id)
as
if (stk[i].id == current.id)
and
var distId = search_min_distance(stk, cp[0]);
as
var distId = search_min_distance(stk, stk[cp[0].id]);

Javascript not waiting for onclick

I am trying to execute this code but for some reason that I cannot figure out the RoundRobin function will execute onload rather than onclick. I have tried removing window.onload or replacing it with document.onload. All I want is for this line document.getElementById("tableButton").onclick = RoundRobin(teamsIn); to wait for the onclick trigger.
var selectedTeams = [];
window.onload = function() {
// JavaScript Document
// add selected teams to array
var teamList = document.getElementById("teamDropdown");
teamList.onchange = function addTeams() {
if (selectedTeams.length > 7) {
alert("no more teams")
} else {
var county = document.getElementById("teamDropdown").value;
selectedTeams.push(county);
}
alert("counties selected are: " + selectedTeams);
}
var teamsIn = 0;
teamsIn = selectedTeams.length;
document.getElementById("tableButton").onclick = RoundRobin(teamsIn);
// slideshow.
var imageArray = new Array();
imageArray[0] = new Image()
imageArray[0].src = "Sponsors/aib.png"
imageArray[1] = new Image()
imageArray[1].src = "Sponsors/centra.jpg"
imageArray[2] = new Image()
imageArray[2].src = "Sponsors/eircom.png"
imageArray[3] = new Image()
imageArray[3].src = "Sponsors/etihad.png"
imageArray[4] = new Image()
imageArray[4].src = "Sponsors/liberty.jpg"
imageArray[5] = new Image()
imageArray[5].src = "Sponsors/supervalu.png"
var step = 0;
function slideShow() {
document.getElementById('slideshow').src = imageArray[step].src
if (step < 5)
step++
else
step = 0
setTimeout("slideShow()", 4000)
}
function RoundRobin(teams) {
alert(teams);
var i;
var ret = "";
var round;
var numplayers = 0;
numplayers = parseInt(teams) + parseInt(teams % 2);
numplayers = parseInt(numplayers);
alert(numplayers);
var a = new Array(numplayers - 1);
var alength = a.length;
for (var x = 0; x < (numplayers); x++) {
a[x] = "Team " + (x + 1);
}
if (numplayers != parseInt(teams)) {
a[alength] = "BYE";
}
var pos;
var pos2;
ret = "----- ROUND #1-----<br />"
for (var r1a = 0; r1a < (numplayers / 2); r1a++) {
ret += a[r1a] + " vs. " + a[alength - r1a] + "<br />"
}
for (round = 2; round < alength + 1; round++) {
ret += "<br /><br />----- ROUND #" + round + "-----<br />"
ret += a[0] + " vs. " + a[alength - (round - 1)] + "<br />"
for (i = 2; i < (numplayers / 2) + 1; i++) {
pos = (i + (round - 2))
if (pos >= alength) {
pos = ((alength - pos)) * -1
} else {
pos = (i + (round - 2))
}
pos2 = (pos - (round - 2)) - round
if (pos2 > 0) {
pos2 = (alength - pos2) * -1
}
if (pos2 < (alength * -1)) {
pos2 += alength
}
ret += a[(alength + pos2)]
ret += " vs. " + a[(alength - pos)] + "<br />"
}
}
var text = document.getElementById('fixtures');
text.innerHTML = ret;
return ret
}
// round robin format
}
What's happening is that you call the function, then you assing the return value to the onclick property. For the event handler to work you need to assign a function to the property.
Wrap the call in a function expression:
document.getElementById("tableButton").onclick = function(){
RoundRobin(teamsIn);
};

How to display a div with random ID without repeating it using jQuery?

I have a function to select a random number from 0 to 45 and then I show the div with the specific ID. It's working fine but it repeats a number.
Can anyone advise so it won't repeat numbers?
I call the function onclick like this
$(".skip").click(function () {
scared++;
$("#counter").html("My current count is: " + dared);
var d = 50;
/*$(".question").addClass("hideMe");
$(this).parents("div").next("div").removeClass("hideMe");*/
var r = Math.round(Math.random() * 44) + 1;
var newquestion = "q" + r;
$('.active').removeClass("active");
$("#" + newquestion).addClass("active");
if (scared > 44) {
$('.main').fadeOut('fast');
$('.logo').switchClass("logo", "share");
$('.progress').css("display", "none");
$('.share-game').css("display", "block");
$('.hero').css("right", "-240px");
$('#score-total').html(score + '');
} else {
}
$('.red-line').append('<div id="children' + (d++) + '" class="red"></div>');
return false;
});
You can see what i did.
var usedNumbers = [];
var randomNumbers = [];
$(function() {
//Getting 20 random numbers
for (i = 0; i < 20; i++) {
randomNumbers.push(getRandomNumber());
}
console.log(randomNumbers);
function getRandomNumber() {
var hasInArray = true;
do {
var r = Math.round(Math.random() * 44) + 1;
if (usedNumbers.indexOf(r) === -1) {
usedNumbers.push(r);
hasInArray = false;
return r;
}
} while (hasInArray === true);
}
});
Warning to not set the numbers of randomnumbers more then what you want to get, because that will cause an infinite loop!
Use an array to capture the used numbers and then check that array on each click, generating a new number if that one is found. It resets back to an empty array when it is full.
var savedNumbers = [];
function getRandom() {
if (savedNumbers.length === 45) {
savedNumbers = [];
}
var r = Math.round(Math.random() * 44) + 1;
if (savedNumbers.indexOf(r) > -1) {
getRandom();
} else {
savedNumbers.push(r);
return r;
}
}
DEMO

How to submit the value of an input field?

I have a math game that works partially. What I need to have happen is to take the values of the divs (one is x and the other is y), type in the answer of those two multiplied, be able to submit it and refresh to solve another.
Any help would be much appreciated!
http://jsfiddle.net/justinw001/Mttw6/11/
<script type="text/javascript">
function myFunction() {
score = 0;
var number = document.getElementById('inputElement').value;
questionAmount = number;
for(i = 0; i < questionAmount; i++) {
var x = Math.floor(Math.random() * 13);
var y = Math.floor(Math.random() * 13);
$('#input1').text(x);
$('#input2').text(y);
<!-- question = prompt('What is ' + x + ' * ' + y + ' = ?'); -->
question = document.getElementById('answer').value;
if(question == null || isNaN(question)) {
break;
}
if(question == x * y) {
score++;
}
}
alert('You got ' + score + ' out of ' + questionAmount + ' correct.');
}
</script>
Try to bind the process with your buttons. Clicking the left button, produce the questions.
And Clicking the right one, verify the answer.
Demo: Fiddle
var score = 0;
var questions = [];
// Generate questions
$('#gen').click(function () {
score = 0;
questions = [];
var questionAmount = parseInt($('#inputElement').val(), 10);
for (var i = 0; i < questionAmount; i++) {
var q = {
x: Math.floor(Math.random() * 13),
y: Math.floor(Math.random() * 13)
};
questions.push(q);
}
nextQuest(questions.pop());
});
// Verify the answer
$('#sub').click(function () {
var ans, x, y;
if (questions.length >= 0) {
ans = parseInt($('#answer').val(), 10);
x = parseInt($('#input1').text(), 10);
y = parseInt($('#input2').text(), 10);
if (ans === x * y) {
score++;
nextQuest(questions.pop());
} else {
alert('err');
}
}
});
var nextQuest = function (q) {
if (q) {
$('#input1').text(q.x);
$('#input2').text(q.y);
$('#answer').val('');
$('#inputElement').val(questions.length);
} else {
$('#input1, #input2').text('');
$('#answer, #inputElement').val('');
alert(score);
}
};

JQuery - getting mixed up with variable scope in parameter functions

JSFiddle - SSCCE
function restoreTitle() {
for (var i = 0; i < 4; i++) {
clicks[i] = false;
letter = $('#title-wrapper p[index="' + i + '"]');
letter.css('cursor', "pointer");
}
animateTitle();
}
function animateTitle() {
for (var i = 0; i < 4; i++) {
letter = $('#title-wrapper p[index="' + i + '"]');
direction = i < 2 ? 1 : -1;
letter.css('right', 50 * direction + "%");
doAnimateLetter(i, letter, direction);
}
}
function doAnimateLetter(i, letter, direction) {
loop(function(){
var current = letter.css('right').replace("%", "");
var incoming = parseInt(current) - (5 * direction);
letter.css('right', incoming + "%");
var completed = incoming == 0;
if(completed) letter.fadeTo(animation_speed, 1);
return !completed;
});
}
function loop(run) {
if (run.apply()) requestAnimationFrame(function () {
loop(run);
});
}
What I would like to achieve is for the two left letters to fly in from the left and for the two right ones to fly in from the right. I can't find where I'm going wrong.

Categories

Resources