scrollmagic anchoring or pausing animation until user scrolls again - gsap

with the following code,
var firstScene = new TimelineLite()
.to(".some-background", 1000, { transform: 'translate(350px, 0)' })
.to(".old-text", 1000, { opacity: 0 })
.to(".new-text", 1000, { opacity: 1 })
.to(".new-text", 1000, { opacity: 0 })
.to(".new-text-2", 1000, { opacity: 1 })
new ScrollMagic.Scene({triggerHook: 'onLeave', triggerElement: "#container", duration: 5000})
.setPin("#container")
.setTween(firstScene)
.addTo(controller);
is it possible to 'anchor' or stop/pause the animation between fading in .new-text and fading it out until user scrolls again rather than creating another trigger somewhere to just delay the animation?

Related

How to animate shrinking and growing of two elements at the same time?

I want to create a weekly plan and the user should be able to "select" a day which should then grow in the ui (example below).
I am using the Animated class from react-native and noticed I am not able to animate the flex-property, so I believe I have to do this using width and height.
I tried the following after reading #M.N.s awnser:
selectDay = (i: number) => {
const {selected, grow, shrink} = this.state;
this.setState({selected: i, latestSelected: selected});
grow.setValue(0.5);
shrink.setValue(1);
Animated.parallel(
[
Animated.timing(grow, {
toValue: 1,
duration: 200,
useNativeDriver: false,
easing: Easing.cubic,
}),
Animated.timing(shrink, {
toValue: 0.5,
duration: 200,
useNativeDriver: false,
easing: Easing.cubic,
}),
],
{stopTogether: false},
).start();
};
// In my render:
const growInterpolate = grow.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '25%'],
});
const shrinkInterpolate = shrink.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '25%'],
});
But it still behaves very laggy:
Video of the animation
In such case you need to use parallel animation:
Animated.parallel([
Animated.timing(animatedHeight, {
toValue: newHeight,
duration: 200,
}),
Animated.timing(animatedWidth, {
toValue: newWidth,
duration: 200,
})
], { stopTogether: false }).start()
More information:
https://reactnative.dev/docs/animated#parallel

React Native custom loader Animation from CSS code

I'm having a problem recreating a
CSS loader animation in React Native with Animated API.
My React Native attempt:
screen record.
CSS code is below:
.whitePillar {
width: 8px;
height: 50px;
margin-right:5px;
background-color: #FFF;
animation: animation 1s infinite;
float: left;
}
.whitePillar :nth-child(10) {
animation-delay: 0.9s;
}
.whitePillar :nth-child(9){
-webkit-animation-delay: 0.8s;
animation-delay: 0.8s;
}
.whitePillar :nth-child(8) {
animation-delay: 0.7s;
}
.whitePillar :nth-child(7){
-webkit-animation-delay: 0.6s;
animation-delay: 0.6s;
}
.whitePillar :nth-child(6) {
animation-delay: 0.5s;
}
.whitePillar :nth-child(5) {
animation-delay: 0.4s;
}
.whitePillar :nth-child(4){
-webkit-animation-delay: 0.3s;
animation-delay: 0.3s;
}
.whitePillar :nth-child(3) {
animation-delay: 0.2s;
}
.whitePillar :nth-child(2) {
animation-delay: 0.1s;
}
#keyframes animation {
50% {
transform: translateX(-25px) scaleY(0.5);
}
}
React Native code is below:
<View style={styles.loaderContainer}>
<View style={styles.pillarsWrapper}>
{[...Array(numberOfPillars)].map((value, index) => (
<LoaderPillar
delay={index*100}
key={index}
/>
))}
</View>
</View>
LoaderPillar represents every individual white pillar:
<Animated.View
style={[styles.pillar, pillarAnimation]}
/>
and I've done the animation on LoaderPillar using this:
const [ pillarAnimationTranslate ] = useState(new Animated.Value(0));
const [ pillarAnimationScale ] = useState(new Animated.Value(1));
const pillarAnimation = {
transform: [{translateX: pillarAnimationTranslate}, {scaleY: pillarAnimationScale}]
};
useEffect(() => {
Animated.loop(Animated.timing(pillarAnimationScale, {
toValue: 0.5,
duration: 500,
delay: delay,
useNativeDriver: true,
easing: Easing.ease
})).start();
}, [pillarAnimationScale]);
useEffect(() => {
Animated.loop(Animated.timing(pillarAnimationTranslate, {
toValue: -25,
duration: 500,
delay: delay,
useNativeDriver: true,
easing: Easing.ease
})).start()
}, [pillarAnimationTranslate]);
I am new to React Native animations, so I don't even know if I'm on the right track. The problem, I think, is the keyframes part in CSS - that percentage (50%) - and I don't know how would I recreate that.
Any advices on upgrading this or even completely changing would be greatly appreciated. Thank You in advance.
EDIT: still NOT working, but very close to the end result.
I broke down this problem into two parts: first making scale animation and then just adding translate animation - it is easier that way.
Code:
const [ pillarAnimationTranslate ] = useState(new Animated.Value(0));
Animated.loop(
Animated.sequence([
Animated.timing(
pillarAnimationScale,
{
toValue: 1,
duration: 500,
delay: delay,
useNativeDriver: true,
easing: Easing.ease
}
),
Animated.timing(
pillarAnimationScale,
{
toValue: 0,
duration: 500,
useNativeDriver: true
})
])
).start();
And then using interpolate function:
const scale = pillarAnimationScale.interpolate({
inputRange: [0, 1],
outputRange: [1, 0.5]
});
const pillarAnimation = {
transform: [{scaleY: scale}]
};
And in the ned returning Animated View (as in the original post);
return (
< Animated.View
style={[styles.pillar, pillarAnimation]}
/>
);
The problem I'm now having is inconsistency of the iterations, as you can see in the GIF below (first iteration is perfect and then it just gets chaotic for some reason, it should be a perfect wave at all times):
Does anybody see what is causing inconsistent iterations?

