How to get smooth counter animations - javascript

I should display an animated counter. Ideally, there should be an continous animation of the number change. The situation looks like the following:
I get every minute a new value.
The counter should show the real value (no fake).
There are times where there is no value change.
Sometimes there counter should spin faster and sometimes slower (depending on the value change).
My idea was to use the last two values and animate between them. Depending on the difference the speed has to change. But I didn't find a counter which allows to change the speed afterwards. Or do you have another idea?
How are all the other websites with a counter doing it? Do they fake?
Edit:
I tried different counter - currently I'm using jOdometer. My current code base is:
var counter = $('.counter').jOdometer({
counterStart: '0',
numbersImage: '/img/jodometer-numbers-24pt.png',
widthNumber: 32,
heightNumber: 54,
spaceNumbers: 0,
offsetRight:-10,
speed:10000,
delayTime: 300,
maxDigits: 10,
});
function update_odometer() {
var jqxhr = $.getJSON("/number.php?jsonp=?")
.done(function(data){
console.log(data);
total = data['Total'];
counter.goToNumber(total);
})
.fail(function(data){
console.log(data);
});
};
update_odometer();
setInterval(update_odometer, 60000);
The counter currently counts from zero to my number, but I want to change this behavior (counting from the next-to-last to the last value - but I have problems with my AJAX call [see here]). It is also possible that I change the library if needed. I looked into jquery.jodometer.js and perhaps I get it working to create a function which changes the speed on the fly.
But the reason why I didn't attached the code was that I search for the programming procedure behind the code. Is it possible to get such a live counter? How does the procedure does look like?
Solution:
Setting the speed solves the problem because the library does the animation for me:
speed:60000
You only have to match the speed of the animation with the update interval.

A simple for loop from current value to value to be updated should solve your problem.
Inside your done function,
for(var i=current_odo_value; i<=data['Total']; i++) {
counter.goToNumber(i);
}
If you can control the speed in your library, this ought to do it. Since the speed is directly proportional to the difference between current value and updated value, that difference can be sent to plugin as the required speed value.
I'm assuming only increase in fetched total value. If it can decrease as well, you need to handle that condition as well.

Related

Why does my programmatic approach to changing CSS animation duration not work?

I have a collection of animations that have their duration assigned to a variable with the starting value of zero. After their first run (which is upon page loading), I would like to be able to change that duration to a non-zero value to get the animation effect I'm going for.
The following code should allow me to set the value of --real-dock-animation-time (what the animations use) to the value of --dock-animation-time after all of their first run, so that the previous value of zero can be changed to animate the desired changes only after the page is loaded.
let animationTimeDetermined = false;
function determineAnimationTime() {
if (!animationTimeDetermined) {
animationTimeDetermined = true;
let r = document.querySelector(':root');
let time = getComputedStyle(r).getPropertyValue("--dock-animation-time");
r.style.setProperty('--real-dock-animation-time', time);
}
}
document.addEventListener("DOMContentLoaded", () =>
Promise.all(document.getElementsByClassName("dynamicHeader")[0].getAnimations().map((anim) => anim.finished)).then(
determineAnimationTime()
))
What ends up happening, though, is it just appears as if it was the non-zero value to begin with and it animates on page load. How can I change the value only after I'm sure the animations' first runs are completed?
I have tried using setTimeout and parsing the CSS's non-zero value to milliseconds, but the imprecise nature of the timer system makes it flicker when the page loads.
If there's another way to get what I'm after that doesn't involve using JS to change the animation times, please let me know. The CSS's values are changed at the very beginning of the page's lifetime because I am setting attributes within the JS.

How to sleep a certain amount of seconds in the Phaser-Framework

