javascript run function after animation frame renders - javascript

Based on what I understand you need 60fps on your animations to make the animations appear smooth. Basically what I'm trying to do is to do the heavy calculations at the start of the frame so by the time the rendering is actually going to happen there won't be much work left to do.
I understand you can use window.requestAnimationFrame to run a function right before the screen is redrawn. But that will cause a jerking effect if the function takes a long time. Is there a way to run a function right after the screen has done a repaint?
I tried something like this but its miss and hit:
window.requestAnimationFrame(do_before);
do_before(){
window.setTimeout(do_after, 1);
}
do_after(){
//code to execute after animation frame
}
As you can see in the picture below the do_after code is still executing in the same frame and because of this I sometimes get long frames:
Link to image
Is there a way to make do_after() run after the screen has finished drawing itself?
Thanks in advance

Actually, the code from you question is right. setTimeout(do_after) is enough in Chrome and Safari (I haven't tested in other browsers). It makes the browser execute the function when the browser is free of other tasks.
If you want to delay the execution from inside a requestAnimationFrame callback, just call setTimeout(do_after) and the callback will be executed right after the frame flush:
requestAnimationFrame(() => {
do_before();
setTimeout(do_after);
});
If you want to delay the execution from another place (e.g. a click handler or an AJAX response handler), call requestAnimationFrame first and then setTimeout:
document.addEventListener('click', () => {
do_before();
requestAnimationFrame(() => {
setTimeout(do_after);
});
});
Unfortunately I haven't found a universal way to execute a callback right at the start of the next frame because there is no straightforward way to know if a code is executed inside a requestAnimationFrame handler. You may use a trick to solve it
If you need to execute a callback right after any frame flush, use the second approach (requestAnimationFrame + setTimeout). It may lead to idling a whole animation frame before running the callback.

There is no API function to do what you want, but you can do the following:
window.requestAnimationFrame(function()
{
do_before();
window.requestAnimationFrame(do_after);
});
This makes sure your do_after is called after the first animation frame, and will trigger a second one after it's done executing.

Related

How to handle the delay that occurs between an append() function?

I am appending an array to a div using jquery, I want to show a small loading indicator while this happens, so I threw a call back function onto my append logic. This works, however, my loader will fire off it's .hide() before my array is painted into the div.
Is there a way I can only run the .hide() after the array has finished painting?
var contentpush = [];
// create x-amount of divs (x being 'tabs')
for (var i = 0; i < tabs; i++){
contentpush.push('<li class="tab" role="tab"><span class="icon"><span class="'+contentformat[i].icon+'" ></span></span><span class="title">'+contentformat[i].title+'</span></li>');
}
$('.tablist').append(contentpush.join('')).ready(function(){$('#skeleton').hide(); });;
Here is a gif of what is going on as well:
As you can see, the skeletal frame loader will disappear long before my array is actually painted into the div. Any thoughts on this are greatly appreciated!
Have you tried setting a timeout for some milliseconds?
Unfortunately, the jQuery .append() function does not include a callback. There is no way to really check for completion of it, as it supposedly happens immediately. synchronously in the order they come, unless you explicitly tell them to be asynchronous by using a timeout or interval. see this
This means that your .append method will be executed and nothing else will execute until that method have finished its job. try following
// set a time interval for the event to complete.
$(contentpush).hide().appendTo(".tablist").fadeIn(1000);
// a small tweak to set a call back function.
$(".tablist").append(contentpush).append(function() { $('#skeleton').hide(); });

How to make my javascript function wait for a html element to render

There is a single Page Application in AngularJS.
It has nested tabs. In the inner tab there is a button on which some event gets fired.I need to trigger the click event of this button present on the inner tab Button gets rendered after both the tabs are rendered. What is the best way to wait until the tabs render themselves and the button is available.
I tried using 'while loop'(i.e keep looping until id for button is undefined) and $timeout(set timeout to 2-3 seconds) service but both have their consequences when there is delay in tab render.
Please suggest if there exists a better approach.
Even though this question is really old, I've found a solution that works for me and I think it might be helpful for some people.
Calling element.getBoundingClientRect() before executing further code worked for me. According to docs this method returns information about the position relative to the viewport (docs):
The Element.getBoundingClientRect() method returns a DOMRect object providing information about the size of an element and its position relative to the viewport.
Assuming that the screen has to render to find information about the position of an element, this function would technically wait for the html element to render or even make the html element render.
Remember, this is only an assumation and I can't guarantee that it works.
Things have changed quite a bit since this question was asked, so there's now a much nicer solution.
requestAnimationFrame(() => {
// this will be called just before the next video frame.
// That will be after any changes to the DOM have been completed.
});
The docs are here...
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
You can do it with jQuery:
$(document).ready(callbackFn);
or native JS:
document.addEventListener('readystatechange', function onReadyStateChange() {
if (document.readyState !== "complete")
return;
callbackFn();
}, false);

HTML Fade music on link

I would like, when navigating away from the page, to execute a fade of a musical cue instead of cutting if off abruptly. It is okay with me if the fade adds a half second to the time needed to execute the link.
I have the following code that will execute a fadeout of a playing music cue.
<audio id="myAudio"
<source src="./audio/pluto.mp3" type="audio/mp3">
Your browser does not support the audio element.
</audio>
and
<script>
function fadeAudio()
{
if (myAudio.volume > 0)
{
myAudio.volume = Math.max(0, myAudio.volume - 0.05);
setTimeout(fadeAudio, 20);
}
}
</script>
I tested this code with a button, and it works fine (sometimes there is a bit of zippering, but I prefer it to an abrupt cutoff).
<button onclick="fadeAudio()">Try it</button>
My problem is that I don't know how to call and execute this fade before navigating away. I was looking at html's onbeforeunload, but that seems to be geared entirely to printing a warning prompt, with no way to insert my intervening fadeAudio() function.
Simply doing the following accomplished nothing:
<body onbeforeunload="fadeAudio()">
And this didn't work with onunload either.
I am thinking another approach would be to rewrite the links on the page to run the fadeAudio() function first. (It's more important to me that transitions between my pages sound nice than if the user decides to close or go elsewhere.) Perhaps this can be done via making a button and calling the fadeAudio and a linking function in sequence. But it seems there might also be a neater way. Any suggestions?
Here is what I found that kind of works:
(1) in the link, one can call a function
(2) in the function, I first call the fadeAudio() function, then I call a setTimeout() function with 1000 ms time allotted to allow the fadeAudio() to complete
(3) then the setTimeout calls a window.open() method of the target link.
I'm going to be tweaking the various timings to see how far I can tighten this without adding too much zippering. It will definitely make things a little sluggish going from location to location on my site though.
Wouldn't it be nice if there was a way for the sound to just fade out in its own thread while the new page appears. If there is a way, I would love to know about it.
In the script tag:
function linkToHome()
{
fadeAudio();
setTimeout(openHome, 1000);
}
function openHome()
{
window.open('index.htm','_self');
}
The URL call in HTML:
Home
Will probably try to figure out a way to paramaterize the above to allow the method or tag to include the target URL.

jQuery: Run animation after all calculations and DOM updates are complete

I am trying to prevent an element from being animated until a specific function is complete. The problem is that the animation starts while the function still is running, so the animation is extremely laggy and jumpy instead of smooth and calm as it is when I disable the function.
My code looks something like this:
function editElement() {
// Do a lot of calculations and edit what is inside #box (no Ajax)
}
$("#click").click(function() {
editElement();
$("#element").slideDown("slow");
});
How can force the slideDown animation to wait until the function is complete before running?
I have tried callbacks and $.Deferred suggested in other questions, but most of them seem to be directed towards Ajax and do not work for me. Thank you for your time!
slideDown is always executed after editElement has finished executing its code because JavaScript is a "linear language". The only exception is when there are asynchronous functions inside, including AJAX and setTimeout / setInterval.
One suggestion though is that you can do this:
function ediElement(..., callback){
//codes here....
//Make sure there is no asynchronous functions.
callback();
}
$("#click").click(function() {
editElement(function(){
$("#element").slideDown("slow");
});
});

Stop lag on calling scroll function with webkit filter javascript

I have this function being called everytime the page is scrolled by a user:
window.onscroll=function(){
document.getElementById("navBlurContent").style.top=-window.pageYOffset+125+"px";
}
However, this causes lots of lag to the browser. I have noticed some answers with jQuery that calls a delay to when the function is called. But, I want to use strictly javascript. I was wondering how this could this be done.
I have now realized that the majority of the lag is being caused by a -webkit-filter I have on the element. But I am not sure how to stop it.
Thanks
Try not to do a DOM select on every scroll.
Cache it:
var blur_content = document.getElementById("navBlurContent");
window.onscroll=function(){
blur_content.style.top=-window.pageYOffset+125+"px";
};

Categories