Javascript Intval Show/Hide Flickering - javascript

I'm trying to cycle real fast through a series of images to produce an animation using the below setInterval. However, if I move focus away from the browser tab and then back again, the animation flickers.
I saw a thread about using "real time" to catch the animation up, but since mine uses a simple show/hide, I wasn't sure how that applied.
var animation = setInterval(function(){
var visible = $j('#container img:visible');
var next = visible.next('img');
if(next.length <= 0) next = $j('#container img:first');
next.show();
visible.hide();
},64);
Any thoughts on how to combat the flickering?

Traditionally, JavaScript animation can be handled a number of ways. One approach involves using a timing function such as setTimeout or setInterval to adjust styling every couple milliseconds. Another approach creates a loop that changes styling as many times as possible along the animation’s time frame. The logic of both of these approaches is to throw a large number of animation frames at the browser, so that it hopefully renders smooth-looking motion.
So, even though the browser renders as many frames of the animation as possible, the dropped frames still make for a choppy-looking animation, which is not to mention the performance implications of overloading the processor with as many tasks as possible.
In reality, it’s actually better to render fewer frames, provided they are rendered consistently. That’s because our eyes pick up these subtle variations, and a few dropped frames tend to stick out more than an overall lower frame rate. That’s where HTML5′s requestAnimationFrame API comes in.
Here is an example for your scenario:
function animation(){
var visible = $('#container img:visible');
var next = visible.next('img');
if(next.length <= 0) next = $('#container img:first');
next.show();
visible.hide();
};
setInterval(function() {
window.requestAnimationFrame(animation);
}, 64);
DEMO

Related

JavaScript scroll based animation is choppy on mobile

I have 2 divs (left and right) and i want to scroll the left based on the right.
https://jsfiddle.net/3jdsazhg/2/
This works fine on desktop, but when i change to mobile, it's not smooth anymore...
This can be noticed very easily, by changing
_left.style.top = _content.scrollTop - (_content.scrollTop * ratioLeftRight) + 'px';
to
_left.style.top = _content.scrollTop + 'px';
Where it should act as a fixed positioned div
I would like to know the exact reason why this isn't smooth... I know that it's not the animation. Simple animation on the div is smooth, the issue comes up when it's based on scroll.
How can i make this animation smooth?
It's probably choppy because it's being fired ALOT when being scrolled, in fact i'm pretty sure IOS mobile pauses the javascript execution whilst the user is scrolling.
Instead I'd suggest using an interval, you could tweak the time between each interval to what feels good for your use-case.
Although it may seem intensive that it's firing this logic every X millisecond when using the scroll event you could be firing the event off hundreds of times per second, which is going to be far more intensive and noticeable to a user using a device with limit processing power.
(function () {
var interval = null,
//Currently set at 0.4 seconds, play with the code
//and change this value to see what works best for
//this use-case
time_between_interval = 400;
setInterval(scrollLogic, time_between_interval);
function scrollLogic () {
//The function body of what you're assigning
//to the scroll event.
}
//I have omitted clearing the interval but you would want to do that, perhaps on page change, or something.
//clearInterval(interval);
})();
I finally managed to think out a solution.
From my point of view, i'm guessing the mobile view fires the scroll event less often and because we are scrolling the wrapper, we first scroll the whole page and then scroll back with js the left part and because it's different from the desktop version, this issue becomes visible...
The solution was to change the left side to fixed position, and substract from the top instead of adding to it.
_left.style.top = -(_content.scrollTop * ratioLeftRight) + 'px';

Make requestAnimationFrame() Animation Persist When on Different Tab

