What I am looking to do is have a number start counting either up or down, lets say from 1 to a 100 or a 100 to 1. I have found many many plugins that do this but they all have a duration variable. The problem is that duration variable applies to how long it takes to get from start to finish. I am looking for a way to set how long it takes to get to the next digit. IE counting from X to Y and updating the number every .25 seconds. This way a larger number would take longer to get to than a smaller number.
This plugin looks great but I can't get it to do what I want.
https://github.com/mhuggins/jquery-countTo
Any help would be great.
Please try this and let me know if that's what you want:
function countTo(min, max, interval, callback) {
var counter = min;
var i = setInterval(function() {
callback(counter);
counter++;
if(counter> max) return clearInterval(i);
}, interval*1000);
};
countTo(0, 100, 0.25, function(counter) {
$("#counter").text(counter);
});
countTo(0, 100, 0.01, function(counter) {
$("#counter2").text(counter);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="counter"> </div>
<div id="counter2"> </div>
You can try something like this
function count(target, start, end, step, timeInterval) {
var timer = setInterval(function() {
if (start == end) {
clearInterval(timer);
return false;
}
start += step;
target.html(start);
}, timeInterval);
}
count($('#timer1'), 1, 100, 1, 50);
count($('#timer2'), 100, 1, -1, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="timer1"></div>
<div id="timer2"></div>
Related
I wrote some JavaScript code to animate CSS properties of elements. I pass the following arguments to the function: amount, interval, and duration; amount being the change in the property (for example 200 could mean add 200 pixels to the element's width), interval being the time between two consecutive changes, and duration being the total duration of the animation.
The code works fine unless I pass the arguments in a way that the change in each interval becomes very small (like a tiny fraction of a pixel).
I know the code is working fine theoretically, as I get the change in console.
Any ideas about the problem?
Cheers.
UPDATE: the code:
function handleTimer (amount, interval, duration, execute, element) {
let i = 0;
let current = 0;
let stepsCount = countSteps(interval, duration);
let stepLength = calcStepLength(stepsCount, amount);
let count = setTimeout(function addOneMore () {
if ( i < stepsCount -1 ){
i++;
current += stepLength;
execute(stepLength, element);
if (current < amount) {
count = setTimeout(addOneMore, interval)
}
} else {
current = amount;
execute(amount - (stepsCount -1) * stepLength, element);
}
}, interval)
}
function countSteps (interval, duration) {
let remainder = duration % interval;
let stepsCount;
if (remainder) {
stepsCount = Math.floor(duration / interval) + 1;
} else {
stepsCount = duration / interval;
}
return stepsCount;
}
function calcStepLength(stepsCount, amount) {
return amount / stepsCount;
}
function resizeWidth (amount, element) {
let widthSTR = $(element).css('width');
let width = parseInt( widthSTR.substr( 0 , widthSTR.length - 2 ) );
$(element).css('width', `${width + amount}px`);
}
So this:
handleTimer(218, 5, 200, resizeWidth, '.box');
works fine, but this:
handleTimer(218, 5, 2000, resizeWidth, '.box');
doesn't.
UPDATE 2:
I know browsers are super accurate with pixels, like when you use percentages. Of course the value will be rounded before rendering since displays cant display half pixels, but the value is still calculated accurately.
I don't know at what decimal the rounding occurs.
This happens because parseInt is rounding your number up.
Pay attention to this line:
let width = parseInt( widthSTR.substr( 0 , widthSTR.length - 2 ) );
if width is a decimal number, like 22.5px, it will be rounded up to 22.
If amount is less than 1, it won't reach 23 and when you round up the number again, you'll get 22 again and it becomes a loop.
You have two solutions:
Use another variable to save the width value, avoiding to writing and reading it from CSS:
let initialWidth = $(element).css('width');
let savedWidth = widthSTR.substr(0, initialWidth, initialWidth.length - 2 ) );
function resizeWidth (amount, element) {
savedWidth += amount;
$(element).css('width', `${savedWidth}px`);
}
Just use parseFloat in place of parseInt to don't round your number up:
let width = parseFloat( widthSTR.substr( 0 , widthSTR.length - 2 ) );
I have a simple progress bar with a JS animation. Every 20ms, the value of the progress bar increases by 0.25. So it takes 20*4*100ms = 8 seconds to complete the progress bar, as you can see on the JSFiddle below.
function updateProgress(currentValue, expectedValue){
var inProgress = setInterval(function() {
currentValue = currentValue + 0.25;
$('#progress-bar').attr('value', currentValue);
$('#progress-text').text(Math.round(currentValue));
if (currentValue == expectedValue) clearInterval(inProgress);
}, 20);
}
updateProgress(0, 100);
<progress id="progress-bar" value="0" max="100"></progress>
<div><span id="progress-text">0</span>%</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
So if I take the same code and start the progress bar at 50% instead of 0%, it will take 20*4*50ms = 4 seconds to complete the progress bar, as you can see on the JSFiddle below.
function updateProgress(currentValue, expectedValue){
var inProgress = setInterval(function() {
currentValue = currentValue + 0.25;
$('#progress-bar').attr('value', currentValue);
$('#progress-text').text(Math.round(currentValue));
if (currentValue == expectedValue) clearInterval(inProgress);
}, 20);
}
updateProgress(50, 100);
<progress id="progress-bar" value="50" max="100"></progress>
<div><span id="progress-text">50</span>%</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
I would like the function to always have the same time to execute, lookless of the starting value.
For example 0 to -> 100 : 4 seconds, and 50 to -> 100 also 4 seconds.
I tried this but it does not work :
function updateProgress(currentValue, expectedValue){
var interval = 4000 / (expectedValue - currentValue) / 4;
var inProgress = setInterval(function() {
currentValue = currentValue + 0.25;
$('#progress-bar').attr('value', currentValue);
$('#progress-text').text(Math.round(currentValue));
if (currentValue == expectedValue) clearInterval(inProgress);
}, interval);
}
updateProgress(50, 100);
I think I'd use requestAnimationFrame for this, this is pretty much what it's designed for.
function updateProgress(currentValue, expectedValue){
var valueDelta = expectedValue - currentValue,
startTime = performance.now();
nextFrame(startTime);
function nextFrame(time) {
var value = Math.min(expectedValue, currentValue + valueDelta * (time - startTime) / 4000);
setValue(value);
if (value !== expectedValue) {
requestAnimationFrame(nextFrame);
}
}
function setValue(value) {
$('#progress-bar').attr('value', value);
$('#progress-text').text(Math.round(value));
}
}
updateProgress(50, 100);
<progress id="progress-bar" value="50" max="100"></progress>
<div><span id="progress-text">50</span>%</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
Whether you choose to use requestAnimationFrame or setInterval, I think the key thing is to base your animation on the current time rather than assuming that the timer will be called on schedule.
When I run your original code it works fine for me. My guess would be that the problem is the timer not being called on schedule when the interval is very small, that will be platform dependent. setInterval is not super accurate at the best of times but for the full range, 0 to 100, you'll be relying on a 10ms timer, which is small enough to be problematic.
<head>
<script>
window.setInterval(function(){timer()},100);
function timer()
{
document.getElementById("timer").innerHTML=
(parseInt(document.getElementById("timer").innerHTML*100)+1)/100;
}
</script>
</head>
<body>
<div id="timer">0.000</div>
</body>
As you see, timer counts only up to 0.29.
Why is it?
It's because of the way floating point math works coupled with your parseInt(). Refer to Is floating point math broken.
When it reaches 0.29, it does 0.29 x 100, which you're expecting to result in 29 but actually it is:
console.log(0.29 * 100);
28.999999999999996
Next, you convert it to an integer using parseInt() which results in 28 (removing all of the decimal places), finally you add 1 and divide by 100 making the result 0.29 and this is repeated on each tick of the timer, the number can't increase.
It would be better to store the raw value as a variable and output it using .toFixed(2), instead of using the number on the UI as the source. Like this:
Fiddle
var num = 0.00;
window.setInterval(function () {
timer();
}, 100);
function timer() {
num = ((num * 100) + 1) / 100;
document.getElementById("timer").innerHTML = num.toFixed(2);
}
Please Help! I'm new to Javascript, so there's probably an easier solution to this. Basically, I need it to prompt for a number and then count down from that number to zero. Once it reaches zero, I need it to count-up and stop at the same prompted number.
I got it to count down at first, then I completely butchered it, I have no clue what to do.
<script type="text/javascript">
// get number from user
var startNum = parseInt(prompt("Input a number to start counting down from.",""));
var counter = setInterval(timer, 1000);
console.log(startNum);
function timer() {
startNum--; // reduce number by 1
console.log(startNum);
if (startNum <= 0) {
clearInterval(counter);
}
}
var counter = setInterval(timer2, 1000);
var endNum = 0
function timer2() {
console.log(endNum)
endNum++; // add number by 1
console.log(endNum);
if (endNum >= startNum) {
clearInterval(counter);
}
}
</script>
You've got a couple issues here. the first one was pointed out by Rob in the comments. You're running both functions at the same time.
The other issue you have is that you're never storing the number. You're just subtracting and adding to nothing essentially.
So -
<script type="text/javascript">
// get number from user
var startNum = parseInt(prompt("Input a number to start counting down from.",""));
var currentNum = startNum;
var counter = setInterval(timer, 1000);
function timer() {
console.log(currentNum);
currentNum -= 1; // reduce number by 1
console.log(currentNum);
if (currentNum == 0) {
clearInterval(counter);
counter = setInterval(timer2, 1000);
}
}
function timer2() {
console.log(currentNum)
currentNum += 1; // add number by 1
console.log(currentNum);
if (currentNum == startNum) {
clearInterval(counter);
}
}
</script>
Something like this should do the trick. Basically creating another variable to hold your start number and consider that the current number and the value that is going to change.
here's a fiddle - http://jsfiddle.net/w5FM6/
cheers
This is probably basic math that I don't seem to remember.
I'm trying to get from 0 to 5,000,000 in 10 seconds while having all the numbers ticking. I don't have to have the number reach exactly 5,000,000 because I can just do a conditional for it to stop when it's over.
Right now I have this:
count+= 123456
if (count > 5000000) {
count = 5000000;
}
It gives the sense of number moving you know? But It really starts off too high. I wanted to gradually climb up.
You could do something like this:
function timedCounter(finalValue, seconds, callback){
var startTime = (new Date).getTime();
var milliseconds = seconds*1000;
(function update(){
var currentTime = (new Date).getTime();
var value = finalValue*(currentTime - startTime)/milliseconds;
if(value >= finalValue)
value = finalValue;
else
setTimeout(update, 0);
callback && callback(value);
})();
}
timedCounter(5000000, 10, function(value){
// Do something with value
});
Demo
Note that with a number as big as 5000000 you won't see the last couple digits change. You would only see that with a small number like 5000. You could fix that; perhaps by adding in some randomness:
value += Math.floor(Math.random()*(finalValue/10000 + 1));
Demo with randomness
You can tween:
import fl.transitions.Tween;
import fl.transitions.easing.Regular;
var count = 0;
var tween:Tween = new Tween(this, "count", Regular.easeInOut,0,5000000,10, true);
This will tween you variable count from 0 to 5000000 in 10 seconds. Read about these classes if you want to expand on this code.
Tween
TweenEvent
Good luck!