Incrementing a number smoothly with a variable time period in JS - javascript

I have a really simple JS counter which I display on a dashboard like screen which does the following:
Every 5 minutes it makes an jsonp call and retrieves a "total" number
It then displays this number to the screen by incrementing the last total displayed till it is equal to the new total. (the number can only ever increase)
I'm having some trouble with making the number increment smoothly. What I would like to do is find a delta (i.e. New total - old total) and increment the number gradually over the 5 minutes till the next call so it looks like a nice smooth transition.
Any ideas on how I can do this?
Currently some of my code looks like this (This block get's called every 5mins. And yes, it's in dire need of a refactor...)
var LAST_NUMBER_OF_SESSIONS = null;
var five_minutes_in_seconds = 300;
var new_number_of_sessions;
$.getJSON('http://blah.com/live_stats/default_jsonp.aspx?callback=?', function(data) {
if(LAST_NUMBER_OF_SESSIONS === null){
LAST_NUMBER_OF_SESSIONS = data.total_sessions;
}
new_number_of_sessions = data.total_sessions;
var delta = Math.floor(new_number_of_sessions - LAST_NUMBER_OF_SESSIONS);
var time_interval = (five_minutes_in_seconds / delta) * 1000;
var old_value = LAST_NUMBER_OF_SESSIONS;
var new_value = null;
sessions_interval = setInterval(function (){
new_value = parseInt(old_value, 10) + 1;
$('#stats').text(new_value);
old_value = new_value;
if(new_value >= new_number_of_sessions){
clearInterval(sessions_interval);
}
}, time_interval);
LAST_NUMBER_OF_SESSIONS = new_value;
});
}
This code it seems to increment the number very quickly at the start of the 5min period and then stop so it's not exactly right...

Try this:
var total = 0,
delta = 0,
stats = $('#stats').text( total );
function increment() {
var v = +stats.text();
if ( v < total ) {
stats.text( v + 1 );
} else {
$.getJSON('http://...', function(data) { // added data here
delta = Math.floor( 300000 / ( data.total_sessions - total ) );
total = data.total_sessions;
});
}
setTimeout(increment, delta);
}
Update:
In order to test my code, I had to simulate the JSON reponse - I used an array of numbers. See here: http://jsfiddle.net/simevidas/MwQKM/
(In the demo, I use an interval of 5 seconds instead of 5 minutes.)

I am not exactly sure why your code doesn't work as expected, although I suspect that it has to do with line LAST_NUMBER_OF_SESSIONS = new_value;. I wrote something similar and it works fine. It's not that different from what you have, minus that last line of code.

Related

Subtracting current hour’s value from previous hour’s value using javascript

I got my first touch with js yesterday and i got this small task to do a small script in bulding controller. I am reading values from certain location and calculating energy, and after 1 hour I should read the same values and subtract them to get get delta energy delta. The script should run constantly so Im using while(1) sleep(3,6 * 1000000)
Here is my code where I'm at
function summa() {
var E1 = (parseFloat(read("location1","value1")) *
parseFloat(read("location11","value11"))) / Math.pow(10,6)
executePropertyCommand("object1","Value","Write", E1)
var E2 = (parseFloat(read("location2","value2")) *
parseFloat(read("location22","value22"))) / Math.pow(10,6)
executePropertyCommand("object2","Value","Write", E2)
var IT_Sum = (E1 + E2)
return IT_Sum}
setTimeout(summa1,3.599 * 1000000);{
function summa1() {
var E1 = (parseFloat(read("location1","value1")) *
parseFloat(read("location1","value1"))) / Math.pow(10,6)
var E2 = (parseFloat(read("location2","value2")) *
parseFloat(read("location22","value2"))) / Math.pow(10,6)
var IT_Sum1 = (E1 + E2)
return IT_Sum1 }}
while(1) {
var sum1 = summa()
var sum2 = summa1()
var IT_delta = summa2 - summa1
sleep(3.6 * 1000000)}
I've tried to locate the settimeout in different locations like into the while loop but i cant seem to get the sum2 to wait for the delay.
Any ideas for better way to calculate the subtraction of same data in 1 hour loops?
You can add values to the array every hour and then calculate the difference of adjacent indexes.
To run code every hour use window.setTimeout and pass callback and time.
// array with values added each hour
var numbers = [];
function runHourly() {
var dateNow = new Date();
var mins = dateNow.getMinutes();
var secs = dateNow.getSeconds();
var interval = (60*(60-mins)+(60-secs))*1000;
if (interval > 0) {
window.setTimeout(runHourly, interval);
}
// your code for calculating delta goes here
numbers.push(summa());
if(numbers.length >= 2) {
var IT_delta = numbers[1] - numbers[0];
// do something with delta here
// shift array for getting delta in an hour for new values…
numbers.shift();
}
}

