Setting the exact duration for incrementing to another number - javascript

I've made a function that increments one number to another. This works however my duration logic doesn't.
The third parameter in .animateNumber() is duration, and I want this to be the time spent incrementing to the new number.
So if the duration is set at 500, then it'll take 500 milliseconds incrementing from 10 (start) - 500 (end), and this would be the same for any starting and ending values.
http://jsbin.com/kepibetuxu/edit?html,js,console,output
HTMLElement.prototype.animateNumber = function(start, end, duration) {
this.style.opacity = 0.5;
var self = this,
range = end - start,
current = start,
increment = end > start? 1 : -1,
stepTime = duration / range,
timer = setInterval(function() {
current += increment;
self.innerHTML = current;
if (current == end) {
self.style.opacity = 1;
clearInterval(timer);
}
}, stepTime);
console.log(range);
console.log(stepTime);
};
document.querySelector('.value').animateNumber(400, 500, 20);
document.querySelector('.value1').animateNumber(0, 500, 20);
<div class="value">0</div>
<div class="value1">0</div>
How may I fix my stepTime logic to do this?

I would just request new frames, and update the number to the approapriate fraction at that time:
function animateNumber(el, start, end, duration) {
var startTime = performance.now();
(function func() {
var factor = Math.min(1, (performance.now() - startTime) / duration);
el.textContent = (start + (end-start) * factor).toFixed(0);
el.style.opacity = factor;
if(factor < 1) requestAnimationFrame(func);
})();
}
animateNumber(document.querySelector('.value1'), 400, 500, 2000);
animateNumber(document.querySelector('.value2'), 0, 500, 2000);
<div class="value1">0</div>
<div class="value2">0</div>

this is how you can do it adding a refresh rate to your function:
HTMLElement.prototype.animateNumber = function(start, end, duration, refresh) {
this.style.opacity = 0.5;
var self = this,
refresh = refresh || 10,
range = end - start,
stepQt = duration/refresh | 0,
increment = end > start? range/stepQt : -range/stepQt ,
current = start;
var timer = setInterval(function() {
current += increment ;
if (current >= end) {
current = end;
self.style.opacity = 1;
clearInterval(timer);
}
self.innerHTML = current | 0;
}, refresh);
};
document.querySelector('.value').animateNumber(400, 500, 2000);
document.querySelector('.value1').animateNumber(0, 500, 2000, 10);
<div class="value">0</div>
<div class="value1">0</div>
the refresh rate is there to help you understand that the increment should be based on the quantity of steps in the animation instead of adjusting the refresh rate based on one by one increments;
you can also not add a refresh rate as I've added a default value;

Related

JS. setInterval does not increment value of variables in external scope

I trying to bring my timer update the value of all let variables. But unfortunally my setInterval fucntion does not want to do this.
Where is my problem located? Thanks
function defineInterval(intervalInHours = 1, precision = 3600, disableInterval = 900, time = 200000) {
let interval = 0
let timeLeftInInterval = 0
let timePercent = 0
let timeDisabled = 0
setInterval(() => {
interval = intervalInHours * precision;
timeLeftInInterval = (time % interval);
console.log(interval, 'interval', timeLeftInInterval, 'timeLeftInInterval ', timeDisabled, 'timeDisabled', timePercent, 'timePercent') // 3600, 2000, 1600, 59 on output
if (disableInterval >= timeLeftInInterval) {
timeDisabled = disableInterval - timeLeftInInterval;
timePercent = (timeDisabled / disableInterval) * 100;
} else {
timeDisabled = interval - timeLeftInInterval;
timePercent = (timeDisabled / (interval++ - disableInterval) * 100);
interval++
}
}, 1000)
}
defineInterval();
Possible issues:
interval = intervalInHours * precision; is getting reset to 3600 every time. Move it above setInterval.
You are not doing anything to change values in if statement, it's not impacting anything. Changing timeDisabled and timePercent is not impacting anything further. It will give same values after every timeout. Are you missing an interval++?
You are doing interval++ two times in your else statement.

Calculating FPS Javascript ( Do I make something wrong? )

Here is my calculateFPS function:
function calculateFPS() {
const now = performance.now();
if(fps.lastCalledTime !== null) {
fps.counter++;
const secondsPerFrame = (now - fps.lastCalledTime) / 1000;
fps.totalFPS += 1 / secondsPerFrame;
if(fps.counter === 20) {
fps.fps = Math.round(fps.totalFPS / fps.counter);
fps.totalFPS = 0;
fps.counter = 0;
}
}
fps.lastCalledTime = now;
}
Here is my fps global object:
let fps = {
lastCalledTime: null,
fps: 60,
counter: 0,
totalFPS: 0,
}
However when I see my game slowing down (the game is Mowing (if I translated it correctly)) basically the FPS should go down... instead it goes up to 400 - 500
Am I doing something wrong?
Thank you in advance...
You can calculate the time difference between two function calls as such
let then = performance.now();
let now;
let frame = 1000/60;
function animate() {
now = performance.now();
console.log(((now - then)/frame) * 60);
then = now;
}
setInterval(animate, frame);

