jQuery cost counter giving strange output, using setInterval to loop an animation - javascript

I have a codepen which simply needs to have a counter where you count up pennies and pounds until the user clicks stop. The cost is calculated based on an hourly rate in the example (50).
Why am I getting strange issues whereby the counter resets at 3, when on animation complete I am updating the variable.
Any help would be very much appreciated, thanks.
http://codepen.io/matt3224/pen/QyydVB?editors=001
$(function(){
var doc = $(document),
rate = parseFloat(50 / 60 / 60).toFixed(4),
earned = rate,
paused = false;
doc.on('click', '.js-start', function(e){
e.preventDefault();
$(this).text('Stop').removeClass('js-start').addClass('js-stop js-start--stop');
setInterval(function(){
if(!paused){
var perSec = +earned + +rate;
$({someValue: earned}).animate({someValue: perSec}, {
duration: 1000,
step: function() {
$('.js-count').text('£' + parseFloat(this.someValue).toFixed(2));
},
complete: function() {
earned = parseFloat(+earned + +rate).toFixed(2);
}
});
}
}, 1000);
});
doc.on('click', '.js-stop', function(e){
e.preventDefault();
$(this).text('Start').removeClass('js-stop js-start--stop').addClass('js-start');
paused = true;
});
});

Related

Converting a manual slideshow to automatic

I followed a tutorial and created a simple manual loop slideshow. I'm trying to make it so it changes the slide automatically even if the prev/next buttons aren't clicked. I tried a crude approach by setting a delay between automatic click events on the "next" button but for some reason it clicks it only once and stops. My js knowledge is very limited and can't figure it out, any input is appreciated. This is the script so far:
$(function() {
var ul = $(".slider ul");
var slide_count = ul.children().length;
var slide_width_pc = 100.0 / slide_count;
var slide_index = 0;
var first_slide = ul.find("li:first-child");
var last_slide = ul.find("li:last-child");
last_slide.clone().prependTo(ul);
first_slide.clone().appendTo(ul);
ul.find("li").each(function(indx) {
var left_percent = (slide_width_pc * indx) + "%";
$(this).css({"left":left_percent});
$(this).css({width:(100 / slide_count) + "%"});
});
ul.css("margin-left", "-100%");
$(".slider .prev").click(function() {
console.log("prev button clicked");
slide(slide_index - 1);
});
$(".slider .next").click(function() {
console.log("next button clicked");
slide(slide_index + 1);
});
function slide(new_slide_index) {
var margin_left_pc = (new_slide_index * (-100) - 100) + "%";
ul.animate({"margin-left": margin_left_pc}, 400, function() {
if(new_slide_index < 0) {
ul.css("margin-left", ((slide_count) * (-100)) + "%");
new_slide_index = slide_count - 1;
}
else if(new_slide_index >= slide_count) {
ul.css("margin-left", "-100%");
new_slide_index = 0;
}
slide_index = new_slide_index
});
}
});
Here is an approach to make it sliding automatically...
But if user clicks on prev/next, it holds the automatic feature for a defined "idle" time.
It need two lines added to your click handlers:
var autoEnabled = true; // ADDED
$(".slider .prev").click(function() {
console.log("prev button clicked");
slide(slide_index - 1);
autoEnabled = false; // ADDED
disabledCount = 0; // ADDED
});
$(".slider .next").click(function() {
console.log("next button clicked");
slide(slide_index + 1);
autoEnabled = false; // ADDED
disabledCount = 0; // ADDED
});
And this to cyclically slide or check if it can re-enable itself.
// ----------------- Automatic sliding interval with "idle time" to re-enable on user click
var idleTime = 5000; // Time without manual click to re-enable automatic sliding.
var autoSlideDelay = 1000; // Time between each slide when automatic.
var disabledCount = 0;
var autoSlide = setInterval(function(){
if(autoEnabled || disabledCount >= idleTime/autoSlideDelay ){
disabledCount = 0;
autoEnabled = true;
slide(slide_index + 1);
}else{
disabledCount++;
}
},autoSlideDelay);
var break_auto_slide = false;
function auto_silde()
{
if(break_auto_slide)
{
break_auto_slide = false;
return;
}
slide(slide_index + 1);
setTimeout(auto_silde,1000 /* time in ms*/);
}
setTimeout will call the function in a specified timeout in milliseconds.
Variable break_auto_slide - set it to true to stop the automatic slide. Next time the function is called it will return without setting a new timer and will reset this variable so auto mode can be turned on again.

