JavaScript Animation: Handling Complex Animations That Use Callbacks & Loop - javascript

I'm using Snap.svg to animate 13 SVGs. All the SVGs start from one point and animate through several other animations (through callbacks). An simplified example of my animation is described, in code, below:
var reset = function(person) {
person.attr({transform: 't0,0', opacity: 0});
animatePerson(person);
};
var animatePerson = function(person) {
person.animate({opacity: 1}, 300, null,function() {
person.animate({transform: 't100,20'}, 1000, null, function() {
person.animate({opacity: 0}, 300, null, function() {
reset(person);
});
});
});
};
var people = [Snap('#Person_1'), Snap('#Person_2'), Snap('#Person_3'), Snap('#Person_4'), Snap('#Person_5')];
My first attempt was to map over the array and set a timeout for the first animation like so:
people.map(function(person, index) {
setTimeout(function() {
animatePerson(person);
}, (300*index));
});
However this did not work as the SVGs would start to overlap/overtake each other when they looped. Then I tried to set the timeout equal to the length of time it took for one complete "lap" of the animation and divide that by the total amount of SVGs like so:
people.map(function(person, index) {
setTimeout(function() {
animatePerson(person);
}, (1600/people.length));
});
Is there a way in Snap.svg or JavaScript to have the animation loop using callbacks and/or timeouts, or an I way off here?
Here is an image of the full animation I am referring to:

One way I have done this, is to write a small function that takes in an element and an array of preset animations, and go through them in turn via the callback, which looks like this...
Edit: Modified slightly to be able to include a different element per animation, and example2 link below, includes the option to include a function to call each time as well.
function nextFrame ( frameArray, whichFrame ) {
if( whichFrame >= frameArray.length ) { return }
frameArray[ whichFrame ].el.animate(
frameArray[ whichFrame ].animation,
frameArray[ whichFrame ].dur,
frameArray[ whichFrame ].easing,
nextFrame.bind(null, frameArray, whichFrame + 1 )
);
}
Then you could pass it an array of anims, like this...
var myFrames = [
{ el: g, animation: { transform: 'r360,150,150' }, dur: 1000, easing: mina.bounce },
{ el: r, animation: { transform: 't100,-100s2,3' }, dur: 1000, easing: mina.bounce },
{ el: r, animation: { transform: 't100,100' }, dur: 1000, easing: mina.bounce },
{ el: g, animation: { transform: 's2,1' }, dur: 1000, easing: mina.bounce },
{ el: r, animation: { transform: 's1,2' }, dur: 1000, easing: mina.bounce },
{ el: c, animation: { transform: 's1,1' }, dur: 1000, easing: mina.bounce }];
Then you can call it with
nextFrame( el, myFrames, 0 );
example (click run on there)
example 2 (this allows you to include a func to call as well as part of it)

Related

Why does my GSAP slider animations stop working after I tried to animate my Nav bar

//Animation on slider
const tl = gsap.timeline({ defaults: { ease: "power1.out" } })
tl.to(".text", { y: "0%", duration: 1 });
tl.to(".slider", { y: "-100%", duration: 1.5, delay: 0.5 });
tl.to(".intro", { y: "-100%", duration: 1 }, "-=1");
tl.fromTo("nav", { opacity: 0 }, { opacity: 1, duration: 0.5 });
tl.fromTo(".shortDescription", { opacity: 0 }, { opacity: 1, duration: 0.5 });
tl.fromTo("footer", { opacity: 0 }, { opacity: 1, duration: 0.5 });
/*Animation on the Nav Bar
const sections = document.querySelectorAll('.selection');
const bubble = document.querySelector('.bubble');
const gradient = ["linear-gradient(to top, #30cfd0 0%, #330867 100%)"
"linear-gradient(to top, #a8edea 0%, #fed6e3 100%)"
];
const options = {
threshold: 0.7
};
let observer = new IntersectionObserver(navCheck, options);
function navCheck(entries) {
entries.forEach(entry => {
console.log(entry);
});
};
section.forEach(section => {
observe.observe(section);
});*/
This is the whole javascript code that I have, I currently put the nav bar animation to a comment for the gsap slider to work. but when I'm already trying to input the nav bar animation the gsap code stops working so the whole set would be stuck with the color black and it won't slide through, so you won't see the page itself.

