Animating to a variable in JQuery - javascript

I'm animating several elements at once and the final properties of some elements depend on the properties of the other elements. For example, I something like $('#a').animate({height:$('#b').height()}), but $('#b').height() changes during the animation. Is there a way to make the animation finish at the final $('#b').height()?

I assume you want to animate the height of #a to match the final height of #b, i.e., the height the element has after the animation.
You can achieve this by updating the end value of the fx object in the step function. Example:
var $a = $('#a').animate({height: 50}, 2000);
$('#b').animate({height: $a.height()}, {
duration: 2000,
step: function(now, fx) {
if (fx.prop === 'height') {
fx.end = $a.height();
}
}
});
DEMO (note: I got the element names the other way round)
This of course only works if the second animation is at least as long as the animation it depends on.
More info in the documentation.

Related

Run function just before jQuery animation ends

I have a scroller that animates scrolling using prev/next buttons. The duration of the animation is calculated based on the distance moved, so the duration is variable.
$c.animate({ scrollLeft: scrollLeft },
duration, 'easeInOutExpo', function () {
if (showPrev === 0) $s.attr("data-prev", showPrev);
if (showNext === 0) $s.attr("data-next", showNext);
});
After the animation is done, I want to refresh the user interface (the buttons), which you can see is done by updating two data attributes.
To date, I've tried two different options:
1. Update the data attributes before the animation
I use a CSS transition delay to make updates happen later but cannot fully co-ordinate it with the variable duration of the animation - sometimes it can be way out.
2. Update the data attributes after the animation
I attach the update function directly after the animation, which works, but there is an obvious delay after the animation is finished before the updates kick in.
Neither is perfect.
Ideally what I would like to do is kick off the function just before the scroll animation is finished - so if the scroll duration is 1s I would like to update the attributes at duration - 0.2s (0.8s).
This seems entirely possible given that I have full control of the duration.
What I don't know is how to implement this using jQuery - possibly kick off two tasks in parallel?
I'm not a jQuery expert by any stretch of the imagination so any help would be appreciated.
Please try with this code
$c.animate({ scrollLeft: scrollLeft },
duration, 'easeInOutExpo', function () {
if (showPrev === 0) $s.attr("data-prev", showPrev);
if (showNext === 0) $s.attr("data-next", showNext);
time = setTimeout(function () {
//keep your code here
}, duration-0.2s);
});
duration-0.2s => make it correct, i just mentioned it as an example.

Velocity JS Lag

