So, I'm very new, so apologies if this is a silly question. I have worked out a Trivia Quiz for my learning to code classes I'm taking. I want to display an image on the confirmation screen that shows whether the user was right or wrong. I think the code is correct-ish? I'm not sure what isn't working.
I left out the main Question and answer object for space. Sorry if I didn't format this ideally? I'm still kinda figuring out how things work here.
Here is my code for reference:
//array to help me iterate and insert images
var imgArray = ["question1", "question2", "question3", "question4", "question5", "question6", "question7", "question8", "question9", "question10", "question11", "question12", "question13"];
var currentQuestion = 0;
var win = 0;
var lose = 0;
var unanswered = 0;
var time = 30;
//set up divs to contain our info
var rightDiv = $("<div class='rightAns'></div>");
var timerDiv = $("<div class='countdown'><h3></h3></div>");
var questionDiv = $("<div class='question'><h1></h1></div><br>");
var answerDiv = $("<div class='answers'></div>");
//object keys to return questions in order
var keys = Object.keys(questions);
var key = keys[n];
var n = 0;
//function to setup and restart game
function reset() {
$("#start-button").hide("slow");
$("#start-here").hide("slow");
win = 0;
lose = 0;
unanswered = 0;
n = 0;
key = keys[n];
currentQuestion = 0;
$("#question-block").empty();
var reset = function () {
time = 30;
$(".rightAns").empty();
$(".rightAns").remove();
// $("#image").empty();
$("#time-remaining").append(timerDiv);
$(".countdown h3").html("Time Remaining: " + time);
$("#question-block").append(questionDiv);
$("#question-block").append(answerDiv);
}
reset();
//function to show questions
function showQuestion() {
$(".question h1").html(questions[key].question);
for (var i = 0; i < questions[key].answers.length; i++) {
$(".answers").append("<button class='answer btn btn-danger btn-lg m-1'>" + questions[key].answers[i] + "</button>");
}
$(".answers button").on("click", function () {
var selected = $(this).text();
//if then to check question correctness
if (selected === questions[key].correct) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("That's Correct!!");
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
win++;
currentQuestion++;
} else {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("Nope! The correct answer was: " + questions[key].correct);
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
lose++;
currentQuestion++;
}
n++;
key = keys[n];
//checking to see if there are more questions left
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
});
}
showQuestion();
var counter = setInterval(count, 1000);
//show time remaining for each question
function count() {
time--;
$(".countdown h3").html("Time Remaining: " + time);
if (time < 1) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").html("You took too long! The correct answer was: " + questions[key].correct);
unanswered++;
n++;
key = keys[n];
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
}
}
function checkForLast() {
if (key === undefined) {
return true;
}
return false;
}
//timer for the message after you choose your answer
function countReset() {
counter = setInterval(count, 1000);
}
//showthe final score screen
function finalScore() {
$(".rightAns").remove();
$("#image").empty();
$("#question-block").prepend("<h2>Unanswered: " + unanswered + "</h2>");
$("#question-block").prepend("<h2>Incorrect: " + lose + "</h2>");
$("#question-block").prepend("<h2>Correct: " + win + "</h2>");
$("#start-button").show();
$("#start-here").show();
}
};
//function to start game on button click
$(document).on("click", "#start-button", reset);
});
After tinkering for a bit, I dropped the "." at the beginning of the call and added the .jpg to the section after imgArray[currentQuestion]. That solved it. Thanks for the suggestions.
Related
My game works until summary page start link is clicked. Then I get undefined variables when trying to play again.
I'm new to JS so I'm sure it is a stupid user error and not handling scope correctly.
If I comment the location.reload at the bottom of the javascript it works just fine after the timer is up, but the coding assignment wants us to not do a refresh. I appreciate any help!
$(document).ready(function() {
var correctAnswers = 0;
var incorrectAnswers = 0;
var unansweredQuestions = 0;
var timeRemaining = 16;
var intervalID;
var indexQandA = 0;
var answered = false;
var correct;
var start = $(".start").html("Start Game");
start.on("click", startGame);
var triviaQandA = [{
question: "What is the fastest animal?",
answer: ["cheetah", "turtle", "giraffe", "elephant"],
correct: "0",
image: ("assets/images/circle.png")
}, {
question: "When you are blue you turn?",
answer: ["red", "green", "blue", "yellow"],
correct: "2",
image: ("assets/images/dot.jpg")
}];
function startGame() {
$(".start").hide();
correctAnswers = 0;
incorrectAnswers = 0;
unansweredQuestions = 0;
loadQandA();
}
function loadQandA() {
answered = false;
timeRemaining = 16;
intervalID = setInterval(timer, 1000);
if (answered === false) {
timer();
}
correct = triviaQandA[indexQandA].correct;
var question = triviaQandA[indexQandA].question;
$(".question").html(question);
for (var i = 0; i < 4; i++) {
var answer = triviaQandA[indexQandA].answer[i];
$(".answers").append("<h4 class = answersAll id =" + i + ">" + answer + "</h4>");
}
$("h4").click(function() {
var id = $(this).attr("id");
if (id === correct) {
answered = true;
$(".question").text("The answer is: " + triviaQandA[indexQandA].answer[correct]);
correctAnswer();
} else {
answered = true;
$(".question").text("You chose: " + triviaQandA[indexQandA].answer[id] + " the correct answer is: " + triviaQandA[indexQandA].answer[correct]);
incorrectAnswer();
}
console.log(correct);
});
}
function timer() {
if (timeRemaining === 0) {
answered = true;
clearInterval(intervalID);
$(".question").text("The correct answer is: " + triviaQandA[indexQandA].answer[correct]);
unAnswered();
} else if (answered === true) {
clearInterval(intervalID);
} else {
timeRemaining--;
$(".timeRemaining").text("You have " + timeRemaining);
}
}
function correctAnswer() {
correctAnswers++;
$(".timeRemaining").text("You are spot on!!!").css({
"color": "#3d414f"
});
reset();
}
function incorrectAnswer() {
incorrectAnswers++;
$(".timeRemaining").text("You are sooo wrong").css({
"color": "#3d414f"
});
reset();
}
function unAnswered() {
unansweredQuestions++;
$(".timeRemaining").text("You didn't choose anything...").css({
"color": "#3d414f"
});
reset();
}
function reset() {
$(".answersAll").remove();
$(".answers").append("<img class=answerImage width='150' height='150' src='" + triviaQandA[indexQandA].image + "'>");
indexQandA++;
if (indexQandA < triviaQandA.length) {
setTimeout(function() {
loadQandA();
$(".answerImage").remove();
}, 2000);
} else {
setTimeout(function() {
$(".question").remove();
$(".timeRemaining").remove();
$(".answerImage").remove();
$(".answers").append("<h4 class = answersAll end>Correct answers: " + correctAnswers + "</h4>");
$(".answers").append("<h4 class = answersAll end>Wrong answers: " + incorrectAnswers + "</h4>");
$(".answers").append("<h4 class = answersAll end>Unanswered questions: " + unansweredQuestions + "</h4>");
correctAnswers = 0;
incorrectAnswers = 0;
unansweredQuestions = 0;
// setTimeout(function() {
// location.reload();
// }, 5000);
var start = $(".start-over").html("Start Game");
start.on("click", startGame);
}, 2000);
}
};
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div class="start"></div>
<h1>Trivia</h1>
<h5 class="timeRemaining"></h5>
<h3 class="question"></h3>
<div class="answers"></div>
<div class="start-over"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
Here's an inline link to my Codepen.
The problem comes from the fact that you increment indexQandA on each question, but never reset it. You need to reset it to 0 when starting a new game - that is, in the else clause of the reset function you need to put indexQandA=0 alongside where you reset the other variables to 0.
There is a further problem when this is done though, the quiz runs ok a second time now, but doesn't display the questions any more. That's because you've removed the .question element during reset. You don't need to do this, you can just hide it, then display it again when the game restarts.
Actually, it transpired there were further problems. I've solved it - run through the game about 5 times in a row with no obvious problems - with the following code (I make no claim that this is the correct code to do it, it's just minimal changes to your existing code to get it to work):
$(document).ready(function() {
var correctAnswers = 0;
var incorrectAnswers = 0;
var unansweredQuestions = 0;
var timeRemaining = 16;
var intervalID;
var indexQandA = 0;
var answered = false;
var correct;
var start = $(".start").html("Start Game");
start.on("click", startGame);
$(".start-over").on("click", startGame);
var triviaQandA = [{
question:"What is the fastest animal?",
answer:["cheetah","turtle","giraffe","elephant"],
correct:"0",
image: ("assets/images/circle.png")
}, {
question:"When you are blue you turn?",
answer:["red","green","blue","yellow"],
correct:"1",
image: ("assets/images/dot.jpg")
}];
function startGame() {
$(".summary").hide();
$(".start").hide();
$(".timeRemaining").show();
$(".question").show();
$(".answers").show();
$(".start-over").hide();
correctAnswers = 0;
incorrectAnswers = 0;
unansweredQuestions = 0;
loadQandA();
}
function loadQandA() {
answer = [];
answered = false;
timeRemaining = 16;
timer();
intervalID = setInterval(timer, 1000);
/*if (answered === false) {
timer();
}*/
correct = triviaQandA[indexQandA].correct;
var question = triviaQandA[indexQandA].question;
$(".question").html(question);
for (var i = 0; i < 4; i++) {
var answer = triviaQandA[indexQandA].answer[i];
$(".answers").append("<h4 class = answersAll id =" + i + ">" + answer + "</h4>");
}
$("h4").click(function() {
var id = $(this).attr("id");
if (id === correct) {
answered = true;
$(".question").text("The answer is: " + triviaQandA[indexQandA].answer[correct]);
correctAnswer();
} else {
answered = true;
$(".question").text("You chose: " + triviaQandA[indexQandA].answer[id] + " the correct answer is: " + triviaQandA[indexQandA].answer[correct]);
incorrectAnswer();
}
console.log(correct);
});
}
function timer() {
if (timeRemaining === 0) {
answered = true;
//clearInterval(intervalID);
$(".question").text("The correct answer is: " + triviaQandA[indexQandA].answer[correct]);
unAnswered();
} else if (answered === true) {
//clearInterval(intervalID);
} else {
timeRemaining--;
$(".timeRemaining").text("You have " + timeRemaining);
}
}
function correctAnswer() {
correctAnswers++;
$(".timeRemaining").text("You are spot on!!!").css({
"color": "#3d414f"
});
reset();
}
function incorrectAnswer() {
incorrectAnswers++;
$(".timeRemaining").text("You are sooo wrong").css({
"color": "#3d414f"
});
reset();
}
function unAnswered() {
unansweredQuestions++;
$(".timeRemaining").text("You didn't choose anything...").css({
"color": "#3d414f"
});
reset();
}
function reset() {
clearInterval(intervalID);
$(".answersAll").remove();
$(".answers").append("<img class=answerImage width='150' height='150' src='" + triviaQandA[indexQandA].image + "'>");
indexQandA++;
if (indexQandA < triviaQandA.length) {
setTimeout(function () {
loadQandA();
$(".answerImage").remove();
}, 2000);
} else {
setTimeout(function() {
$(".summary").show();
$(".question").hide();
$(".timeRemaining").hide();
$(".answers").hide();
$(".start-over").show();
$(".answerImage").remove();
$(".summary").append("<h4 class = answersAll end>Correct answers: " + correctAnswers + "</h4>");
$(".summary").append("<h4 class = answersAll end>Wrong answers: " + incorrectAnswers + "</h4>");
$(".summary").append("<h4 class = answersAll end>Unanswered questions: " + unansweredQuestions + "</h4>");
correctAnswers = 0;
incorrectAnswers = 0;
unansweredQuestions = 0;
indexQandA=0;
// setTimeout(function() {
// location.reload();
// }, 5000);
$(".start-over").html("Start Game");
start.on("click", startGame);
}, 2000);
}
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="start"></div>
<h1>Trivia</h1>
<h5 class="timeRemaining"></h5>
<h3 class="question"></h3>
<div class="answers"></div>
<div class="summary"></div>
<div class="start-over"></div>
</body>
</html>
There were 2 main problems with your code as it initially was:
most seriously, you were adding startGame as the click handler for the "start over" button each time the reset function was called. As a result, multiple such handlers were getting added by the time you played a 3rd, 4th, 5th... time, with the result that the startGame function was getting called multiple times, which was why you were getting the answer options printed multiple times. I've fixed this by removing that section of code entirely, and adding the event listener once, on page load.
your timer was also going a bit haywire, as you were calling the timer function manually as well as using setInterval to run it every second, and nor were you always clearing it when the question was answered. I've simplified this greatly, and made it work, just by setting the timer in loadQandA, as before, and clearing it in the reset function.
You will see that I've mainly just commented things out, rather than removed them - this will hopefully make it easier to see what I've removed.
Okay, so i am making a lobby function for an online 4 player game. Everything is set, and when all 4 players join the lobby, I want to start a countdown of 10 seconds for the players to click on accept match making on client side.(inspired from csgo)
I use ajax to call upon and refresh lobby data from a php file, so live statistics show up of who is in the lobby.
This goes in a loop, and here occurs the problem. I want the countdown function to be called when all 4 players have joined, and to stop it immediately if a player leaves, but as the parent function goes in a loop, (using set interval in javascript), it also repeatedly calls the countdown function.
Tried this, but does not help.
function loadlobbymodule(x){
var spl = x.split(",");
var lid = spl[1];
$.ajax({
url: 'inc/fn/lobbyload.php?lid='+ lid,
success: function(data) {
var spl = data.split(",");
var p1 = spl[0];
var p2 = spl[1];
var p3 = spl[2];
var p4 = spl[3];
var pl = spl[4];
var pleft = 4 - pl;
var p1_i = spl[5];
var p2_i = spl[6];
var p3_i = spl[7];
var p4_i = spl[8];
if(p1!=''){
$('#slot1').html('<img src="../../img/' + p1_i +'" width="100px" height="100px"><Br><br>' + p1);
} else{
$('#slot1').html('');
}
if(p2!=''){
$('#slot2').html('<img src="../../img/' + p2_i +'" width="100px" height="100px"><Br><br>' + p2);
}else{
$('#slot2').html('');
}
if(p3!=''){
$('#slot3').html('<img src="../../img/' + p3_i +'" width="100px" height="100px"><Br><br>' + p3);
}else{
$('#slot3').html('');
}
if(p4!=''){
$('#slot4').html('<img src="../../img/' + p4_i +'" width="100px" height="100px"><br><br>' + p4);
}else{
$('#slot4').html('');
}
$('#slotl').html(pleft + ' players left to join.');
if(pl == 4){
var accept = 1;
} else{
var accept = 0;
}
//alert(accept + ' sent');
accepto(accept);
}
});
}
function accepto(x){
//alert(x + ' reached');
if (x == 1){
if (!timeleft){
timeleft = 10;
var downloadTimer = setInterval(function(){
timeleft--;
$('.h3').html('All players joined. Accept in ' + timeleft + ' seconds');
if(timeleft <= 0)
clearInterval(downloadTimer);
},1000);
}
} else {
$('.h3').html('Waiting for players to join');
}
}setInterval(function(){loadlobbymodule(loll)}, 500);
Make the timer global and keep checking for active players
window.myGlobalTimer = yourTimer()
listening_PlayerThatLeave : ()=>{
clearTimeout(myGlobalTimer)
}
listening_AllPlayersIn : ()=>{
window.myGlobalTimer
}
/* dont keep making a new timeOut everytime , instead use the global var*/
function accepto(x){
//alert(x + ' reached');
if (x == 1){
if (!timeleft){
timeleft = 10;
//here
var downloadTimer = setInterval(function(){
timeleft--;
$('.h3').html('All players joined. Accept in ' + timeleft + ' seconds');
if(timeleft <= 0)
clearInterval(downloadTimer);
},1000);
}
} else {
$('.h3').html('Waiting for players to join');
}
}
I have a div with a next and previous button
<div class="b1"></div>
<input type="button" class="btnP" value="Prev"/>
<input type="button" class="btnN" value="Next"/>
and a list of css classes
.b1 { background-color:#fff;}
.b2 { background-color:#000;}
.b3 { background-color:#123;}
.b4 { background-color:#444;}
.b5 { background-color:#bbb;}
which i want to use for that div when the user press the next or previous button by that numbering order.
This is what i did so far:
http://jsfiddle.net/51dq5num/
var size_ini = 1;
$(".btnN").click(function () {
var size_increase = size_ini++;
var size_increase1 = size_ini;
$("#content").html("<span>" + size_increase + "</span>").removeClass().addClass("b" + size_increase);
if (size_increase > 4) {
size_ini = 1;
}
});
I manage to get the next button working but i'm not sure how to do it for the previous button
Is there a better way to do this rather then adding and removing css classes from the div?
Try this :
$(".btnP").click(function () {
var size_increase = $("#content").attr("class").substring(2, 1);
size_increase--;
if (size_increase < 1) {
size_increase = 5;
}
$("#content").html("<span>" + size_increase + "</span>").removeClass().addClass("b" + size_increase);
});
jsFiddle : http://jsfiddle.net/51dq5num/7/
You can do something like this:
var newClass = function(div, next) {
div[0].className = div[0].className.replace(/b\d+/, "b" + newClass[next ? 'next' : 'prev']());
};
newClass.atual = 1;
newClass.last = 5;
newClass.next = function(){
this.atual = (this.atual == this.last ? 1 : this.atual + 1);
return this.atual;
};
newClass.prev = function(){
this.atual = (this.atual == 1 ? this.last : this.atual - 1);
return this.atual;
};
var myDiv = $("#content");
$(".btnN").click(function () {
newClass(myDiv, true);
});
$(".btnP").click(function () {
newClass(myDiv, false);
});
Jsfiddle here.
This is a combined solution for both buttons.
var size_ini = 0;
$("input[type='button']").click(function () {
if($(this).hasClass("btnN"))
{
size_ini=size_ini+1;
var c="b"+size_ini;
$("#content").removeClass().addClass(c).html("TG"+size_ini);
}
else
{
size_ini=size_ini-1;
var c="b"+size_ini;
$("#content").removeClass().addClass(c).html("TG"+size_ini);
}
});
Note as it is not mentioned i have not checked on the max condition thus btnP can increase the counter infinitely.You can put it in a condn and limit it to a max value.
http://jsfiddle.net/n8dLgh3L/1/
Here is js code to increase and decrease.
var size_ini = 0;
$(".btnN").click(function () {
if (size_ini > 4) {
size_ini = 1;
} else {
size_ini++
}
$("#content").html("<span>" + size_ini + "</span>").removeClass().addClass("b" + size_ini);
});
$(".btnP").click(function () {
var size_decrease = $("#content").attr("class").substring(1, 2);
if (size_decrease <= 1) {
size_decrease = 5;
} else {
size_decrease--;
}
$("#content").html("<span>" + size_decrease + "</span>").removeClass().addClass("b" + size_decrease);
});
You ca achieve this with the help of .substr() for incrementing the number of class. Have a look.
function Getnumber(classNumber,nav)
{
var no=0;
if(nav=="P")
{
no=parseInt(classNumber.substr(1,2))-1;
}
else
{
no=parseInt(classNumber.substr(1,2))+1;
}
return no;
}
$(".btnN").on("click",function(){
var oldClass=$('div').attr("class");
var num=Getnumber(oldClass,"N");
if(num<6)
$('div').addClass("b"+num).removeClass(oldClass);
});
$(".btnP").on("click",function(){
var oldClass=$('div').attr("class");
var num=Getnumber(oldClass,"P");
if(num>0)
$('div').addClass("b"+num).removeClass(oldClass);
});
Feel free to ask.
This script generate divs with cloud images that fly from left to right with random height and intervals. It generally works but it keeps incrementing divs "id" infinitely. I can't figure out how to reset the counter being safe that never two identical "id"s will exist in the same time.
function cloudgenerator(){
var nr=1;
var t1 = 20000;
var t2 = 50000;
function cloud(type,time,nr){
$("#sky").append("<div id=\"cloudFL"+nr+"\" class=\"cloud"+type+"\" ></div>");
setTimeout(function() {
$("#cloudFL"+nr).css({top:Math.floor(Math.random() * 400)+'px'}).animate({
left:'100%',
},time,'linear',function(){$(this).remove();
});
}, Math.floor(Math.random() * t1));
};
function wave(){
var tx = 0;
setInterval(function(){
cloud(1,t1,nr);
nr++;
var n = $( "div.cloud1" ).length;
$( "span" ).text( "There are " + n +" n and "+ tx +" tx")
if(tx < n){tx = n}
else(tx = 1)
},500);
};
wave()};
cloudgenerator()
In the bottom, there is an instruction that checks if number of divs is starting to drop and presents those values in span for debugging.
Quick and easy solutionYou could loop through the id's in JQuery, starting from the lowest number, until you find a JQuery selector that yields 0 results...
var newid = 0;
var i = 1;
while(newid == 0) {
if( $('#cloudFL' + i).length == 0 ) { newid = i; }
else { i++; }
}
JSFIDDLE DEMO
Alternative solution (scalable)
Given that you may have many clouds onscreen at one time, you could try this alternative approach.
This approach creates an array of 'used ids' and the wave function then checks if any 'used ids' are available before creating a new id for the cloud function. This will run quite a bit more efficiently that then above 'quick fix solution' in situations where many clouds appear on screen.
function cloudgenerator(){
var nr=1;
var t1 = 20000;
var t2 = 50000;
var spentids = [];
function cloud(type,time,id){
$("body").append('<div id="' + id + '" class="cloud' + type + '" >' + id + '</div>');
setTimeout(function() {
$('#'+id).css({top:Math.floor(Math.random() * 400)+'px'}).animate({
left:'100%',
},time,'linear',function(){
spentids.push( $(this).attr('id') );
$(this).remove();
});
}, Math.floor(Math.random() * t1));
};
function wave(){
setInterval(function(){
if(spentids.length == 0) {
cloud(1,t1,"cloudFL" + nr);
nr++;
} else {
spentids = spentids.sort();
cloud(1,t1,spentids.shift());
}
},500);
};
wave()};
cloudgenerator()
JSFIDDLE DEMO - ALTERNATIVE
Why not get the timestamp and add this to your id?
If you donĀ“t need the ids i would stick to #hon2a and just add the styling to the class and remove the ids.
And another solution:
You could make a check if ID xyz is used. Like this e.g.
var cloudCount = jQuery('.cloud20000').length + jQuery('.cloud50000').length + 10;
for(var i = 0; i <= cloudCount; i++) {
if(jQuery('#cloudFL' + i).length <= 0) {
nr = i;
return false;
}
}
cloud(1,t1,nr);
As a java script beginner, I wanted to try my hand at writing stop watch code and I wrote the following:
<!DOCTYPE html>
<html>
<body>
<p>A script on this page starts a stopwatch:</p>
<p id="demo"></p>
<button id="start-stop" onclick="myTimerFunction()">Start time</button>
<button id="resetter" style="visibility:hidden" onclick="resetTimer()">Reset</button>
<script>
var timer = new Object();
timer.hours = 0;
timer.minutes = 0;
timer.seconds = 0;
timer.milliseconds = 0;
timer.add = add;
function add() {
timer.milliseconds+=10;
if(timer.milliseconds == 1000) {
timer.seconds++;
timer.milliseconds = 0;
}
if(timer.seconds == 60) {
timer.minutes++;
timer.seconds = 0;
}
if(timer.minutes == 60) {
timer.hours++;
timer.minutes = 0;
}
}
timer.display = display;
function display () {
var str = "";
if(timer.hours<10) {
str += "0";
}
str += timer.hours;
str += ":";
if(timer.minutes<10) {
str += "0";
}
str += timer.minutes;
str += ":";
if(timer.seconds<10) {
str += "0";
}
str += timer.seconds;
str += ":";
/*var x = timer.milliseconds/10;
if(x < 10) {
str += "0";
}*/
if(timer.milliseconds<10) {
str += "0";
}
if(timer.milliseconds<100) {
str += "0";
}
str += timer.milliseconds;
return str;
}
timer.reset = reset;
function reset() {
timer.hours = 0;
timer.minutes = 0;
timer.seconds = 0;
timer.milliseconds = 0;
}
var myVar;
function start() {
timer.add();
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = timer.display() + "\t" + t;
}
function stop() {
clearInterval(myVar);
}
function resetTimer() {
stop();
timer.reset();
document.getElementById("demo").innerHTML = timer.display();
document.getElementById("start-stop").innerHTML="Start time";
document.getElementById("resetter").style.visibility="hidden";
}
function myTimerFunction() {
var x = document.getElementById("start-stop");
if(x.innerHTML.match("Start time")) {
document.getElementById("resetter").style.visibility="visible";
myVar = setInterval(function(){start()},10);
x.innerHTML="Stop time";
}
else if(x.innerHTML.match("Stop time")) {
stop();
x.innerHTML="Start time";
}
}
</script>
</body>
</html>
But, the problem is when I put the delay in setInterval(func,delay) as 1 and doing corresponding changes, it is not giving reliable timing for seconds. It is slower than a normal clock. It gives 'kind of' reliable timing for delay >= 10.
I checked for stop watch js scripts online but all of them use some or other form of Date() and set "delay" as "50", which I do not understand why, as of now. There is an answer here in SO which doesn't use Date() but it also has the same problem as mine. I could not comment there as I do not have enough reputation so I am asking a question instead.
So, my question is: Is it impossible to achive normal clock reliability, if we don't use Date() function? Else if it is possible, please help me improve this piece of code or please provide some pointers.
Thanks.
Here's how you'd do it without getTime, which you really shouldn't...
var ms = 0;
var intervalID;
function start() {
var freq = 10; // ms
intervalID = setInterval(function () {
ms += 10;
var myDate = new Date(ms);
document.getElementById('watch').innerHTML = myDate.getUTCHours() + ":" + myDate.getMinutes() + ":" + myDate.getSeconds() +
":" + myDate.getMilliseconds();
}, freq);
}
function stop() {
clearInterval(intervalID);
}
function reset() {
ms = 0;
myDate = new Date(ms);
document.getElementById('watch').innerHTML = myDate.getUTCHours() + ":" + myDate.getMinutes() + ":" + myDate.getSeconds() +
":" + myDate.getMilliseconds();
}
Fiddle
As you've found out setInterval/setTimeout is not reliable. You must use a native time library to get a reliable time.
Since you can't keep the time in JavaScript the idea is that you poll the time, and poll it often so that it looks close enough.
If you naively do:
setInterval(function () {
console.log((new Date()).getTime();
}, 1000); // 1 second
you will see that it will skip seconds.
A better approach is something like:
var last = 0;
setInterval(function () {
var now = Math.floor((new Date()).getTime() / 1000); // now in seconds
if (now !== last) {
console.log(now);
last = now;
}
}, 10); // 10ms
If you want more information as too why JavaScript timers are unreliable, read this great article.
http://ejohn.org/blog/how-javascript-timers-work/