How to scale back element from scaled up size? - javascript

I have the following function which increases the size of circles but instead of starting over after they were scaled, I want to scale back to original size. Backwards. So when it reached scale 2, it should go back incrementally to 1.
How can I accomplish this?
function animateCircles() {
var circles = document.getElementsByClassName('circle')
setTimeout(function () {
for(i=0;i<circles.length;i++) {
circles[i].animate([
// keyframes
{ transform: 'translateY(0px)' },
{ transform: 'scale(2)' }
], {
// timing options
duration: 2000,
iterations: Infinity
});
}
},0)
setTimeout(function () {
for(i=0;i<circles.length;i++) {
circles[i].animate([
// keyframes
{ transform: 'translateY(0px)' },
{ transform: 'scale(1.5)' }
], {
// timing options
duration: 2000,
iterations: Infinity
});
}
},2000)
}

Just add another keyframe within your first animation (and adjust time accordingly):
function animateCircles() {
var circles = document.getElementsByClassName('circle')
setTimeout(function() {
for (i = 0; i < circles.length; i++) {
circles[i].animate([
// keyframes
{
transform: 'translateY(0px)'
}, {
transform: 'scale(2)'
}, {
transform: 'scale(1)'
}
], {
// timing options
duration: 2000,
iterations: Infinity
});
}
}, 0)
}
animateCircles();
.circle {
background-color: #F00;
border-radius: 50%;
width: 75px;
height: 75px;
}
<div class="circle"></div>

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 can I make my NuxtJS transition layout specific and not global?

Okay so I have been trying to wrap my head around this for such as longtime now so I've turned to Stack Overflow for help! Essentially, I am using NuxtJS as the frontend framework for a website I'm building for a client. I have a transition property in my Nuxt.config.js file
Nuxt.config.js
transition: {
mode: 'out-in',
css: false,
beforeEnter: function(el) {
console.log('Pre Enter');
TweenMax.set(".transition--layer",{ transformOrigin: '100% 0%', yPercent: 0})
TweenMax.set(".transition-layer--text h2 span", {opacity:0.75, yPercent:0,force3D:true});
},
enter: function (el, done) {
console.log('Enter');
TweenMax.to(".transition-layer--text h2 span", 0.5, {opacity:0.75, yPercent:-100, delay:0.4, ease:Power3.easeInOut, force3D:true}, 0.2);
TweenMax.to(".transition--layer", .75, {delay:1, yPercent: -100, ease: Power3.easeInOut})
done()
},
beforeLeave: function (el) {
console.log('Before Leave');
TweenMax.set(".transition--layer",{ transformOrigin: '100% 0%', yPercent: 100})
},
leave: function (el, done) {
console.log(' Leave');
var done = done;
TweenMax.to(".transition--layer", .75, { yPercent: 0, ease: Power3.easeInOut})
TweenMax.fromTo(".transition-layer--text h2 span", 0.5, {opacity:0, yPercent:100, force3D:true}, {delay:0.75, ease:Power3.easeInOut, opacity:0.75, yPercent:0,force3D:true, onComplete: function () { console.log('leave'); done() }}, 0.2);
}
},
I am wanting to move this code inside one of my Layouts since, I need this transition to be layout specific rather than global. I've tried moving this inside one of my layouts by doing the below. However, this didn't work? Is this even possible? I found a git feature request on the Nuxt JS Github page however, the issue has been closed https://github.com/nuxt/nuxt.js/issues/1054
<script>
export default {
transition: {
mode: 'out-in',
css: false,
beforeEnter: function(el) {
console.log('Pre Enter');
TweenMax.set(".transition--layer",{ transformOrigin: '100% 0%', yPercent: 0})
TweenMax.set(".transition-layer--text h2 span", {opacity:0.75, yPercent:0,force3D:true});
},
enter: function (el, done) {
console.log('Enter');
TweenMax.to(".transition-layer--text h2 span", 0.5, {opacity:0.75, yPercent:-100, delay:0.4, ease:Power3.easeInOut, force3D:true}, 0.2);
TweenMax.to(".transition--layer", .75, {delay:1, yPercent: -100, ease: Power3.easeInOut})
done()
},
beforeLeave: function (el) {
console.log('Before Leave');
TweenMax.set(".transition--layer",{ transformOrigin: '100% 0%', yPercent: 100})
},
leave: function (el, done) {
console.log(' Leave');
var done = done;
TweenMax.to(".transition--layer", .75, { yPercent: 0, ease: Power3.easeInOut})
TweenMax.fromTo(".transition-layer--text h2 span", 0.5, {opacity:0, yPercent:100, force3D:true}, {delay:0.75, ease:Power3.easeInOut, opacity:0.75, yPercent:0,force3D:true, onComplete: function () { console.log('leave'); done() }}, 0.2);
}
},
}
</script>
It is actually quite easy to have different transitions for different layouts. I will say this with the caveat that I can make it work with what I know, which is basic old vanilla css and I really have no idea what your TweenMax and so forth up above is doing. I will show you an example of how I do it and I'm sure you'll be able to tailor it to your needs.
If I want a universal transition I'd set it up like this:
//nuxt.config.js
transition:
{
name: 'fade',
mode: 'out-in'
},
and a global css file, let's say main.css
//main.css
.fade-enter-active {
animation: acrossIn .30s ease-out both;
}
.fade-leave-active {
animation: acrossOut .30s ease-in both;
}
#keyframes acrossIn {
0% {
transform: translate3d(-100%, 0, 0);
}
100% {
transform: translate3d(0, 0, 0);
}
}
#keyframes acrossOut {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(100%, 0, 0);
}
}
Now if I want to tailor a transition to a specific layout I'll remove the styles from main.css and put them in the style section of the layout file:
//default.vue
<style>
.fade-enter-active {
animation: acrossIn .30s ease-out both;
}
.fade-leave-active {
animation: acrossOut .30s ease-in both;
}
#keyframes acrossIn {
0% {
transform: translate3d(-100%, 0, 0);
}
100% {
transform: translate3d(0, 0, 0);
}
}
#keyframes acrossOut {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(100%, 0, 0);
}
}
...
</style>
Each layout file must keep the naming set up in nuxt.config but otherwise it works fine. The only limitation is there is no transition if going from one layout to another.

JavaScript Animation: Handling Complex Animations That Use Callbacks & Loop

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)

jQuery: Call and Uncall a Function

I am using the following code to call a function when the screen is less than 200 but I can't disable the function when the scroll is more than 200.
function animateHeader() {
$(selector)
.animate({ opacity: 0.0, bottom: 70 }, { duration: 600 })
.animate({ opacity: 0.0, bottom: 50 }, { duration: 0 })
.animate({ opacity: 0.0, bottom: 70 }, { duration: 600, complete: animateHeader })
}
$window.on('scroll', function() {
if ($(window).scrollTop() < 200) {
animateHeader();
} else {
// Disable animateHeader()
}
}); // Finish scroll
I know there are alternatives to not call a function here in this case, but is it possible to disable a function when it's already active?
Try using stop() function:
else {
$(selector).stop();
}

Categories