how to execute multiple animations simultaneously in mootools? - javascript

I have two divs (say, divs with ids: div1 and div2) whose height I need to expand using Fx.Tween
And I want the animations to be simultaneous.
'#div1' 's style.height is to be changed from auto to 0.
'#div2' 's style.height is to be changed for current height to a new height calculated by a function called calculateHeight()
how do I do that?

Mootools animations aren't blocking (animations in JS very rarely are!) so simply executing the two tweens sequentially will have the desired affect (as close as a human can perceive)
function go()
{
$('div1').tween('height', 0);
$('div2').tween('height', calculateHeight());
}
function calculateHeight()
{
return 0; //or whatever
}

I think this has to do with the wait:false option.
I'm not a programmer and mootools is easy but not as much to be so good at it but I remember reading some docs where it says you can control wether the second animation works as soon as the first one ends or simultaneously.
Chain Method: wait
Injects pauses between chained events.
Syntax
myClass.wait(duration);
Arguments
1. duration - (integer) The duration (in milliseconds) to pause the chain stack; defaults to 500.
I think you should CHAIN the morphing and make it wait(0). But I'm not sure. Hope this helps.

Related

Item positioning on scroll gives a warning about asynchronous scrolling

I'm trying to position two images by changing their top margin based on the scroll position.
The margins have a max value as well.
Everything works just fine but I have a warning on the console, saying that this solution can cause a jittery scrolling effect in browsers with asynchronous scrolling.
My first question is, should I worry about this?
Also, this is literally my first few lines of javascript and I'm not sure if this solution is good enough, so any advice is appreciated.
It just looks so simple I feel like there is a catch.
I could do it by adding classes to the images and set the margins in CSS, but it would be a lot longer code I guess.
I'm trying to do this strictly with js and CSS grid, just to learn to solve problems with limited tools.
The images are in a div, which is in a grid cell.
window.addEventListener("scroll", function () {
myMargin = 0.011 * window.scrollY;
if (myMargin < 3.4) { //max margin is 3.4% for myImg1
myImg1.style.marginTop = animMargin + "%";
myImg2.style.marginTop = animMargin / 2.7 + "%"; //myImg2 moves on a different scale
} else {
myImg1.style.marginTop = "3.4%"; //when the max value reached the margin is fixed
myImg2.style.marginTop = "1.25%";
}
});
Scrolling handlers can be intensive and put performance strain on the page as they will fire far more times than your handler actually needs. This ends up causing choppy/lag when scrolling as the browser may need to repaint in response to your handler.
A common technique is to throttle or debouce the handler.
Throttle:
only invokes func at most once per every x milliseconds.
Debouce:
delays invoking func until after x milliseconds have elapsed since the last time the debounced function was invoked.
The warning you are getting is actually fine, but you may benefit from using a throttled callback and increase the wait time to the max that is suitable for your needs - so least times it is called in order for it to work for you.
Demo using lodash throttle
// only call the handler once every 200ms
const throttledScroll = _.throttle(() => {
console.info('throttled', window.scrollY);
}, 200);
window.addEventListener('scroll', throttledScroll);
html,
body {
height: 300vh;
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

jQuery callback for element size change?

Is there a way to use a callback function after the screen is done resizing an element?
For example:
element.css('height', 'auto', function() {
element.css('height', element.height() - 6);
});
In words: when the element is reset to it's default height. The DOM needs to re-evaluate the height of the element. That takes a bit of time, but that time varies from client to client. So I don't want to use a setTimeOut function and slow down the script much more then needed.
So how can I execute some JavaScript just after the element's height is reset?
PS: I already tried the jQuery animate function. But still that callback function doesn't seem to wait long enough for the element to actually obtain it's original height.
Even tough the comments weren't helpful at all. I found something that actually seems to work. It waits for the height change to process and instantly process the next rule afterwords.
element.css('height', 'auto').delay(1).css('height', element.height() - 6);

Is it okay to use .animate with 0 duration all the time? Is there a better alternative?

I've grown used to code my jquery animation by doing the following.
Set the initial state of the element (things like width, height, top, left, opacity, etc...) using either css or javascript. This initial state is the state at the end of the animation.
Use .animate with 0 duration to move the element to the state in which elements are at the beginning of the animation.
Use a regular .animate with the appropriate duration to do the animation in which at the end, the elements are back to state in step 1.
Here is an example.
/* css file */
.animatedObject
{
width:60%;
}
// javascript file
$('.animatedObject')
.animate({width: '-=20%'}, 0)
.animate({width: '+=20%'}, 1000);
There are several advantage using this code at least for me. First, it looks clear to me what I'm trying to animate. Second, if javascript is disabled, the object would be at the end state of the animation which is often where I want it to be for graceful degradation. Third, objects can change position slightly for adjustments using css and the animation would still look largely the same.
The reason I'm not using the .css is that it if I try to replace the animate with 0 duration with the .css method, I would get differing animation starting point. I don't think it support += or -=, or if it does, it behaves differently.
So, is this a good way to do this? What is the industry standard way?
Well you could still use .css():
var anObj = $('.animatedObject');
anObj.css("width", anObj.css("width") - (20 / anObj.css("width"))).animate({
width: '+=20%'
}, 1000);
I believe this would work faster.
Edit:
I did a little benchmark for you, using jsperf.com. Here are my results (using Google Chrome):
.animate({}, 0)
Code:
$('.animatedObject')
.animate({width: '-=20%'}, 0)
.animate({width: '+=20%'}, 1000);
End Results:
10,013 operations per second
±7.48%
fastest
.css();
Code:
var anObj = $('.animatedObject');
anObj.css("width", anObj.css("width") - (20 / anObj.css("width"))).animate({
width: '+=20%'
}, 1000);
End Results:
2,477 operations per second
±6.39%
75% slower
Conclusion
Keep the animation function. It turns out using .css() is actually slower. I guess it's the fact that you have 2 extra functions. It's not worth it. This was actually a surprise to me as I thought .css() would function faster than it did. Test this yourself in your browser!

jquery - how to queue up a series of css property changes

I want to set a series of animation properties - a list of names that are currently invisible but will be marked visible, one right after another, with a set delay of about 100ms between each other. How do I accomplish this with jquery? Essentially, it would be something like this (pseudo-code):
for each $(.item) {
$(this).delay(index*100ms).css({'visibility': 'visible'}
}
The only thing that might compound this, while most of the elements would have the same class, not all of them would, so an animation queue of some sort would work best.
You can use .delay() to do this.
$('#foo').slideUp(300).delay(800).fadeIn(400);
When this statement is executed, the element slides up for 300 milliseconds and then pauses for 800 milliseconds before fading in for 400 milliseconds.
You actually want to do one thing to multiple items, so this is how I'd do that:
$.each($(".a"), function(index, value) {
$(this).delay(index*400).fadeOut(400);
});
You were on the right track with your pseudocode, you need to offset each animation by index * someTime.
Turns out, .delay() actually doesn't work with css() so here's an updated solution:
$.each($(".a"), function(index, value) {
$(this).delay(index*400).queue( function(next){
$(this).css('visibility','visible');
next();
});
});
demo

JavaScript/CSS: Delay between adding element to DOM and its CSS rules being applied?

I am using JavaScript to dynamically add an element to the DOM. I want to use CSS3 transitions to "fade in" the element as it is added.
I am using something like the following to achieve this:
function add(el) {
el.className += ' fader';
el.style.opacity = 0;
document.getElementById('parent-element').appendChild(el);
//setTimeout(function () { el.style.opacity = 1; }, 5);
el.style.opacity = 1;
}
And the CSS:
.fader {
-webkit-transition: opacity 0.5s;
}
This does not work as expected - the element does not fade in. If I replace the line el.style.opacity = 1; with setTimeout(function () { el.style.opacity = 1; }, 5);, as seen commented-out above, it does work as expected.
I am guessing that the first case does not work as there is some delay between adding the element and the appropriate CSS rules being applied to it. The 5ms delay created by the setTimeout in the second case gives enough time for these rules to be applied, therefore the fade takes place as expected.
Firstly, is this a correct assumption? Secondly, is there a better way to solve this? The setTimout feels like a hack. Is there perhaps some event that is fired once the element has had all its styles applied?
For a CSS3 transition to work, the object has to exist in a particular state and then you have to make a change to the object that triggers the transition.
For a variety of reasons, all of my experience with CSS3 transitions has shown me that a state that counts for this is only a state that it exists in when your javascript returns and the browser goes back to its event loop. It's as if, the only way you can tell the browser to loop at your object now and remember it's state for future transitions is to go back to the browser event loop. There are some programming reasons why this may be the case (so it's not trying to execute transitions as you're programmatically building your object and changing it), but those issues could have been solved a different way (like with a specific method call to codify the object now), but it wasn't done that way.
As such, your solution is the way I've found to do it. Create the object in it's initial state. Set a timer for a very short duration. Return from all your javascript so the object will get codified in its initial state and so the timer can fire. In the timer event, add a class to the object that triggers the CSS3 transition.
I don't honestly know if CSS3 transitions are specified this way in the specification, but my experience in Safari, Firefox and Chrome has been that this is how they work.

Categories