When you are using requestAnimationFrame() for animation, the animation persists when you change browsers but not when you change tabs within your browser. The animation seems to pause.
For example, this animation.
http://pixijs.github.io/examples/index.html?s=basics&f=spritesheet.js&title=SpriteSheet%20Animation
Is there a way to make the animation persist even when you are in a different tab?
Your question isn't actually PIXI specific. It's about how the browser handles screen updates.
PIXI applications typically update each frame using the common Javascript function Window.requestAnimationFrame().
This function tends to pause when you switch tabs. From the docs:
The callback rate may be reduced to a lower rate when running in background tabs or in hidden <iframe>s in order to improve performance and battery life.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
So the short answer is no,
HOWEVER you can easily simulate it by keeping keep track of the time elapsed between updates, and move your animation forward accordingly.
In the PIXI example you provided, change the animate() function to this code below, and re-run it. Switch tabs, and when you switch back, you will see that the animation appears to continue as though you never switched tabs. Hope that helps! :)
var lastUpdate = new Date();
function animate() {
//Determine the amount of time since last frame update
var now = new Date();
var elapsed = now - lastUpdate;
lastUpdate = now;
//Update the rotation based on time elapsed
movie.rotation += elapsed/1000;
// render the stage container
renderer.render(stage);
requestAnimationFrame(animate);
}

CSS/JS scrolling glitch effect (performance)

I am trying to achieve a "crt-like" scrolling glitch effect using Javascript and CSS. I have come up with the following code which clones the content and applies clip to make it look like it scrolls while adding random horizontal offset.
function scanglitch() {
var e = $('#wrapper').clone().appendTo('#glitchcontainer');
var i = 0;
e.css({"clip": "rect(" + i + "px,3830px," + (i + 15) + "px,0px)"});
e.css("z-index",200);
var interval = setInterval(function () {
e.css({"clip": "rect(" + i + "px,3830px," + (i + 15) + "px,0px)"});
e.css({"left": Math.round(Math.random() * 10) + "px"});
i+=4;
if (i > window.innerHeight) {
e.remove();
window.clearInterval(interval);
}
}, 40);
}
Fiddle (Click on the text to see the effect)
I am actually quite pleased with the effect, but the implementation is obviously a hack. As a result the performance is unacceptably low (chrome cpu usage spikes from 5% to 50% when the effect is triggered).
Could someone help me figure out a way to achieve this effect in a more elegant and less performance-heavy way?
UPDATE:
I have implemented your suggestions: Using translate instead of left, scrolling with translate instead of a js loop, calculations outside of the css tag and using requestAnimationFrame(). The code is nicer and more predictable now, but the animations are still very taxing.
New fiddle
You can try using requestAnimationFrame (it is available in almost all browsers). Seems to make a big difference in Chrome.
JSFiddle
EDIT
Here's a transition-only version, and while it doesn't even implement the jitter, it's useful for comparison. Surprisingly(?) it shows about the same, if not more, CPU usage. (You can check the Profile and Timeline tabs in Chrome)
CSS3 Transition-Only JSFiddle
Here's some information about why that should be expected. Essentially, CSS transitions and requestAnimationFrame work very similarly under the hood.
I would delegate as much as possible to css transitions. So instead of moving the clip with js in the interval callback, transition it from top to bottom (example of transitioning).
You could try something similar with the left property, there's no random easing function but maybe you could achieve something similar with one of the bounce functions. Maybe change the easing function with an interval that's less frequent than your current one.
Also, just by slowing the interval of your current solution you'd get visually ok results with less CPU usage.
Side-note: for a completely different route you can replicate your html in a canvas and apply some effects to that. Google has plenty of results for "canvas glitch".
Update: here's my version of your latest fiddle
I get about 10 % less cpu usage with it when comparing to yours. Key differences are:
uses a timeout instead of requestAnimationFrame. requestAnimationFrame is meant to keep framerate high and the animation smooth but we don't need that for the random offsetting. Timeout is also better than an interval since the loop function is quaranteed to finish before next iteration starts.
removed the transparent background, since transparency has a rendering cost

Control sprite animation speed

