Animating a div disappearance, how to smooth that? - javascript

I've been trying to animate a Dashboard Widget's div disappearance, but it just brutally goes "poof" (as in, disappears as expected, only instantly).
function removeElement(elementId)
{
duration = 9000; // The length of the animation
interval = 13; // How often the animation should change
start = 1.0; // The starting value
finish = 0.0; // The finishing value
handler = function(animation, current, start, finish) {
// Called every interval; provides a current value between start and finish
document.getElementById(elementId).style.opacity = current;
};
new AppleAnimator(duration, interval, start, finish, handler).start();
interval = 1;
start= "visible";
finish = "hidden";
duration = 9001;
handler = function(animation, current, start, finish) {
document.getElementById(elementId).style.visibility="hidden";
};
new AppleAnimator(duration, interval, start, finish, handler).start();
}
I expected this to "disappear" the div a millisecond after its opacity reaches zero, but for a not so obvious reason (to me), it just disappears immediately. If I comment out the second animation code, the div fades out (but it's still active, which I don't want).
All solutions I've yet seen rely on using JQuery and wait for the event at the end of the animation, is there another way to do that, other than JQuery?

If you are looking for a pure javascript solution it probably needs a good understanding of how javascript event work and basically about javascript language. As reference you should check this question on CodeReview
But as I think the best solution for you and not to rely on jQuery is to checkout CSS3 animations. Even if they are not supported by all browsers you could use Modernizer to fill polyfills for animations.
My favorite CSS3 Animation library is Animate.css. It's pretty neat and gives you a variety of demos in the page.
You'll first have to choose an animation and add it to your css stylesheets. Then have another custom class that contain everything about the animation.
.disappear{
-webkit-animation-duration: 3s;
-webkit-animation-delay: 2s;
-webkit-animation-iteration-count: infinite;
}
Then you could use javascript events to toggle in classes to your Elements. Below is how you add a class to an element.
var animationObject = document.getElementById("poof");
animationObject.className = animationObject.className + " disappear";
If you need more help regarding javascript of how this should be done check out this answer.
Hope this helps...

I found it: AppleAnimator possesses animator.oncomplete: A handler called when the timer is complete.
In my case:
var anim = new AppleAnimator(duration, interval, start, finish, handler);
anim.oncomplete= function(){
document.getElementById(elementId).style.visibility="hidden";
};
anim.start();
The Apple documentation actually calls "Callback" the animation code itself, and "handler" the callback, which makes it a bit hard to realize at first.
Thanks frenchie though, the "YourCallbackFunction" made me realize I was missing something related to callbacks :D

Related

Problem synchronizing DOM manipulation with style changes in carousel

I built a basic picture carousel a while back, and I'm finally getting around to transferring it from MooTools over to jQuery so I can drop MooTools. I've got the script completely functional, but for whatever reason when the carousel slides in one direction, you can see a "pop" where it resets itself.
I've tried playing around with the order it handles everything, but no matter what it seems to always desync for just a fraction of a section.
Here's a copy of my code: https://jsfiddle.net/Chaosxmk/pf6dzchm/
The offending section of code is this:
styles['position'] = 'absolute';
styles[self.params.axis] = -32768;
$(self.list[0]).css(styles).hide();
$(self.list[0]).appendTo(self.carousel);
$(self.list[conf.mi]).css(self.params.axis, (100-conf.pr)+'%');
styles = {};
styles['position'] = 'relative';
styles[self.params.axis] = 'auto';
$(self.list[conf.mi]).css(styles);
Issue is that $.fadeOut() sets display:none on the element, which causes some strange rendering issues in your setTimeout() callback. Works better if you use $.fadeTo() instead:
if (self.params.direction) {
// Go forward
self.carousel.css(self.params.axis, '-'+conf.pr+'%');
$(self.list[0]).fadeTo(400, 0);
$(self.list[conf.mi]).css(self.params.axis, '100%').fadeTo(400, 1);
} else {
// Go backward
self.carousel.css(self.params.axis, conf.pr+'%');
$(self.list[conf.mi-1]).fadeTo(400, 0);
self.list.last().css(self.params.axis, '-'+conf.pr+'%').fadeTo(400, 1);
}
For simplicity I used a 400ms duration, but you can set this to whatever you need.
JSFiddle

