So I've got this counter and it needs to increment a number by 75 every 60 seconds. The code I have below does this fine but due to rounding some numbers stay up longer than others, and some numbers are skipped.
I'd rather have this to smoothly/evenly count to get the same end result. I know I would need to somehow calculate the setInterval timer number, but I'm not sure what to get that.
(function(){
//Numbers
var num = 0;
var perMinute = 75;
var perSecond = perMinute / 60;
//Element selection
var count = document.getElementById("count");
function update(){
//Add the per-second value to the total
num += perSecond;
//Display the count rounded without a decimal
count.innerHTML = Math.round(num);
}
//Run the update function once every second
setInterval(update, 1000);
})();
Working example: http://jsfiddle.net/ChrisMBarr/9atym/1/
Never rely on Timeout or Interval to be accurate. Instead, save the "start time" and compare it to the current time.
(function() {
var start = new Date().getTime(),
perMinute = 75,
perMS = perMinute/60000,
count = document.getElementById('count');
function update() {
var elapsed = new Date().getTime()-start;
count.innerHTML = Math.round(elapsed*perMS);
}
setInterval(update,1000);
})();
Note that you can adjust the 1000 to vary "smooth" the counter is (more important for bigger values of perMinute) and it will always work perfectly, to within the resolution's overshoot.
Moving your rounding seemed to fix this (Edit: No it doesn't. See the jsfiddle example of a better fix I put below).
(function(){
//Numbers
var num = 0;
var perMinute = 75;
var perSecond = perMinute / 60;
//Element selection
var count = document.getElementById("count");
function update(){
//Add the per-second value to the total
num += Math.round(perSecond);
//Display the count rounded without a decimal
count.innerHTML = num;
}
//Run the update function once every second
setInterval(update, 1000/perSecond);
})();
Edit: a proper fix - http://jsfiddle.net/4y2y9/1/
Related
I have a problem with this code. 4.9 never comes out, only 4.5 or 5.5. Could it be possible to spin up the decimals instead of the integers to reach 4.9?
let counts = setInterval(updated, 500);
let upto = 1.5;
function updated() {
var count = document.getElementById("counter");
count.innerHTML = ++upto;
if (Number(upto.toFixed(1)) >= 4.9) {
clearInterval(counts);
}
}
First: do not increment by 1 (++upto === upto + 1).
Second: You need to modify your clearInterval condition:
let counts=setInterval(updated, 10);
let upto=70.1;
function updated(){
var count= document.getElementById("counter");
count.innerHTML=upto + 0.1;
if(Number(upto.toFixed(1))===88.5)
{
clearInterval(counts);
}
}
You had two small but important issues that I fixed. Read the comments I put in the code snippet.
Updated: Use toFixed to show x count of decimals.
let counts = setInterval(updated, 10);
let upto = 70.1;
var count = document.getElementById("counter");
function updated() {
// ++upto would never hit 88.5, it will hit 88.1 89.1 -> so we do += 0.1
// Updated: Show only one decimal using toFixed()
const _t = upto += 0.1
count.innerHTML = _t.toFixed(1);
// Changing upto to number again because toFixed converts it to string
if (Number(upto.toFixed(1)) === 88.5) {
clearInterval(counts);
}
}
<p id="counter"></p>
Use a from step to variables, and make sure to reset the curr value to a to value when it exceeds that max:
// Counter options:
const from = 0;
const step = 0.1;
const to = 4.9;
const speed = 100; // ms
// Counter:
const elCounter = document.getElementById("counter");
let itvCounts = null;
let curr = from;
const updateCounter = () => {
curr += step;
if (curr >= to) {
clearInterval(itvCounts);
curr = to;
}
elCounter.innerHTML = +curr.toFixed(1);
};
// Init:
itvCounts = setInterval(updateCounter, speed);
<span id="counter"></span>
Find more useful examples and implementations here:
Animate counter from start to end value
How to restart counter animation when it's out of view?
Im trying create some type of number generator on webpage. I want to show like five numbers before the generated number show. For better imagine, you can look to google generator. When you click generate, it shows like 3-4 numbers before generated number. I use setInterval or setTimeout but i dont know how it works. My js code:
var button = document.querySelector("button");
button.addEventListener("click",function() {
for (var i = 0; i < 8; i++) {
setInterval(textC,5);
}
});
function textC(){
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
Thanks for every help!
The issue with setInterval() is that it will continue forever unless cleared, causing you to keep generating random numbers. Instead you can use setTimeout(), but set the timeout to change based on the value of i in the for loop. That way, each interval will occur 50 m/s after the other.
See example below:
const button = document.querySelector("button");
const number = document.querySelector("#number");
button.addEventListener("click", function() {
for (let i = 0; i < 5; i++) {
setTimeout(textC, 50 * i);
}
});
function textC() {
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
<p id="number"></p>
<button>Generate</button>
Don't use a loop (why not?). Just nest setTimeout and call it until a predefined threshold is reached. It gives you maximum control.
var button = document.querySelector("button");
var number = document.querySelector("#number");
const nRuns = 12;
const timeout = 100;
let iterator = 0;
button.addEventListener( "click", textC);
function textC(){
number.textContent = `${Math.floor(Math.random() * 1000) + 1}\n`;
iterator += 1;
if (iterator < nRuns) {
setTimeout(textC, timeout)
} else{
iterator = 0;
// you control the loop, so it's time for some extra text after it
number.textContent += ` ... and that concludes this series of random numbers`;
}
}
<p id="number"></p>
<button>Generate</button>
I am trying to make a function that will only retain its variable count from the past minute.
For example, if I call function count 100 times, if 60 of those calls were from the past minute, it will only return 60, and not 100.
This is what I have tried so far, making the variable an array and adding numbers to it everytime its called, but I do not know how to remove a count when a minute has passed.
var count = 1;
var countArray = [];
UPDATE:
I have updated my code with this, but the array elements are not removing as they should,
function Count() {
var jNow = new Date();
jCountArray.push(jNow);
for (var i = 0; i <= jCountArray.length; i++) {
var secondsDiff = (new Date(jNow).getTime() - new Date(jCountArray[i]).getTime()) / 1000;
if (secondsDiff >= 10) { jCountArray.shift(); }
}
console.log(jCountArray);
return jCountArray.length;
}
If I understand your requirements correctly, and the only thing you need Count to do is return how many times it was called in the last minute, I think we could do something relatively easily leveraging setTimeout:
function getCounter() {
let count = 0;
let duration = 60000;
return function () {
count = count + 1;
setTimeout(function () {
count = count - 1;
}, duration);
return count;
}
}
let counter = getCounter();
function count() {
console.log(counter());
}
<button onclick="count()">Count</button>
The only trick here is, to keep the actual count private, we need a factory function to wrap it in a closure. If that's unimportant you can write it as a simple function and keep the count in the parent scope. Also, for testing purposes you can change the duration to a lower millisecond count to see it in action.
My goal is to perform a jQuery script that'll make any number visually grow from zero until its value with setInterval().
Here's what I came up with:
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var refresh = 5;
var start = 0;
var step = 1;
var interval = window.setInterval(function() {
start += step;
$el.text(start);
if(start >= max)
clearInterval(interval);
}, refresh);
});
My problem is I have numbers ranging from a few hundreds to several hundreds thousands. With this script, bigger number take more time to reach their value.
My goal is to make any number, regardless of its goal value, take the same amount of time to reach it. I sense that I should divide the number by the number of seconds I want the animation to run and then, set the result as the interval step?
I'm inquiring but still seeking for help :)
Thanks.
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var duration = 1000; // shared duration of all elements' animation
var refresh = 5;
var frames = duration / refresh; // number of frames (steps)
var start = 0;
var step = Math.max(Math.round(max / frames), 1); // step should be >= 1
var interval = window.setInterval(function() {
if(start + step < max) {
start += step;
}
else {
start = max;
clearInterval(interval);
}
$el.text(start);
}, refresh);
});
This should work I suppose,
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var start = 0;
var refresh = 5;
var totalSteps = 10;
var step = max/totalSteps;
function calculate(){
start += step;
$el.text(Math.round(start));
if(start < max){
setTimeout(function() {
calculate();
}, refresh);
}
}
calculate();
});
This will always finish in 100 steps. I.e. 100*refresh = 100*5 = 500 seconds.
Trying to make a simple count up timer in jQuery... this sort of works but is adding the numbers to the end of '0000' and I want it to go '0001' '0002' '0003' etc...
This is all happening in the jQuery onReady scope.
var i = '0000'
var timer = function doSomething ( )
{
i = i+= 1
$('.counter').text(i);
console.log(i);
}
setInterval (timer, 1000 );
Your "i" variable needs to be an integer. You can format it how you like when you want to print it somewhere.
$(document).ready(function() {
var i = 0;
var target = $('.counter');
var timer = function doSomething ( )
{
i++;
var output = pad(i,4);
target.text(output);
console.log(output);
}
setInterval (timer, 1000 );
});
function pad(number, length) {
var str = '' + number;
while (str.length < length) {
str = '0' + str;
}
return str;
}
Your current code is appending to a string, not addition to a number. It essentially looks like
i = '0000' + 1, i = '00001' + 1, i = '000011' + 1 ...
and so on. You'll need to keep it integer based to continue adding to the number. Here's an example with the formatting it looks like you wanted.
var pad = function(n) { return (''+n).length<4?pad('0'+n):n; };
jQuery.fn.timer = function() {
var t = this, i = 0;
setInterval(function() {
t.text(pad(i++));
}, 1000);
};
$('#timer').timer();
http://jsfiddle.net/jDaTK/
I would do something more like this:
// Make sure Date.now exists in your environment
Date.now = Date.now || function () { return Number(new Date()); };
var time = 0,
start = Date.now(),
intervalId;
intervalId = setInterval(function () {
var seconds, display;
// get the exact time since the timer was started
time = Date.now() - start;
// get the number or seconds, rounded down
seconds = Math.floor(time / 1000);
display = '' + seconds;
// pad the beginning of your display string with zeros
while (display.length < 4) {
display = "0" + display;
}
console.log(display);
}, 100);
setInterval is not exact. This code ensures that while the display could be up to nearly a second off (in theory), the actual time you are tracking is always the exact amount of time that has elapsed since you started the timer. But this code would update the display about once every tenth of a second, so it's not likely to ever be off more than a few milliseconds.
From here you can figure out smarter ways to update the display to ensure you have the level of accuracy you need. If this needs to be pretty accurate, then you could make sure you are displaying to the tenth of the second.
I really recommend the jQuery CountUp plugin. I tried a number of Javascript counters and this was one of the easiest to implement and came with lots of goodies:
<script type="text/javascript">
$(document).ready(function(){
$('#counter').countUp({
'lang':'en', 'format':'full', 'sinceDate': '22/07/2008-00::00';
});
});
</script>
<div id="counter"></div>