How to pause and resume timer object

I am making a timer, well I am making timers...basically you can start one timer for something but then the idea is that in the middle of that you might want to start something else so you can pause it and start another one and then when that is done, you can resume the initial timer.
The timer object is working fine and I can get multiple timers going at the same time...my problem is that when i go to resume the first timer it waits for the amount of time that the other timer has been going before resuming.
I have a basic fiddle of it here: https://jsfiddle.net/1ea07uv9/19/
My apologies for the code...I have been messing around with it trying to get it to work it has become quite the mess...it doesnt work exactly the way I have it in my local environment but it illustrates my problem....in the fiddle if you click begin first timer...wait about ten seconds or so and then click on timer one it stops...for about 10 seconds and then continues...I need it to just continue straight away.
Im pretty sure that it has to do with the lines:
var diff = (new Date().getTime() - currentObj.start) - currentObj.time;
currentObj.timerInit = window.setTimeout(instance, (1000 - diff));
where currentObj.start is now however long you waited behind?
EDIT: It was requested I post my code in this post instead of just a fiddle so here it is
//Array where jobs will be stored
var jobs = [],
begin = false;
//Job object
function Job(name, active, s, m, h, elapsed){
var currentObj = this;
this.name = name;
this.seconds = s;
this.minutes = m;
this.hours = h;
this.time = 0;
this.elapsed = elapsed;
this.timeLimit = 28800;
this.completePercent = 0;
this.jobNumber = 0;
this.timer = function(begin){
var secondStr = '00',
minuteStr = '00',
hourStr = '00';
currentObj.start = new Date().getTime();
function instance(){
currentObj.time += 1000;
currentObj.elapsed = Math.floor(currentObj.time / 1000);
secondStr = currentObj.seconds.toString();
if(secondStr.length == 1){
secondStr = '0' + currentObj.seconds.toString();
}
minuteStr = currentObj.minutes.toString();
if(minuteStr.length == 1){
minuteStr = '0' + currentObj.minutes.toString();
}
hourStr = currentObj.hours.toString();
if(currentObj.seconds <= 58){
currentObj.seconds++;
}else{
currentObj.seconds = 0;
if(currentObj.minutes <= 58){
currentObj.minutes++;
}else{
currentObj.minutes = 0;
currentObj.hours++;
}
}
$('[data-job-id="'+currentObj.jobNumber+'"]').html(hourStr + ':' + minuteStr + ':' + secondStr);
var diff = (new Date().getTime() - currentObj.start) - currentObj.time;
currentObj.timerInit = window.setTimeout(instance, (1000 - diff));
}
if(begin){
currentObj.timerInit = window.setTimeout(instance, 1000);
}
}
this.pause = function(){
clearTimeout(this.timerInit);
}
}
//Create the snooze timer object and chuck it into the array
jobs.push(new Job('snooze', false, 0, 0, 0, 0));
//Begin specific timer
$('#timer_start').click(function(e){
e.preventDefault();
if(jobs.length <= 3){
//Create new job object and push it into the array
jobs.push(new Job('jobNameInput', true, 0, 0, 0, 0));
//Loop through all of the jobs and give it a number (according to its array position)
for(var i=0; i < jobs.length; i++){
jobs[i].jobNumber = i;
//Give the jobs their names but check we arent changing the snooze button!
if(i == jobs.length - 1){
jobs[i].timer(true);
}
}
}else{
alert('sorry mate...you can only have 3 jobs!');
}
});
//Switch timer
$('.start').click(function(){
var thisTimer = $(this).next('.time').attr('data-job-id');
for(var i=0; i < jobs.length; i++){
jobs[i].pause();
}
jobs[thisTimer].timer(true);
});

Increment from zero to number in a set time