JS — FLIP technique and requestAnimationFrame, refactor to not be nested

I'm having some trouble understanding the requestAnimationFrame API. I think it makes the browser wait for the callback to complete until the browser triggers a repaint (or reflow?). Is that correct? If you call requestAnimationFrame within the callback, the browser will repaint and execute the new RAF's callback and then repaint again? If this is the case, how can I make two sequential calls to this API be more async/promisified rather than nesting them like my example below?
Here I have used the FLIP technique to insert a document fragment into the DOM and animate the height of a DOM element, it seems to work fine. I do not like the callback nature/nesting of the code. I struggle to understand how I can make this more async. Is it possible use a promise and make it thenable?
window.requestAnimationFrame(() => {
this.appendChild(frag);
this.style.height = `${rows * rowHeight}px`;
const { top: after } = this.getBoundingClientRect();
this.style.setProps({
"transform" : `translateY(${before - after}px)`,
"transition" : "transform 0s"
});
window.requestAnimationFrame(() => {
this.style.setProps({
"transform" : "",
"transition" : "transform .5s ease-out"
});
});
});
So, are my preconceived notions about RAF correct? And how can the above code example be void of callbacks and not as nested?
I'm not sure to get your own explanation of requestAnimationFrame, but to put it simply, it is just a setTimeout(fn, the_time_until_painting_frame).
To put it a little bit less simply, it puts fn in a list of callbacks that will all get executed when the next painting event loop will occur. This painting event loop is a special event loop, where browsers will call their own painting operations (CSS animations, WebAnimations etc. They will mark one event loop every n-th time to be such a painting frame. This is generally in sync with screen refresh-rate.
So our rAF callbacks will get executed in this event loop, just before browser's execute its painting operations.
Now, what you stumbled upon is how browser do calculate CSS transitions: They take the current computed values of your element.
But these computed values are not updated synchronously. Browsers will generally wait this very painting frame in order to do the recalc, because to calculate one element, you need to recalculate all the CSSOM tree.
Fortunately for you, there are some DOM methods which will trigger such a reflow synchronously, because they do need updated box-values, for instance, Element.offsetTop getter.
So simply calling one of these methods after you did set the initial styles (including the transition one), you will be able to trigger your transition synchronously:
_this.style.height = "50px";
_this.style.setProperty("transform", "translateY(140px)");
_this.style.setProperty("transition", "transform 0s");
_this.offsetTop; // trigger reflow
_this.style.setProperty("transform", "");
_this.style.setProperty("transition", "transform .5s ease-out");
#_this {
background: red;
width: 50px;
}
<div id="_this"></div>

css animation fast forward and rewind

I was wondering if it was possible, using some javascript or jquery, to skip to the next, or go to the last part of a css animation. Lets say we have the following:
#keyframe effect{
0%{opacity:1;}
45%{opacity:1;}
50%{opacity:0;}
95%{opacity:0;}
100%{opacity:1;}
}
that will fade something out and then back in
so lets say I made some buttons. How would I do the following:
$('#next').click(function(){
//skip to the next animation part
});
$('#previous').click(function(){
//skip to the previous animation part
});
It's not really possible unless you break the CSS into different parts based on classes and then add/remove classes.
However, there is an absolutely fantastic javascript library called Greensock, that allows timeline-based animation - and in many cases is faster than CSS animations. It also has the benefit of being cross-browser compatible.
If you were, for example to create something similar using Greensock, it would look something like this:
var effect = new TimelineMax({paused:true});
effect.addLabel('start');
effect.to(
'#myItem',
1,
{css:{opacity:1}}
);
effect.addLabel('step1');
effect.to(
'#myItem',
1,
{css:{opacity:0}}
);
effect.addLabel('end');
effect.play();
$('#gotoEnd').on('click', function(e){
e.preventDefault();
effect.seek('end');
});
With the use of the animation-play-state Property, you can pause an animation and update the transform, then restart it.
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
However you can't pause the animation, transform it, resume it, and expect it to run fluidly from the new transformed state.
At this time, there is no way to get the exact current "percentage completed" of a CSS keyframe animation. The best method to approximate it is using a setInterval or requestAnimationFrame.
This CSS tricks article explains this further, and gives an example of using setInterval. Another option is to use request animation frame
As mentioned GreenSock or Velocity are animation libraries which allow for extremely fast and smooth animations

