So I'm having this problem I have a scrollTrigger Timeline and i want a button to scroll to take me to a specific position.
I tried using seek but it didnt work even ScrollTo plugin lack a support for this
I have a gsap Timeline
const tl = gsap.timeline({
paused: true,
scrollTrigger: {
trigger: '.home',
start: 'top top',
end: 'bottom+=1000 top',
pin: true,
scrub: 0.5,
markers: true
},
defaults: {
duration: 2
}
})
// Main home animation
.to(['.left'], {
clipPath: 'polygon(0 0, 100% 0, 100% 100%, 0 100%)',
ease: 'power1.out'
}, 'scene')
// Name scaling animation
.to(['.name-title'], {
scale: 0,
ease: 'power1.out'
}, 'scene')
.from(document.getElementById('achievements'), {
autoAlpha: 0
}, '-=1.5')
// Achievements reveal animation
.from(document.getElementById('achievements').querySelectorAll('.row'), {
motionPath: {
path: [
{
x: 0,
y: 100
}
]
},
autoAlpha: 0,
stagger: 0.2,
ease: 'power3.out'
}, '-=2')
.addLabel('achievements')
// Hide achievements animation
.to(document.getElementById('achievements').querySelectorAll('.row'), {
motionPath: {
path: [
{
x: 0,
y: -100
}
]
},
autoAlpha: 0,
stagger: 0.2,
ease: 'power3.in'
}, '+=2')
and i have a button in my home that should take me to achievements section but i cant find any proper solution.
So i deviced my own workaround solution (P.S: im using Vue)
scrollTo () {
const pos = Math.ceil(document.body.scrollHeight * (this.loadTl.labels.achievements / this.loadTl.duration()))
gsap.to(window, { duration: 2, scrollTo: pos, ease: 'linear' })
}
loadTl here is a computed property for my Timeline i Found the position of achievements and used ScrollToPlugin to scroll to that pixel.
But im looking for a better way of doing this.
Related
Is there any way to fix an animation bug when I quickly mouseover/mouseout an element?
This is the live version of the website - https://daphne-rebuild.netlify.app/
When I quickly hover on and off the circle, it becomes buggy. Happens all the time so I'm really hoping there's some kind of fix.
<div class="hover-circle" #mouseover="hoverCircle" #mouseout="leaveCircle">
<div class="circle"></div>
<span>Enter</span>
</div>
hoverCircle(e) {
gsap.to(".hover-circle .circle", {
duration: 1,
scale: 1.3,
ease: "power4.out"
});
gsap.to(`.home-${this.currentComponent}`, {
delay: 0.1,
duration: 1,
scale: 1.05,
ease: "power4.out"
});
},
leaveCircle() {
gsap.to(".hover-circle .circle", {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
gsap.to(`.home-${this.currentComponent}`, {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
},
The problem is you placed a delay on hoverCircle. If hoverCircle and leaveCircle happen within less than 0.1s, the delayed animation from hoverCircle will actually get executed after the animation from leaveCircle. Removing the delay will probably fix the problem.
I can't be sure from the code you posted, but you might also want to stop any currently playing animations on your element (both when entering and leaving). To do that, use...
gsap.killTweensOf(target)
..., documented here.
In your example, it would probably look like:
hoverCircle() {
gsap.killTweensOf(".hover-circle .circle");
gsap.to(".hover-circle .circle", {
duration: 1,
scale: 1.3,
ease: "power4.out"
});
gsap.killTweensOf(`.home-${this.currentComponent}`);
gsap.to(`.home-${this.currentComponent}`, {
duration: 1,
scale: 1.05,
ease: "power4.out"
});
},
leaveCircle() {
gsap.killTweensOf(".hover-circle .circle");
gsap.to(".hover-circle .circle", {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
gsap.killTweensOf(`.home-${this.currentComponent}`);
gsap.to(`.home-${this.currentComponent}`, {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
}
If you have this in multiple places, you might want to refactor into a method called stopAnimations:
hoverCircle() {
this.stopAnimations();
gsap.to(".hover-circle .circle", {
duration: 1,
scale: 1.3,
ease: "power4.out"
});
gsap.to(`.home-${this.currentComponent}`, {
duration: 1,
scale: 1.05,
ease: "power4.out"
});
},
leaveCircle() {
this.stopAnimations();
gsap.to(".hover-circle .circle", {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
gsap.to(`.home-${this.currentComponent}`, {
duration: 0.5,
scale: 1,
ease: "power4.inOut"
});
},
stopAnimations() {
gsap.killTweensOf(".hover-circle .circle");
gsap.killTweensOf(`.home-${this.currentComponent}`);
}
I have used GSAP 3.0 ScrollTrigger in one of my websites everything is working fine but I want my animations to be reversed when leaving the section or div. I know there is a callback call onLeave but I am not able to figure out how to use it. I am new to the scroll trigger. I am pasting the code sample for you to understand.
armor animation config
let armor = gsap.timeline({
scrollTrigger: {
trigger: '.armor-animation',
pin: true,
pinSpacing: true,
anticipatePin: .5,
scrub: 1,
start: "top 150px",
end: "+=1500",
toggleActions: "play reverse none none",
// scroller: ".smooth-scroll"
// markers: true,
onLeave: () => {
// armor.from(".layer-1", .8, {
// translateY: 200,
// opacity: 0
// }, .5)
// console.log("leave");
}
}
});
armor section animation
armor.from(".layer-1", .8, {
translateX: -200,
opacity: 0
}, .5)
.from(".layer-2", .8, {
translateY: 200,
opacity: 0
}, .6)
.from(".layer-3", .8, {
translateY: -200,
opacity: 0
}, .6)
.from(".crack-effect", 2, {
translateY: -200,
opacity: 0
}, 2)
.from(".method h1", 2, {
translateX: 200,
opacity: 0
}, .6);
//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.
I'm using barba.js to fade new pages in. Code must be placed between the barba wrapper div. When I click a link to a new page though, the new page fades in at the same position as the previous page was in. So if the user clicks a link, the new page is loading in near , which I don't want.
How can I get the new page to load in at the top?
I found the answer on stack about scrollRestoration function but I still don't understand how to make this work.
Could somebody help me to compile the js code below, add some css or html to fix this issue?
$(window).scrollTop(0);
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
function delay(n) {
n = n || 2000;
return new Promise((done) => {
setTimeout(() => {
done();
}, n);
});
}
function pageTransition() {
var tl = gsap.timeline();
tl.to(".animate-this", {
duration: .2, opacity: 0, delay: 0, y: 30, //scale:0, delay: 0.2,
});
tl.to(".animate-this", {
duration: 0, opacity: 0, delay: 0, scale:0, //scale:0, delay: 0.2,
});
tl.fromTo(".loading-screen", {width: 0, left: 0}, {
duration: 1,
width: "100%",
left: "0%",
ease: "expo.inOut",
delay: 0.3,
});
tl.to("#svg-1", {
duration: 1, opacity: 0, y: 30, stagger: 0.4, delay: 0.2,
});
tl.to(".loading-screen", {
duration: 1,
width: "100%",
left: "100%",
ease: "expo.inOut",
delay: 0, //CHANGE TIME HERE END TRANS
});
tl.set(".loading-screen", { left: "-100%", });
tl.set("#svg-1", { opacity: 1, y: 0 });
}
function contentAnimation() {
var tl = gsap.timeline();
tl.from(".animate-this", { duration: .5, y: 30, opacity: 0, stagger: 0.4, delay: 0.2 });
}
$(function () {
barba.init({
sync: true,
transitions: [
{
async leave(data) {
const done = this.async();
pageTransition();
await delay(2500);
done();
},
async enter(data) {
contentAnimation();
},
async once(data) {
contentAnimation();
},
},
],
});
});
Have a look:
https://pasteboard.co/Ja33erZ.gif
Here also a codepen to check my issue (html,css):
https://codepen.io/cat999/project/editor/AEeEdg
scrollRestoration shouldn't be necessary, this can be done by resetting scroll position during the transition:
tl.fromTo(".loading-screen", {width: 0, left: 0}, {
duration: 1,
width: "100%",
left: "0%",
ease: "expo.inOut",
delay: 0.3,
onComplete: function() {
window.scrollTo(0, 0);
}
});
Working example here: https://codepen.io/durchanek/project/editor/ZWOyjE
This should be what you're looking for:
barba.hooks.enter(() => {
window.scrollTo(0, 0);
});
(can be found in the docs)
Question:
I am wondering if there is a way to add a negative delay to the staggerFrom / staggerTo functions in greensock?
Problem:
I have animation is running too long for my liking. It would be great if my staggered animations could happen as the previous animations are playing to cut down the duration.
Example:
I have put together this codepen to illustrate what I am after: http://codepen.io/nickspiel/pen/LpepvQ?editors=001
You can see in the codepen that I have used negative delays on the basic from timeline functions but this doesn't work for the staggerForm function as the delay parameter is used to delay each element of the jquery collection.
Have you tried to use the new cycle property introduced in the latest v1.18.0 of GSAP?
So you can cycle with delay but passing 0 as stagger value in the staggerTo calls.
Also, you can pass position parameter to staggerTo calls to make them overlap with the previously inserted tween.
Here is the forked pen for an idea.
JavaScript:
...
animateElement = function() {
timeline.from(main, 0.3, { scaleY: '0%', ease: Back.easeOut.config(1.7) })
.staggerFrom(dataBlocks, 0.3, { cycle: { delay: function(index) {
return index * 0.1;
}}, scale: '0%', y: 100, ease: Back.easeOut.config(1.7) }, 0)
.from(lineGraphLines, 1.5, { drawSVG: 0, ease: Power1.easeOut }, '-=0.5')
.from(lineGraphAreas, 1, { opacity: 0, ease: Back.easeOut.config(1.7) }, '-=2.0')
.staggerFrom(lineGraphDots, 0.2, { cycle: { delay: function(index) {
return index * 0.1;
}}, scale: 0, ease: Back.easeOut.config(1.7) }, 0, '-=1.0')
.staggerFrom(donutCharts, 0.6, { cycle: { delay: function(index) {
return index * 0.1;
}}, drawSVG: 0, ease: Power1.easeOut }, 0, '-=2.0')
.from(menuBackground, 0.3, { scaleX: '0%', ease: Back.easeOut.config(1.7) }, '-=6')
.staggerFrom(menuElements, 0.3, { cycle: { delay: function(index) {
return index * 0.1;
}}, scaleX: '0%', ease: Back.easeOut.config(1.7) }, 0, '-=1')
.from(headerBackground, 0.5, { scaleX: '0%', ease: Power1.easeOut }, '-=5.5')
.staggerFrom(headerBoxes, 0.3, { cycle: { delay: function(index) {
return index * 0.1;
}}, scale: '0%', ease: Back.easeOut.config(1.7) }, 0, '-=1.0')
.staggerFrom(headerText, 0.4, { cycle: { delay: function(index) {
return index * 0.1;
}}, scaleX: '0%', ease: Back.easeOut.config(1.7) }, 0, '-=1.0')
.from(headerText, 0.4, { scaleX: '0%', ease: Back.easeOut.config(1.7) }, '-=4');
};
...
This may not be exactly the type of animation you wanted but you'll need to adjust the position parameter in most/all of your tweens as per your liking but I think the main take away for you would be the use of cycle with delay.
Hope this helps in some way.
P.S. You can pass negative stagger values but they have a different meaning. It tells the engine to start the staggered animation from the last element.
I asked this same question on the Greensock GitHub repo and had the following response:
Absolutely - that's already baked in. I'm not sure if you're using
TweenMax or one of the timeline classes, so I'll show you both:
TweenMax.staggerTo(elements, 1, {x:100, delay:2}, 0.01);
// - OR -
var tl = new TimelineLite();
tl.staggerTo(elements, 1, {x:100, delay:2}, 0.01);
// - OR -
var tl = new TimelineLite();
tl.staggerTo(elements, 1, {x:100}, 0.01, "label+=3");
In my case the last option worked flawlessly.