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();
}
});
Related
I'm attempting to create an animation (using anime.js) that plays an animation timeline once when the users starts typing and will loop for the duration that the user is typing in the input box. When the user stops typing the animation will complete its current loop and stop playing.
Here's my progress at the moment, you can observe the animation working incorrectly: https://codepen.io/andrewbentley/full/XqMrze
Here's what my anime.js code timeline:
var basicTimeline = anime.timeline({
loop: true,
autoplay: false,
duration: 700
});
basicTimeline
.add({
targets: '#circ1',
duration: 100,
translateY: -10,
easing: 'easeInQuad'
})
.add({
targets: '#circ1',
duration: 100,
translateY: 0,
easing: 'easeInQuad'
})
.add({
targets: '#circ2',
duration: 100,
translateY: -10,
easing: 'easeInQuad'
})
.add({
targets: '#circ2',
duration: 100,
translateY: 0,
easing: 'easeInQuad'
})
.add({
targets: '#circ3',
duration: 100,
translateY: -10,
easing: 'easeInQuad'
})
.add({
targets: '#circ3',
duration: 100,
translateY: 0,
easing: 'easeInQuad'
})
.add({
targets: '#circ3',
delay: 100
});
document.querySelector('#email').onkeypress = basicTimeline.play;
document.querySelector('#email').onkeyup = basicTimeline.pause;
Is anyone able to advise me as to the best way of achieving the desired effect whilst using anime.js timeline utility and the use of event listeners such as onkeypress, onkeyup etc.
I think you need a timer which pauses your animation after some time of inactivity.
https://codepen.io/anon/pen/qYoPKQ
var timer = false;
document.querySelector('#email').onkeypress = function () {
if(basicTimeline.paused) basicTimeline.play();
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
basicTimeline.pause();
basicTimeline.reset();
}, 500);
};
The issue of stopping an animation at the end of the current loop has been raised here:
on github There are some good suggestions there.
Perhaps the best one is from Edrees Jalili
function pausableLoopAnime({loopComplete, ...options}) {
const instance = anime({
...options,
loop: true,
loopComplete: function(anim) {
if(instance.shouldPause) anim.pause();
if(typeof loopComplete === 'function') loopComplete(anim);
}
});
instance.pauseOnLoopComplete = () => instance.shouldPause = true;
return instance;
}
const animation= pausableLoopAnime({
targets: '.polymorph',
points: [
{ value: '215, 110 0, 110 0, 0 47.7, 0 67, 76' },
{ value: '215, 110 0, 110 0, 0 0, 0 67, 76' }
],
easing: 'easeOutQuad',
duration: 1200,
});
setTimeout(animation.pauseOnLoopComplete, 100)
I have created animations that trigger when elements enter in viewport. Problem is that I have to repeat same code for every element. I'm using anime.js and scrollMonitor.js for animations, and it's kinda hard to make working for-loop.
Here is my code:
$(window).on("load", function() {
'use strict';
var elementWatcher1 = scrollMonitor.create('#about', -200);
elementWatcher1.enterViewport(function() {
var startAnimation = anime.timeline();
startAnimation
.add({
targets: '#about .toAnimate',
translateY: [50, 0],
opacity: 1,
duration: 600,
delay: function(el, index) {
return index * 80;
},
easing: 'easeOutQuad'
});
this.destroy();
});
var elementWatcher2 = scrollMonitor.create('#portfolio', -200);
elementWatcher2.enterViewport(function() {
var startAnimation = anime.timeline();
startAnimation
.add({
targets: '#portfolio .toAnimate',
translateY: [50, 0],
opacity: 1,
duration: 600,
delay: function(el, index) {
return index * 80;
},
easing: 'easeOutQuad'
});
this.destroy();
});
var elementWatcher3 = scrollMonitor.create('#gallery', -200);
elementWatcher3.enterViewport(function() {
var startAnimation = anime.timeline();
startAnimation
.add({
targets: '#gallery .toAnimate',
translateY: [50, 0],
opacity: 1,
duration: 600,
delay: function(el, index) {
return index * 80;
},
easing: 'easeOutQuad'
})
.add({
targets: '#gallery .toAnimateToo',
opacity: 1,
duration: 600,
delay: function(el, index) {
return index * 80;
},
easing: 'easeOutQuad',
offset: 0
});
this.destroy();
});
});
Does anyone have idea how can I put this in for-loop?
In ES5 just use a forEach loop on an array of those selectors:
$(window).on("load", function() {
'use strict';
["#about", "#portfolio", "#gallery"].forEach(function(selector) {
var elementWatcher = scrollMonitor.create(selector, -200);
elementWatcher.enterViewport(function() {
var startAnimation = anime.timeline();
startAnimation
.add({
targets: selector + ' .toAnimate',
translateY: [50, 0],
opacity: 1,
duration: 600,
delay: function(el, index) {
return index * 80;
},
easing: 'easeOutQuad'
});
this.destroy();
});
});
});
In ES2015+, you could use for-of instead (with const for elementWatcher) instead.
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)
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); }
});
I have two jquery animations one by other:
books.animate({ left: left1 }, {
duration: this.slideDuration,
easing: this.easing,
complete: complete
});
laptops.animate({ left: left2 }, {
duration: this.slideDuration,
easing: this.easing,
complete: complete
});
I want the animations to run simultanusly so I use {queue: false}:
books.animate({ left: left1 }, {
duration: this.slideDuration,
easing: this.easing,
queue: false,
complete: complete
});
laptops.animate({ left: left2 }, {
duration: this.slideDuration,
easing: this.easing,
queue: false,
complete: complete
});
But now the completed callback called twice! How can I know exactly when does the both animations are done?
Using jQuery deferred methods try
$.when(
books.animate({ left: left1 }, {
duration: this.slideDuration,
easing: this.easing
}),
laptops.animate({ left: left2 }, {
duration: this.slideDuration,
easing: this.easing
})
).done( function( ) {
alert("done!");
});
Fiddle here
Why not remove the complete handler from one of the animations?
From the extract of code that you've posted, it looks as though you're using the same duration and easing methods on both animations. Therefore it's inherently true that they will complete at the same time, so long as they're being called at the same time...
this may sounds like something complicated, but why not Deferred Objects ?
http://api.jquery.com/category/deferred-object/
you may investigate more here
jQuery animation with deferred pipes?
According to http://darcyclarke.me/development/using-jquery-deferreds-with-animations/:
books.animate({ left: left1 }, {
duration: this.slideDuration,
easing: this.easing,
queue: false
});
laptops.animate({ left: left2 }, {
duration: this.slideDuration,
easing: this.easing,
queue: false
});
$.when(books, laptops).done(complete);