Are javascript and css timing synchronized?

Are javascript (timeout, interval) and css (animations, delay) timing synchronized ?
For instance :
#anim1 {
animation: anim1 10s linear;
display: none;
}
anim1.style.display = "block" ;
setTimeout(function() {
anim2.style.webkitAnimation= 'anim2 10s linear';
}, 10000);
Will anim2 be precisely triggered at the end of anim1 ? Is it different depending on the browser ? In this case I'm more interested in a webkit focus.
Note that anim1 is triggered via javascript to avoid loading time inconsistencies.
NB : This is a theoretical question, the above code is an illustration and you must not use it at home as there are way more proper means to do so.
As far as I know, there is no guarantee. However, there are events which you can listen for;
anim1.addEventListener('animationend',function(){
anim2.style.webkitAnimation= 'anim2 10s linear';
}
Note that because these are new, there are still vendor prefixes you need to account for; webkitAnimationEnd and oanimationend for Webkit and Opera.
Also as my original answer (wrongly) suggested, there is transitionend (with similar prefixes) if you want to use CSS transitions instead of animations.
This is the wrong way to do this. There isn't any guarantee that they will be in sync, though it's likely they'll be close.
Events are provided for the start, end an repeat of an animation.
https://developer.apple.com/documentation/webkitjs/webkitanimationevent details these.
Use code like:
element.addEventListener("webkitAnimationEnd", callfunction,false);
to bind to it.

Fx on JavaScript: How to fade stuff, etc without frameworks?

I would like to learn how to do fade, and similar effects on JavaScript. I often get answers, like why not use jQuery, Mootools, etc ? Well, I want to learn how stuff works, then I won't mind using any of these frameworks.
I'm currently learning about making changes on the DOM, so, I've read a lot of stuff on this theme. Also, I've read about Reflow, still, I didn't find any cool stuff on Repaint, but, I'll keep searching.
From seeing source files etc, I see a few methods, that I don't know if they've created or are Core methods of JS.
My question is, is there any resource where I can learn all this neat stuff like smooth position change, fading elements trough opacity or whatever, etc?
Take a look at emile.js. It's brand-spanking new. Great way to learn how to do your own.
Introduced at the recent jsconf conference. Written by Thomas Fuchs (script.aculo.us).
http://github.com/madrobby/emile
Émile Stand-alone CSS animation
JavaScript mini-framework
Doesn't need
a JavaScript framework
Full set of CSS
properties for animation (length-based
and colors)
Easing and callbacks
Less
than 50 lines of code
Get updates on
Twitter: http://twitter.com/emilejs
here's an example that works in firefox and chrome. ie doesn't respect the opacity style.
var ELEMENT;
var STEPS;
var INTERVAL;
var COUNT;
var TIMERID;
// 5 * 200ms = 1 second
STEPS = 5;
INTERVAL = 200;
function Button1_onclick() {
ELEMENT = document.getElementById("foo");
COUNT = STEPS - 1;
TIMERID = setInterval(Fade, INTERVAL);
}
function Fade() {
ELEMENT.style.opacity = String(COUNT / STEPS);
COUNT--;
if (COUNT < 0) {
clearInterval(TIMERID);
TIMERID = 0;
}
}
setInterval and clearInterval are standard js functions. they will execute the given function every x milliseconds. in our case we kill it when we've hit 0 opacity.
sliding a window is a similar process. you'd set the left/right/top/bottom style instead of opacity.
Fading using javascript is basically modifying opacity of an element programmatically. The "smoothness" is done by using timers. Same for position/size changes. You need to read up on css to understand what style properties of an element you have to control using javascript for the effect you want.
If you are really curious, you can dive into the source of yui in github: http://github.com/yui

Categories

Resources