Javascript/jQuery bug in my Trivia Game

I am creating a basic Trivia Game for a Web Dev class. We are to use HTML/CSS/JS/jQuery to create it. The new element that we are to work with in this assignment are the setTimeout() & setInterval() methods.
After clicking the start button, the game will ask a question and offer 4 possible answers. The user either clicks an answer or the timer runs out. The results are displayed and then then the next questions auto-loads. Once all of the questions in the questions array are asked, the game displays the overall results and then refreshes screen.
The bug that I discovered is that if I let the timer run all the way down until the "zero" is just displayed on the screen and then quickly click on an answer, it causes the game to react as if the conditions of an answer being clicked and the time running out had occurred simultaneously. Then the next question loads too many answers and the timer is decrementing at an increased rate. I'm not sure if there is some sort of time lag in the timer reaching zero somewhere that allows the answer clicks to transmit through and this creates a new timerID that doesn't get cleared which causes the time decrementing on the next question to increase in rate.
I've created a Fiddle for this: https://jsfiddle.net/brianpatrickhummel/0a2hg782/
var correctAnswers = 0;
var incorrectAnswers = 0;
var unansweredQuestions = 0;
var timeRemaining = 16;
var intervalID;
var indexQandA = 0; //index to load a different question each round without the game reset or screen refresh
var answered = false; //variable to stop the timer if user has clicked an answer
var correct;
var triviaGame = [
{question:"HOW MANY COLORS ARE THERE ON A RUBIK'S CUBE ?", answer:["5", "6", "7", "4"], correct: "1", image:("assets/images/rubik.png")},
{question:"WHAT IS THE SPEED OF LIGHT ?", answer:["8,600 MILES per SECOND","86,000 MILES per SECOND","186,000 MILES per SECOND","886,000 MILES per SECOND"], correct:"2", image:("assets//images/lightspeed.jpg")},
{question:"APPROXIMATELY HOW LONG DOES IT TAKE FOR SUNLIGHT TO REACH THE EARTH ?", answer:["45 SECONDS", "10 HOURS", "2 HOURS 15 MINUTES", "8 MINUTES"], correct:"3", image:("assets//images/sunlight.jpg")},
{question:"WHAT ELEMENT'S CHEMICAL SYMBOL IS Pb ?", answer:["POTASSIUM","STRONTIUM","LEAD","PALLADIUM"], correct:"2", image:("assets//images/periodictable.png")},
{question:"HOW FAST CAN BEES FLY ?", answer:["35 MPH", "15 MPH", "48 MPH", "8 MPH"], correct:"1", image: ("assets/images/bee.png")},
{question:"WHAT IS THE MOST ABUNDANT ELEMENT IN THE UNIVERSE ?", answer:["HYDROGEN", "OXYGEN", "HELIUM", "CARBON"], correct:"0", image:("assets//images/universe.png")},
{question:"THE AIR THAT WE BREATHE IS COMPRISED MOSTLY OF WHAT ELEMENT ?", answer:["CARBON", "ARGON", "OXYGEN", "NITROGEN"], correct:"3", image:("assets//images/breathe.jpg")},
{question:"WHAT IS THE DIAMETER OF THE EARTH ?", answer:["140,000 MILES", "2,500,000 MILES", "8,000 MILES", "25,000,000 MILES"], correct:"2", image:("assets//images/earth.png")}
];
// ------------- FUNCTION DECLARATIONS ----------------------------
function startGame() {
console.log("game has begun");
$('.start-button').remove();
correctAnswers = 0;
incorrectAnswers = 0;
unansweredQuestions = 0;
loadQandA ();
}
function loadQandA() {
// console.log(correctAnswers);
// console.log(incorrectAnswers);
// console.log(unansweredQuestions);
// console.log(indexQandA);
answered = false; // will allow timeRemaining to be pushed back to <h5> after round reset....else statement in function timer()
timeRemaining = 16;
intervalID = setInterval(timer, 1000);
if (answered === false){
timer();
}
correct = triviaGame[indexQandA].correct;
var question = triviaGame[indexQandA].question;
$('.question').html(question);
for (var i = 0; i < 4; i++) {
var answer = triviaGame[indexQandA].answer[i];
$('.answers').append('<h4 class= answersAll id=' + i + '>' + answer + '</h4>');
}
$( "h4" ).click(function() {
var id = $(this).attr('id');
// alert(id);
if (id === correct) {
answered = true; // stops the timer
// alert("correct answer");
$('.question').text("THE ANSWER IS: " + triviaGame[indexQandA].answer[correct]);
correctAnswer ();
}
else {
answered = true; //stops the timer
// alert("incorrect answer");
$('.question').text("YOU CHOSE: " + triviaGame[indexQandA].answer[id] + ".....HOWEVER THE ANSWER IS: " + triviaGame[indexQandA].answer[correct]);
incorrectAnswer();
}
});
}
function timer() {
if (timeRemaining === 0) {
answered = true;
clearInterval(intervalID);
$('.question').text("THE CORRECT ANSWER IS: " + triviaGame[indexQandA].answer[correct]);
unAnswered();
}
else if (answered === true) {
clearInterval(intervalID);
}
else {
timeRemaining--;
$('.timeRemaining').text('YOU HAVE ' + timeRemaining + ' SECONDS TO CHOOSE').removeClass('animated pulse infinite');
}
}
function correctAnswer() {
correctAnswers++;
$('.timeRemaining').text("YOU HAVE ANSWERED CORRECTLY!").css({'color':'#3D414F'}).addClass('animated pulse infinite');
resetRound();
}
function incorrectAnswer() {
incorrectAnswers++;
$('.timeRemaining').text("YOU HAVE ANSWERED INCORRECTLY!").css({'color':'#3D414F'}).addClass('animated pulse infinite');
resetRound();
}
function unAnswered() {
unansweredQuestions++;
$('.timeRemaining').text("YOU FAILED TO CHOOSE AN ANSWER").css({'color':'#3D414F'}).addClass('animated pulse infinite');
resetRound();
}
function resetRound() {
$('.answersAll').remove();
$('.answers').append('<img class=answerImage src="' + triviaGame[indexQandA].image + ' ">'); // adds answer image
indexQandA++; // increments index which will load next question when loadQandA() is called again
if (indexQandA < triviaGame.length) {
setTimeout(function(){ loadQandA(); $('.answerImage').remove();}, 5000); // removes answer image from previous round
}
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>INCORRECT ANSWERS: ' + incorrectAnswers + '</h4>');
$('.answers').append('<h4 class= answersAll end>UNANSWERED QUESTIONS: ' + unansweredQuestions + '</h4>');
setTimeout(function(){ location.reload(); }, 7000);
}, 5000);
}
}
// ----------------------- MAIN PROCESS ---------------------
$('.startButton').on("click", function() {
$('.startButton').removeClass('infinite').addClass('animated fadeOutDown'); //manages the Animate.css applied to Start Button
startGame();
});
Each time you establish a timer with either setTimeout or setInterval, you need to set a variable to the returned timer id. That variable needs to have a high enough scope so that you can access it from any place where the timer must be interacted with.
Then, anywhere you need to interrupt the timer, you can clear it. In your case, when an answer is clicked, you need to stop the countdown timer.
Here's a scaled down example:
window.addEventListener("DOMContentLoaded", function(){
var clock = document.getElementById("clock");
var btnStart = document.getElementById("btnStart");
var btnStop = document.getElementById("btnStop");
// Declare this where you can get at it
var timer1 = null;
function start(){
clock.textContent = new Date().toLocaleTimeString();
timer1 = setTimeout(start, 900);
}
function stop(){
// Cancel the timer
clearTimeout(timer1);
}
btnStart.addEventListener("click", start);
btnStop.addEventListener("click", stop);
start();
});
<div id="clock"></div>
<button id="btnStop">Stop the Clock</button>
<button id="btnStart">Start the Clock</button>