Unable to loop over table rows to animate respective progress bars

Ok, for brevity's sake, I'm just including the javascript code itself. If the HTML or CSS is really needed, I'll update the post.
The objective: I've got a table with rows (displaying tasks), and I have a progress bar to the right of each task showing how much time has elapsed.
The problem: only the first progress bar works. All subsequent progress bars just show a completely filled-up bar. Upon looking at the console log, the program isn't looping at all. It performs no calculations for any rows other than the first. I've tried moving various variables inside and outside the loop, but no cigar.
Please forgive me if the code looks terrible and/or the answer is obvious. This is essentially my first real javascript 'program.'
var Table = document.getElementsByTagName("table");
var Row = document.getElementsByTagName("tr");
var rowDisplay = document.getElementsByTagName("td");
function fillBar(timeElapsedPercent) {
for (i = 0; i < rowDisplay.length; i++) {
var eachRow = rowDisplay.item(i);
const interval = setInterval(() => {
// Grabbing the needed info from the cells
var taskName = rowDisplay[0].innerText;
var rawDeadline = rowDisplay[1].innerText;
var rawStartTime = rowDisplay[2].innerText;
var bar = document.querySelector('.bar');
//calculations for the progress bar
var now = new Date();
var startTime = new Date(rawStartTime.replace(/(am|pm)/, ''));
var deadline = new Date(rawDeadline.replace(/(am|pm)/, ''));
var timeTotal = Math.abs(deadline - startTime);
var timeTotalPercent = Math.abs(timeTotal / 60000);
console.log('value for total time in minutes of', taskName, 'is', timeTotalPercent);
var nowTillDeadline = Math.abs(deadline - now);
var nowTillDeadlinePercent = Math.abs(nowTillDeadline / 60000);
var timeElapsed = Math.abs(timeTotalPercent - nowTillDeadlinePercent);
var timeElapsedPercent = Math.abs((timeElapsed / timeTotalPercent) * 100);
// moving the progress bar
bar.style.width = timeElapsedPercent + '%';
if (timeElapsedPercent >= 99) {
bar.style.width = '100%';
clearInterval(interval);
}
}, (1*1000))
}
}
fillBar();
All right then, time to answer my own question again.
I'll include the HTML for the row, then the Javascript to manipulate it:
<td class="col-sm-4">
<div id="progressBarBackground">
<div class="bar" id="progressBar"></div>
</div>
</td>
function fillBar() {
const interval = setInterval(() => {
var i;
for (i = 1; i < Table.rows.length; i++) {
// grabbing relevant info from DOM
var taskName = Table.rows[i].cells[0].innerText;
var rawDeadline = Table.rows[i].cells[1].innerText;
var rawStartTime = Table.rows[i].cells[2].innerText;
var bar = Table.rows[i].cells[6].getElementsByClassName("bar").item(0);
// calculations for progress bar
var now = new Date();
var startTime = new Date(rawStartTime.replace(/(am|pm)/, ''));
var deadline = new Date(rawDeadline.replace(/(am|pm)/, ''));
var timeTotal = Math.abs(deadline - startTime);
var timeTotalPercent = Math.abs(timeTotal / 60000);
var nowTillDeadline = Math.abs(deadline - now);
var nowTillDeadlinePercent = Math.abs(nowTillDeadline / 60000);
var timeElapsed = Math.abs(timeTotalPercent - nowTillDeadlinePercent);
var timeElapsedPercent = Math.abs((timeElapsed / timeTotalPercent) * 100);
// manipulating the necessary DOM element
bar.style.width = timeElapsedPercent + '%';
if (timeElapsedPercent >= 99) {
bar.style.width = '100%';
clearInterval(interval);
}
}
}, (1*1000))
}
So my problems were as follows:
1) The for-loop needs to be inside the interval, not the other way around. I read somewhere that an interval is basically just a timed for-loop. That was a light bulb moment for me.
2) Using .querySelector() to get the progress bar only gets the first one, even if it's in the for-loop; to get the progress bar for each row, the .getElementsByClassName() method was needed in addition to the .item() method with its index position, which you would never know from the error code you get if you leave it out. Since I only had one element within the cell to get, its index position is 0.
3) At the start of my for-loop, I changed from displayRows.length to Table.rows.length, but in order to do that, I had to change the way I defined var Table. Instead of .getElementsByTagName(), I used get .getElementById() -- for my fellow noobs, note it's just one Element, not Elements.
I think those were the three main issues. There were probably other minor issues, but I tried about 100 different things between now and when I first posted the problem, so it's hard to know.
I also made use of console.log at various points while I was troubleshooting everything. I deleted those lines here for the sake of code neatness, but they were immensely helpful.