How can I control the animation speed of a sprite using create JS?
When you press right and left, the sprite will run through the frames... I'd like to leave the fps at 60, but alter how fast the frames are looped through without altering the main game FPS rate.
See a demo here. Press right and left arrow to see.
I thought changing the bmp animation frequency property would do the trick...
bmpAnimation.frequency = 2;
But it did not work...
Or should I be using the jQuery animation?
Also, I noticed that each time I hit a random key, the animation plays 1 frame then goes back to first frame. Why is that?
Thanks!
1) The frequency is a property of the spriteSheet-animation, not the bitmapAnimation itself.
So you would have to set the freuqency in the SpriteSheetData itself(http://www.createjs.com/Docs/EaselJS/classes/SpriteSheet.html) or if you want to set it during runtime you could use:
bmpAnimation.spriteSheet.getAnimation("walk_right").frequency = 2;
Please also note that the frequency will be deprecated in the next version of EaselJS in favor of speed (bit this is in the NEXT version, so just something for you to keep in mind)
2) You are currently calling the gotoAndPlay() every frame (if walking), that means that every frame your animation will be set to the first frame of that animation, you could easily avoid this by using something like:
if ( dir == "right" and bmpAnimation.currentAnimation != "walk_right" ) {
bmpAnimation.gotoAndPlay("walk_right");
}
But a better way would be to only call that method ONCE when you start walking and then again when you stop walking.

Subtle font size animation over short distances with long durations in jQuery

I want to animate some text in a slow and subtle way. jQuery animations work with integer values, so if you want to animate a size over say 10px in two seconds, you see a series of small steps at five FPS which looks jerky.
Here's a jsFiddle that shows what I'm talking about.
I found a similar question about animating positions, but the top/left/etc properties are integral, and so the accepted answer says it's not possible. However font-size can be animated as a real number, if jQuery will spit real numbers out.
I will also want to chain together a series of such animations.
Any ideas?
I had another look a the minimum point value which is visually recognisable. The smallest unit for pt I noticed change in was 0.2pt.
However, I noticed that when applying the change in steps of 0.2 points over a period of 1 millisecond per increment in a while loop that it still looked a little "laggy". May not if not running in jsfiddle though.
The point is that if you want to change the font-size smoothly by 10 points you must apply the change in steps of 0.2pt or 0.25pt or 0.5pt (what ever you find smoothest) at a time and you then must use an interval of 1 to stay smooth but you should not apply a different interval as otherwise the incremental steps are to small to notice and the whole animation ends up choppy again.
I think trying to force this 10pt change over 2 seconds will always look choppy no matter what framework you use, due to the lack of visual change on the font-size in the lower decimals.
This worked for me quite well:
(I'm not taking decreasing font-size animation into account in this example but that can be added off course)
function smoothAnimation($selector, startPoints, points){
var increments = 0.2;
var currentPoints = startPoints;
var endPoints = currentPoints + points;
while(currentPoints < endPoints){
currentPoints += increments;
$selector.animate({"font-size": currentPoints.toString() + "pt"}, 1, "swing");
}
}
$('#msg').click(function() {
$msg = $('#msg');
$msg.animate({"font-size": "80pt"}, 400, "swing");
smoothAnimation($msg, 80, 10);
$msg.animate({"font-size": "40pt"}, 400, "swing");
});
DEMO - smooth(ish) font-size animation
To make it look smoother increase the increments value to 0.25 or even 0.5. Ones you have nice smooth step you can set the points to any other value and the animation stays smooth as long as you don't force a 2 second animation interval.
Another option would be direct manipulations css transformations - here's an example (I only included webkit css to make it readable, but similar functions exist in all modern browsers). The "ease-out" property includes the fast-then-slow functionality you were aiming for. It's certainly smoother than what you've been able to get so far, but it's quite blurry - not sure if it's a trade-off you'd want to make. And as it's an experimental property, you'd still probably want your existing jQuery animation as a fallback for older browsers.
jQuery animations are terrible. Look into another tweening solution that utilizes requestAnimationFrame technique or a better timing mechanism. Maybe try a tween lib like tween.js look at the Rome demo, nice slow moving clouds...
Right now, only firefox has support for sub-pixel rendering of fonts, so animations in other browsers will always snap to pixel.

Categories