In my game i'm trying to make a variable go up gradually, so i need to be able to sleep a certain amount of time before I increment the variable again.
1) Use a timer. This will allow you to execute one off delayed events, or execute that function call repeatedly.
An example, as the phaser website basically gives you examples of everything if you search for it,
http://phaser.io/examples/v2/time/basic-timed-event
Also, from the docs
http://phaser.io/docs/2.4.8/Phaser.Timer.html
Should you need to repeat, note the function "loop" (I would post the link, but i don't have enough reputation yet).
2) The alternative is simply to tie in to Phaser's game tick. Within your state (if this is where you are executing you variable incrementation), create an update function (this will be called every game update). You can access time since last update.
Look up the class Phaser.Timer (again, i cannot post the link).
See the properties elapsed and elapsedMS. You could use this to manually track time elapsed since your last incremental event (behind the scenes, this is basically what phaser tweens or timed events are doing).
eg:
var timeSinceLastIncrement = 0;
function update()
{
// Update the variable that tracks total time elapsed
timeSinceLastIncrement += game.time.elapsed;
if (timeSinceLastIncrement >= 10) // eg, update every 10 seconds
{
timeSinceLastIncreemnt = 0;
// Do your timed code here.
}
}
Note, that option 1 is cleaner, and likely to be the preferred solution. I present option 2 simply to suggest how this can be done manually (and in fact, how it is generally done in frameworks like phaser behind the scenes).

Most efficient way to throttle continuous JavaScript execution on a web page

I'd like to continuously execute a piece of JavaScript code on a page, spending all available CPU time I can for it, but allowing browser to be functional and responsive at the same time.
If I just run my code continuously, it freezes the browser's UI and browser starts to complain. Right now I pass a zero timeout to setTimeout, which then does a small chunk of work and loops back to setTimeout. This works, but does not seem to utilize all available CPU. Any better ways of doing this you might think of?
Update: To be more specific, the code in question is rendering frames on canvas continuously. The unit of work here is one frame. We aim for the maximum possible frame rate.
Probably what you want is to centralize everything that happens on the page and use requestAnimationFrame to do all your drawing. So basically you would have a function/class that looks something like this (you'll have to forgive some style/syntax errors I'm used to Mootools classes, just take this as an outline)
var Main = function(){
this.queue = [];
this.actions = {};
requestAnimationFrame(this.loop)
}
Main.prototype.loop = function(){
while (this.queue.length){
var action = this.queue.pop();
this.executeAction(e);
}
//do you rendering here
requestAnimationFrame(this.loop);
}
Main.prototype.addToQueue = function(e){
this.queue.push(e);
}
Main.prototype.addAction = function(target, event, callback){
if (this.actions[target] === void 0) this.actions[target] = {};
if (this.actions[target][event] === void 0) this.actions[target][event] = [];
this.actions[target][event].push(callback);
}
Main.prototype.executeAction = function(e){
if (this.actions[e.target]!==void 0 && this.actions[e.target][e.type]!==void 0){
for (var i=0; i<this.actions[e.target][e.type].length; i++){
this.actions[e.target][e.type](e);
}
}
}
So basically you'd use this class to handle everything that happens on the page. Every event handler would be onclick='Main.addToQueue(event)' or however you want to add your events to your page, you just point them to adding the event to the cue, and just use Main.addAction to direct those events to whatever you want them to do. This way every user action gets executed as soon as your canvas is finished redrawing and before it gets redrawn again. So long as your canvas renders at a decent framerate your app should remain responsive.
EDIT: forgot the "this" in requestAnimationFrame(this.loop)
web workers are something to try
https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers
You can tune your performance by changing the amount of work you do per invocation. In your question you say you do a "small chunk of work". Establish a parameter which controls the amount of work being done and try various values.
You might also try to set the timeout before you do the processing. That way the time spent processing should count towards any minimum the browsers set.
One technique I use is to have a counter in my processing loop counting iterations. Then set up an interval of, say one second, in that function, display the counter and clear it to zero. This provides a rough performance value with which to measure the effects of changes you make.
In general this is likely to be very dependent on specific browsers, even versions of browsers. With tunable parameters and performance measurements you could implement a feedback loop to optimize in real-time.
One can use window.postMessage() to overcome the limitation on the minimum amount of time setTimeout enforces. See this article for details. A demo is available here.

Javascript, object with set lifetime?