Increment Bitcoin Numerif Format Javascript

Hello why i try to coding something like a counter for bitcoin. this is the Code
result: <div id="counter"></div>
This is the Html
This is Javascript Code
var INTERVAL = 1; // in seconds
var INCREMENT = (0.00000001).toFixed(8); // increase per tick
var START_VALUE = (0.00000001).toFixed(8); // initial value when it's the start date
var count = 0;
$(document).ready(function() {
var msInterval = INTERVAL * 3000;
count = INCREMENT + START_VALUE;
document.getElementById('counter').innerHTML = count;
window.setInterval( function(){
count += INCREMENT;
document.getElementById('counter').innerHTML = count;
}, msInterval);
});
Heres the Output you can check
https://jsfiddle.net/8eqc2b3t/
Can anyone help
First of all, I've modified your code a little to make a bit more sense, you're using a few keywords that could be reserved within certain languages, so I'd avoid that in future ( like using count as a variable name )
var interval = 1; // in seconds
var increasePerTick = (0.00000001).toFixed(8); // increase per tick
var startingValue = (0.00000001).toFixed(8); // initial value
var $counter = $('#counter');
var btcAmount = 0.00000000;
$(document).ready(function() {
var msInterval = interval * 1000; // Convert to Milliseconds
$counter.text(startingValue); // Set initial amount
window.setInterval( function(){
btcAmount = (parseFloat(btcAmount)+parseFloat(increasePerTick)).toFixed(8);
$counter.text(btcAmount);
}, msInterval);
});
The main issue was that when you were using the + operand you were adding to the string rather than adding the two floats together. You'd also not added jQuery to your Fiddle, causing it not to work, I've fixed this and shown how to do the calculation here too, which basically is to parse both the floats, set them toFixed(8) and then print them to the counter.
The addition part is here:
btcAmount = (parseFloat(btcAmount)+parseFloat(increasePerTick)).toFixed(8);
You were also converting your msInterval incorrectly. Now seconds in interval should work out correctly when changed.
Hope this helps.
Edit:
Forgot to add the Fiddle, sorry! : https://jsfiddle.net/20Lppogq/

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.

Javascript decimal increment?

I've got the following variable JS:
http://jsfiddle.net/c8u8wLsL/13/
$(document).ready(function () {
var total = 15.5,
value = 0,
elem = $('div');
var interval = setInterval(function () {
elem.text(value.toFixed(1) + '$');
if (value >= total) {
clearInterval(interval);
}
value = value + 0.1;
}, 5);
});
Two questions:
The resulting number is 15.6 why?
How can I make the incrementation spend the same amount of time from 0 to the target value? (from 0 to 25 spends the same time as from 0 to 250)
You forget to exit from function. Also you should probably update node's text after checking total.
if (value >= total) {
return clearInterval(interval);
}
elem.text(value.toFixed(1) + '$');
fiddle http://jsfiddle.net/Lqxsh39q/
To solve second problem you can pre-calculate duration of each interval before it setup. And use it like second argument in setInterval. Something like duration = 1000 / (total * 10); or any formula that you want.
fiddle: http://jsfiddle.net/Lqxsh39q/1/
#Glen Swift's answer is correct but I have to point out regarding your original code:
You get the resulting number as 15.6 because:
When you think you are getting 15.5 as the result, you are actually getting 15.4999999, which is smaller than 15.5 and hence the if condition is false even if you think it is true. So it gets incremented once again, giving the final result as 15.6.
As far as the second part is concerned, to get the same time, you need to have the same number of steps for each addition rather than the fixed 0.1. Let's say you want to reach the target in 100 steps everytime, you can divide the total interval by 100 and then replace it in the code where you are writing 0.1 currently.
The final code should look something like:
$(document).ready(function () {
var total = 15.5,
value = 0,
ment=(total-value)/100,
elem = $('div');
var interval = setInterval(function () {
if (value >= total) {
return clearInterval(interval);
}
elem.text(value.toFixed(1) + '$');
value = value + ment;
}, 5);
});
See the fiddle here
Your existing code:
var interval = setInterval(function () {
elem.text(value.toFixed(1) + '$');
if (value >= total) {
clearInterval(interval);
}
value = value + 0.1;
}, 5);
It should check for the >= total condition first. if condition fails then exit the function.
But you are modifying the text element before the check. thus your error.
This would do.
var interval = setInterval(function () {
value = value + 0.1;
if (value <= total) {
elem.text(value.toFixed(1) + '$');
} else {
clearInterval(interval);
}
}, 5);

Categories

Resources