I am trying to increment from 0 to a number (can be any number from 2000 to 12345600000) within a certain duration (1000 ms, 5000 ms, etc). I have created the following:
http://jsfiddle.net/fmpeyton/c9u2sky8/
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
var duration = 1000;
var animationInterval = duration/counterTotal;
counterElement.text("0");
var numberIncrementer = setInterval(function(){
var currentCounterNumber = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
if (currentCounterNumber < counterTotal){
currentCounterNumber += Math.ceil(counterTotal/duration);
// convert number back to comma format
// currentCounterNumber = addCommas(currentCounterNumber);
counterElement.text(currentCounterNumber);
} else {
counterElement.text(counterTotal);
clearInterval(numberIncrementer);
}
console.log("run incrementer");
}, animationInterval);
function addCommas(number){
for (var i = number.length - 3; i > 0; i -= 3)
number = number.slice(0, i) + ',' + number.slice(i);
return number;
}
And this somewhat works, but it does not respect the duration. I.e. if you increase the number from 1000 to 1000000000, they both take different amounts of time to reach the destination number.
How can I increment from zero to a number in a specific time frame?
As #Mouser pointed out, the issue is that the animationInterval can't be too small (the actual minimum threshold will vary based on the browser and platform). Instead of varying the interval, vary the increment to the counter:
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.text()/*.replace(/,/g, "")*/);
var duration = 1000;
var animationInterval = 10;
var startTime = Date.now();
counterElement.text("0");
var numberIncrementer = setInterval(function(){
var elapsed = Date.now() - startTime;
var currentCounterNumber = Math.ceil(elapsed / duration * counterTotal);
if (currentCounterNumber < counterTotal){
counterElement.text(currentCounterNumber);
} else {
counterElement.text(counterTotal);
clearInterval(numberIncrementer);
}
console.log("run incrementer");
}, animationInterval);
I played around with your fiddle and found that the delay needs to be higher. At 8ms or 16ms, it is accurate enough to handle a second, but not accurate enough to handle half a second. From experimenting, it seems like a delay of 64ms is small enough to seem like it's incrementing smoothly, but big enough to have an accurate effect.
The difference is that the current number is calculated based on the process rather than directly manipulated.
var counterElement = $(".lg-number");
var counterTotal = parseInt(counterElement.data('total'));
var interval = 0;
var duration = parseInt(counterElement.data('duration'));;
var delay = 64
var numberIncrementer = setInterval(function(){
var currentCounterNumber = 0;
interval += delay;
if (interval <= duration){
var progress = interval / duration;
currentCounterNumber = Math.round(progress * counterTotal);
} else {
currentCounterNumber = counterTotal
clearInterval(numberIncrementer);
}
counterElement.text(currentCounterNumber);
}, delay);
http://jsfiddle.net/c9u2sky8/5/
Also: Javascript timers are not perfectly accurate. But this should be accurate enough for UI use cases.

Timer counting faster on second run

I am working on a simple game right now. its almost done except for the timer has a glitch in it and I can't figure out whats doing it. when you push a button, an HTML5 text on the canvas starts to count down from 35 to 0. On the first run it's fine. But if you choose to play again with out refresh the timer starts to countdown faster. here is the code.
var timer = 35;
ctx.fillText("Countdown: " + timer, 320, 32);
function resetReggie(){
reggie.x = canvasWidth / 2;
reggie.y = canvasHeight / 2;
}
//Starts Timer for Timed Game
function timedMsg()
{
resetReggie();
ballsCaught = 0;
timer = 35;
alert('Pick up as many as you can in ' + timer + ' seconds');
countDown();
var t=setTimeout(function() {
var again = confirm("TIMES UP! You Gathered " + ballsCaught + " Balls! Play Again?");
if (again === true){
timedMsg();
resetReggie();
}
if (again === false){
resetReggie();
ballsCaught = 0;
timer = 35;
}
}, timer * 1000);
}
function countDown() {
if (timer != 0){
timer-=1;
setTimeout('countDown()', 1000);
}
}
I think the problem is in the line
}, timer * 1000);
where you have a value that is at most 34 at the time 'timer' is evaluated to set the timeout. Because you initialize it to 35 but then call countDown() which decreases it to 34, then you have a call to confirm() which might let 'timer' decrease even more. As a result the subsequent call to timedMsg() happens a little too soon causing countDown() to be called twice as often. Try the following (I ran it in node) and then change the 4 to 6.
function countDown() {
console.log("Countdown: " + timer, 320, 32);
if (timer != 0) {
timer -= 1;
setTimeout(countDown, 1000);
}
}
function timedMsg() {
timer = 5;
countDown();
var t=setTimeout(function() {
timedMsg();
}, 4 * 1000);
}
timedMsg();
As mentioned in my comment, each time you start a new game, it appears you are decreasing the timeout value. As a result, this reduces the time each time.
Try this:
var timeout = currentTime = 5;
var int = setInterval(function() {
​console.log(currentTime);
currentTime--;
if(currentTime < 0) {
var again = confirm('Play again?');
if(again) {
currentTime = timeout;
}
else {
clearInterval(int);
}
}
}, 1000);​
http://jsfiddle.net/gRoberts/CsyYx/
Look at your console (F12 in Chrome), or update the code to write to the browser to see it working ;)

Categories

Resources