I have run in to a problem I do not know how to code in JavaScript really. The thing is I would like to be able to create a lot of objects added to an Array. when objects are created to be added to this array they will have a "lifetime". When this lifetime runs out this object should be removed from the array.
What Im trying to build here is a particle system where particles will vanish from being rendered after the particles lifetime in question have expired.
Anyone who have a good idea or example for this?
I have thought about using setTimeout, setInterval and clearInterval but not sure how this would be most effective.
Something like this?
Update for Felix Kling:
var a = [], next = function() {
a = a.slice(0,-1);
document.body.innerHTML += a.length + "<br />";
if (a.length != 0)
setTimeout(next, 100);
};
for (var i = 0; i < 100; i++) {
a.push({hi: 1});
}
setTimeout(next, 100);​
You can use the code sample of micha. On every call of "next" function you can update the state of you particles (position, velocity, etc). Also you can track the time of the creation of the particles and on every "next" call check if the current time minus the creation time exceeds certain constant and if it does then remove the particles. Depending on the required quality of the animation you may want to reduce the time between timeouts, e.g. setTimeout(next, 25);
Good luck :)

Issue with a javascript jQuery script in OpenX

I'm using OpenX at work, and one of my boss requirements is a expandable banner. For that (and made a horrible simplification of the whole story) I made this script.
function retro(){
var acs = jQuery('#trial_center').height() - 5;
jQuery('#trial_center').css('height', acs + 'px');
}
jQuery(document).ready(function(){
jQuery("#trial_center").mouseover(function(){
setTimeout("jQuery('#trial_center').css('height', '500px')", 1000);
})
jQuery("#trial_center").mouseleave(function(){
var c = 89;
while (c > 0) {
setTimeout("retro()", 1000);
c--;
}
})
});
The problem I have is in the mouseleave event: the original idea was to made this loop several times (89 times), and each time, decrease the height of the banner until it get his original size. Why this? Because my boss want an "effect", and this effect must be in sync with the customer's flash.
The problem is that instead of decrease his size progressively, apparently the script made all the operations an "after" the sum of setTimeout calls, updated the page. So, the result is exactly as the banner shrinks one time from the expanded size to the original size.
I don't know what is wrong with this, or if exists other more intelligent solution.
Any help will be very appreciate.
Thanks in advance
Your loop setting the timeout is just setting 89 timers for one second later than the loop runs, and the loop will run in milliseconds — so they'll all fire about a second later. That doesn't sound like what you want to do.
Two options for you:
1. Use animate
jQuery's animate function seems like it does what you want. You can tell jQuery to animate the size change, and you tell it how long to take to do so:
jQuery('#trial_center').animate({
height: "500px" // Or whatever the desired ending height is
}, 1000);
That will animate changing the height of the container from whatever it is at the point that code runs to 500px, across the course of 1,000 milliseconds (one second). Obviously you can change the duration to whatever you like.
2. Set up the timer loop manually
If for whatever reason you don't want to use animate, you can do this manually (of course you can; jQuery can't do anything you can't do yourself, it just makes things easier). Here's how to set up a timer loop:
jQuery("#trial_center").mouseleave(function(){
var c = 89;
// Do the first one right now, which will schedule the next
iteration();
// Our function here lives on until all the iterations are
// complete
function iteration() {
// Do one
retro();
// Schedule this next unless we're done
if (--c > 0 {
setTimeout(iteration, 100); // 100ms = 1/10th second
}
}
});
That works because iteration is a closure over c (amongst other things). Don't worry about the term "closure" if it's unfamiliar, closures are not complicated.
Separately: You're using mouseover to set the height of the trial_center element a second later; you probably wanted mouseneter rather than mouseover. mouseover repeats as the mouse moves across it.
Off-topic:
It's best not to use strings with setTimeout; just pass it a function reference instead. For example, instead of
setTimeout("retro()", 1000);
you'd use
setTimeout(retro, 1000); // No quotes, and no ()
And for the other place you're using, instead of
setTimeout("jQuery('#trial_center').css('height', '500px')", 1000);
you'd use
setTimeout(function() {
jQuery('#trial_center').css('height', '500px');
}, 1000);

Categories

Resources