Animation complete not called JavaScript DOM

I am trying to animate an image with a completion function. The animation works fine but the complete property is not called. I tried looking around and didn't find any result on the matter that says that what i'm doing is wrong. I tried on Chrome and Firefox I am using the code below
document.getElementById("myImageId").animate([{
transform: 'translateY(0px)'
},
{
transform: 'translateY(-300px)'
}
], {
duration: 300,
complete: function () {
alert('end ani')
}
});
Element.animate() returns a Animation object, and you can attach an event handler for finish to the object:
var animation = document.querySelector('#myImageId').animate([{
transform: 'translateY(0px)'
},
{
transform: 'translateY(-300px)'
}
], {
duration: 300,
delay: 300,
fill: 'forwards',
});
animation.addEventListener('finish', () => alert('end ani'));
<div id="myImageId"><img src="https://picsum.photos/200"></div>
Another option, which is only supported by FireFox currently, is the Animation.finished promise:
var animation = document.querySelector('#myImageId').animate([{
transform: 'translateY(0px)'
},
{
transform: 'translateY(-300px)'
}
], {
duration: 300,
delay: 300,
fill: 'forwards',
});
animation.finished.then(() => alert('end ani'));
<div id="myImageId"><img src="https://picsum.photos/200"></div>

how to remove element in anime.js?

I'm a beginner in anime.js. I animate something and after the animations is complete i want to remove the element that i'm animating.
The animation is working perfect. I just can't remove the element that im working and i dont want to hide it
logoTimeline
.add({
targets: text1,
duration: 700,
delay: function(el, index) { return index*50; },
opacity: 1,
easing: 'easeOutCirc',
translateX: function(el, index) {
return [(-50+index*10),0]
},
offset:0
})
.add({
remove:text1
})
Per the API Documentation you need to add a complete callback function which will fire once the animation has completed:
logoTimeline
.add({
targets: text1,
duration: 700,
delay: function(el, index) { return index*50; },
opacity: 1,
easing: 'easeOutCirc',
translateX: function(el, index) {
return [(-50+index*10),0]
},
offset:0,
complete: function(anim) {
logoTimeline.remove();
}
});

Combine the use of velocity.js' slideUp and begin: function

How do you combine these two, so that one can slide an item up, but trigger some JS just as that animation starts.
SlideUp code
.velocity("slideUp", { delay: 500, duration: 1500 });
Begin: code
$element.velocity({
opacity: 0
}, {
/* Log all the animated divs. */
begin: function(elements) { console.log(elements); }
});
Doing something like this doesn't work.
.velocity("slideUp", { delay: 500, duration: 1500 }), {
/* Log all the animated divs. */
begin: function(elements) { console.log(elements); }
});
You have to put thebegin property inside the options object:
.velocity("slideUp", {
delay: 500, duration: 150,
begin: function(elements) { console.log(elements); }
});

Web animations API callback function

I've just discovered the Web Animations API, and I'm trying to figure out how to introduce a callback function for these animations..I've tried using the following
$('.box_wrapper')[0].animate([
{ right: '-100%' },
{ right: 0 }
], {
fill: 'forwards',
duration: 1000,
onfinish: function() {
// do stuff
}
});
Looking at the w3c spec on this section I thought that the onfinish property is what I'd need to use, but nothing happens.
I've also tried using the jQuery callback syntax;
$('.box_wrapper')[0].animate([
{ right: '-100%' },
{ right: 0 },
], {
fill: 'forwards',
duration: 1000
}, function() {
// do stuff
});
But of course this doesn't work either. Any Ideas, I'm sure it's something simple, I've just not been able to find the info yet.
I nearly had it right, with a small tweak like so, the callback works;
$('.box_wrapper')[0].animate([
{ right: '-100%' },
{ right: 0 }
], {
fill: 'forwards',
duration: 1000
}).onfinish = function() {
// do stuff
};

Categories