Refresh GSAP ScrollTrigger after Barba transition

I'm unable to get ScrollTrigger working after a page transition.
I'm using the views data within the barbs.init.
/*PAGE TRANSITION*/
barba.init({
transitions: [{
name: 'opacity-transition',
leave(data) {
return gsap.to(data.current.container, {
duration: 0.5,
opacity: 0,
y: '50px',
});
},
enter(data) {
gsap.from(data.next.container, {
duration: 0.5,
opacity: 0,
x:'-50px',
});
}
}],
views: [{
namespace: 'tester',
beforeLeave(data) {
//alert('Leaving tester');
},
beforeEnter(data) {
//alert('Entering tester');
},
afterEnter(data) {
//alert('Entered tester');
ScrollTrigger.refresh();
}
}]
});
Most other code fires OK. However I cannot get gsap scroll trigger to work after a page transition. (Have the same issue with locomotive.js)
Can someone please advise what I might be doing wrong.
I'm new to Barba and ScrollTrigger, and have limited JS experience so an explicit answer would be very welcome.
You needed to add the ScrollTrigger.refresh(); to trigger when the animation ends, not the new page entered. You can do that using the onComplete property in your GSAP tween, as follow:
// ADD onComplete
enter(data) {
gsap.from(data.next.container, {
duration: 0.5,
opacity: 0,
x:'-50px',
onComplete: () =>{
ScrollTrigger.refresh(true)
}
And you can delete this in your Barba.js view
// DELETE THIS
afterEnter(data) {
//alert('Entered tester');
ScrollTrigger.refresh();
}

My React Native Animation Duration Isn't Working

I have an animation in my login screen which is supposed to slide down the buttons when the sign in button is clicked and slide up the email and password input boxes at the same time, i have a duration of 2000 milliseconds but the positions change instantly instead of smoothly sliding.
The Animation is in a functional component, so to stop the animation from reverting back before i click to reverse it so i am using useState() to hold the position.( Previously before i was using useState(), when i changed the text in the input boxes, the animation would reset back to the original position)
Here is the Animation
const [Buttons, setButtons] = useState(200);
const [Input, setInput] = useState(800);
const AnimatedButtons = new Animated.ValueXY({ x: 0, y: Buttons })
const AnimatedInputs = new Animated.ValueXY({ x: 0, y: Input })
const StartAnmation = () => {
setButtons(800);
Animated.timing(
AnimatedButtons, {
toValue: { x: AnimatedButtons.x, y: AnimatedButtons.y },
duration: 2000,
useNativeDriver: true,
}).start()
setInput(-100);
Animated.timing(AnimatedInputs, {
toValue: { x: AnimatedInputs.x, y: AnimatedButtons.y },
duration: 2000,
useNativeDriver: true,
}).start()
}
const ReverseAnimation = () => {
setButtons(200)
Animated.timing(
AnimatedButtons, {
toValue: { x: AnimatedButtons.x, y: AnimatedButtons.y },
duration: 2000,
useNativeDriver: true,
}).start()
setInput(800)
Animated.timing(AnimatedInputs, {
toValue: { x: AnimatedInputs.x, y: AnimatedInputs.y },
duration: 2000,
useNativeDriver: true,
}).start()
}
I have 2 button onPress() that call the animations and have 2 Views which change positions, The positions change alright but i doesnt slide out gradually , just instantly change
Thanks

How to trigger TimelineMax animation when ScrollToPlugin is scrolling (ScrollMagic)?

I have a section with button which on click triggers scroll to the next section.
What I want to do is when this scroll event is happening I want to trigger my tl.from animations.
Right now animations tl.from are triggered only on user scroll but not on button pressed.
const button = document.getElementById('cta');
let tl = new TimelineMax({ onUpdate: updatePercentage })
function scrollToNextSection() {
TweenLite.to(window, 2, { scrollTo: '#section-1'});
}
tl.from('.section__left', .5, { x: 200, opacity: 0, ease: Power4.easeOut })
tl.from('.section__right', .5, { x: -200, opacity: 0, ease: Power4.easeOut })
tl.from('.section__img', 1, { x: 400, opacity: 0 })
// init controller
var controller = new ScrollMagic.Controller();
// create a scene
new ScrollMagic.Scene({
triggerElement: '#section-1',
triggerHook: 'onLeave',
duration: '100%',
})
.setPin("#section-1")
.setTween(tl)
.addTo(controller);
function updatePercentage() {
tl.progress();
}
button.addEventListener('click', scrollToNextSection);
Try to change your code like that :)
const button = document.getElementById('cta');
let tl = new TimelineMax({ onUpdate: updatePercentage }).from('.section__left', .5, { x: 200, opacity: 0, ease: Power4.easeOut })
.from('.section__right', .5, { x: -200, opacity: 0, ease: Power4.easeOut })
.from('.section__img', 1, { x: 400, opacity: 0 });
function scrollToNextSection() {
TweenLite.to(window, 2, { scrollTo: '#section-1'});
}
// init controller
var controller = new ScrollMagic.Controller();
// create a scene
new ScrollMagic.Scene({
triggerElement: '#section-1',
triggerHook: 'onLeave',
duration: '100%',
})
.setPin("#section-1")
.setTween(tl)
.addTo(controller);
function updatePercentage() {
tl.progress();
}