Prevent setInterval() from increasing speed after set number of clicks

I'm building a clicker game where I want a timer to auto click for me. I want the timer to increase speed each time I click a button, but prevent increasing the timer's speed after clicking said button 5 times.
This is what I have come up with so far:
var total = 0;
var itemValue = 0;
var autoClick = function() {
if(itemValue <= 5) {
total = total + itemValue;
}
};
$("#button").click(function() {
itemValue++;
setInterval(autoClick, 1000);
});
Any suggestions?
So you want to increase total by x value each second.
x depending on how namy clicks on an "increase speed button"...
I got it?
To prevent concurring intervals, you have to clear the previous.
var total = 0;
var itemValue = 0;
var myInterval;
var autoClick = function() {
total = total + itemValue;
console.log(total);
};
$("#button").click(function() {
if(itemValue <= 4) {
// Increase...
itemValue++;
// Prevents multiple intervals.
clearInterval(myInterval);
myInterval = setInterval(autoClick, 1000/itemValue);
console.log("Increasing by "+itemValue+" now...");
}else{
console.log("Hey! By "+itemValue+" is way enought!");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">Increase speed!</button>

Javascript count up onload load function

I am creating a script which will refresh "viewers" count displayed at the top of my website.
Javascript:
<script type="text/javascript">
window.onload = function(){
var auto_refresh = setInterval(
function ()
{
$('#viewers').load('viewers.php');
}, 5000);
}
</script>
HTML:
<span id="viewers">0</span>
viewers.php output:
100
I'd like to add a "count up/down" effect, so for example if the viewers.php outputs 200, it will then count up after the 5000 milliseconds, and if this count dropped to 50, the 100 will count down to 50.
Thanks for the help!
Here is a solution that counts up or down to the new number of viewers over a given delay period. It seems to run a little slow, probably due to the delay of my code inside the setInterval.
Just call the setViewers whenever you want to update the count.
<script type="text/javascript">
window.onload = function(){
var delay = 4000;
var viewers = $("#viewers");
var auto_refresh = setInterval(
function ()
{
var curViewers = Number(viewers.html())
$('#viewers').load('viewers.php', function(){
var newViewers = Number(viewers.html());
setViewers(curViewers, newViewers);
});
}, 5000);
function setViewers(currentNum, newNum){
if(currentNum == newNum) return;
var updateSpeed = delay / Math.abs(currentNum - newNum);
var countDir = currentNum > newNum ? -1 : 1;
var timer = setInterval(function(){
currentNum += countDir;
viewers.text(currentNum);
if(currentNum == newNum) clearInterval(timer);
}, updateSpeed);
}
}
</script>

Stop notification timeout on hover

I have a slider error notification which slides out, displays error and disappears in 10 seconds. It can be removed earlier if you click on it.
On thing that is missing is stopping it disappearing by mouse hover.
For some people, 10 seconds is not enough to read the error.
So I need to stop the timer with mouse hover.
To summarise: I'd like it to disappear in 10 seconds as it is now if you don't interact with it. If I hover over it, the timer should be stopped and the message should stay there till you click on it to remove.
How can I stop the timer (the setTimeout function) on hover?
This is the message slider function:
function popa(text = "Internal Error!", type = "error") {
var alert = document.createElement("div");
var stack = document.querySelectorAll('.alert').length;
alert.appendChild(document.createTextNode(`${stack + 1}: ${text}`));
alert.classList.add("alert");
alert.classList.add(`alert-${type}`);
document.querySelector("body").appendChild(alert);
var steps = 20;
var width = parseInt(getComputedStyle(alert).getPropertyValue('width'));
var slide = width + Math.round(width / 4);
var step = Math.round(slide / steps);
alert.onclick = () => {
alert.parentNode.removeChild(alert);
};
(function next(cnt, max) {
if (cnt++ > max) {
return;
}
alert.style.right = `${(-width) + (step * cnt)}px`;
setTimeout(() => {
next(cnt, max);
}, 10);
})(0, steps);
console.log(text);
setTimeout(() => {
if (alert.parentNode) {
alert.parentNode.removeChild(alert);
}
}, 10000);
}
Thank you.
P.S. No jQuery please
window.setTimeout() returns an integer timerID which you can use with window.clearTimeout():
var notificationTimer;
function createTimer() {
notificationTimer = setTimeout(function(){ alert('hi'); }, 10000);
}
function clearTimer() {
clearTimeout(notificationTimer);
}
See also: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout

Categories