I have been using parallax for some time and I have been using CSS animations , transforms and etc in order to get the results that I want. But after reading some stuff about Velocity , thought giving it a try.
The problem is the animations are having some kind of delay. Probably because I'm not applying velocity correctly, but I have researched and it seems that I'm doing is correct.
$ability.velocity({
translateX: '-50px',
opacity: '0'
});
$(document).on('scroll', function(){
var wScroll = $(this).scrollTop();
if(wScroll > $('.ability-self').offset().top - $(window).height()/1.2){
$ability.velocity({
translateX: "0",
opacity: '1'
});
} else{
$ability.velocity({
translateX: '-70px',
opacity: 0
});
}
The problem with that is that the animation only happens 1 or 2 seconds after I scroll after the element. I have checked if any CSS attribute might be interfering, but I didn't find a relevant one.
Is my JS bad?
Assuming your use of Velocity is correct, your code is causing a lot of stress for the browser.
What you should do is first cache the layout values that don't change:
var window_h = $(window).height()/1.2
and:
var ability_top = $('.ability-self').offset().top
And second, debounce the scroll event handler, since scroll is triggered a lot and you only need to respond once every frame, or possibly even less. For debouncing you could use lodash's or Underscore's _.debounce() or just copy paste the implementation, so your code would look like:
$(document).on('scroll', _.debounce(function(){
// code here...
}, 50))

animate two properties within same duration

I am building my own animation library; here is the jsfiddle link.
The problem is when I try to animate multiple properties the animation is finished as soon as the property with the last value is satisfied. For example:
I want to change an element's top and left properties to 500 and 300, respectively. The animation completes with both top and left as 300. This is incorrect.
My code structure resembles the following:
Main animate function:
function animate(ele,prop,duration,easing,callback) {
//...
}
Animation manager:
function Animation() {
this.start = function(ele,prop,duration,easing,callback) {
new animate(ele,prop,duration,easing,callback).start();
};
}
Please let me know how can solve this problem
http://jsfiddle.net/rrqe4qh1/1/
while applying the styles
this.ele.style[k]= val + 'px';
It was conflicting with style values of other properties as well
adding the below check helped
if(e===k) this.ele.style[k]= val + 'px';

Raphael js - animate opacity on group while retaining individual elements opacities

How can I animate the opacity on a bunch of Raphael objects as one object while maintaining the individual elements opacity states? I can't animate on sets without affecting each individual element, so how do I create one object to handle—I'm thinking in a jQuery mindset if that helps answer.
If you keep global variable, then you can do this. Look at the DEMO.
var p = new Raphael(10,10, 500, 500);
var x = 0.5;
var r = p.rect(20, 20, 100, 80, 5).attr({fill: 'red', opacity: x}),
c = p.circle(200, 200, 80).attr({fill: 'orange'}),
s = p.set(r, c);
s.click(function() {
s[0].attr({opacity: x - 0.3});
s[1].attr({opacity: 0.3});
});
A general solution that works for any number of elements, any number of changes and any number of sets is to use .customAttributes which calculate and store the correct opacity level for each element in the set based on a value attached to that individual element and a value for the set.
For example (in the demo, click multiple times to see the opacity of the set of three circles change one way and the individual circle clicked on change the other way):
http://jsbin.com/oxeyih/9/edit
Using something like this, which essentially adds this feature to all existing and future sets and elements in this Raphael paper instance:
// apply this using .attr or .animate to sets or each in a set
// to set the opacity of the set as a whole, maintaining relative opacity
paper.customAttributes.setOpacity = function( setOpacity ){
// elemOpacity might not be set yet
if (typeof this.attr('elemOpacity') == 'undefined') {
this.attr('elemOpacity', this.attr('opacity'));
}
return {opacity: setOpacity * this.attr('elemOpacity')};
}
// apply this using .attr or .animate to indiviual elements
// to set that element's opacity, factoring in the opacity of the set
paper.customAttributes.elemOpacity = function( elemOpacity ){
// setOpacity might not be set yet; setting it could create infinite loop
var setOpacity = this.attr('setOpacity');
setOpacity = typeof setOpacity == 'undefined' ? 1 : setOpacity;
return {opacity: setOpacity * elemOpacity };
}
You may want to add some kind of validation if your code could go wrong if either of the custom attributes go below 0.0 or above 1.0.
Any time you set the opacity of an element, use animate({elemOpacity: xx}, time); (or .attr()) and it'll take the set opacity into account, and any time you want to set the opacity of a set, call animate({setOpacity: xx}, time); on a set, and it'll take each element's opacity into account.
In some cases with complex sets, rather than animating many elements which can be slow in many browsers, it's much better for performance, and simpler, to just plonk an overlay on top... This is a good idea if the elements in question can be safely sent .toBack() and you don't need to interact (click, hover) with them further.
Just add an overlay rectangle, set to match the inherited colour of the container element (here's a way to get inherited background colour dynamically), send it then the set .toBack(), and animate the opacity of that overlay.

How to follow jQuery animated div across screen?

I'm using jQuery.crSpline to animate a graphic along a curved path. I'm pretty happy with the result.
However, the full canvas size is intentionally pretty wide - definitely larger than most screens - so the graphic will run out of viewport space pretty quickly and animate off the screen.
Instead, I'd like browser viewport to follow or centre on the image so that it stays 'in shot'.
How would I go about this with jQuery? Is scrollTop an option?
I've created a jsFiddle demo, based on the crSpline demo source, but with a wide minX setting.
NB: I did first attempt this with YUI3 and Loktar offered a canvas based solution, however I'm not using YUI & canvas any longer.
Is this what you had in mind? http://jsfiddle.net/gNdwD/33/. It seems a little choppy but its a rough first attempt.
It doesn't seem like crSpline exposes any coordinates on the animated element so we have to periodically observe them and adjust the viewport accordingly:
setInterval(function() {
var mover = $('#mover'),
posX = mover.position().left,
posY = mover.position().top;
$(window)
.scrollLeft(posX - $(window).width() / 2)
.scrollTop(posY - $(window).height() / 2);
}, 10);
I suspect the choppiness happens because our setInterval is out of sync with the $.animate on the mover. You can fix that by running two animations: one on the mover and one on the scrollTop and scrollLeft of a wrapper div. You can simultaneously apply two $.animates like this.
There exists an option for step function in jQuery animate,which is run on every step of the animation.
See second version of function parameters here :
http://api.jquery.com/animate/
.animate( properties, options )
propertiesA map of CSS properties that the animation will move toward.
optionsA map of additional options to pass to the method. Supported keys:
duration: A string or number determining how long the animation will run.
easing: A string indicating which easing function to use for the transition.
complete: A function to call once the animation is complete.
step: A function to be called after each step of the animation.
queue: A Boolean indicating whether to place the animation in the effects queue. If false, the animation will begin immediately. As of jQuery 1.7, the queue option can also accept a string, in which case the animation is added to the queue represented by that string.
specialEasing: A map of one or more of the CSS properties defined by the properties argument and their corresponding easing functions (added 1.4).
See this fiddle based on your code, which calls step function to adjust viewport :
http://jsfiddle.net/gNdwD/35/
$('<div id="mover" />')
.appendTo($(document.body))
.animate({ crSpline: spline },{
duration: 20000,
step: function() { /* THE STEP FUNCTION TO ADJUST VIEWPORT */
var mover = $('#mover'),
posX = mover.position().left;
posY = mover.position().top;
$(window)
.scrollLeft(posX - $(window).width() / 2)
.scrollTop(posY - $(window).height() / 2);
} ,
complete:function () {
// Re-run the demo with a new spline after we're done
window.setTimeout(function() {
DEMO.run();
}, 5000);
}
});

Categories

Resources