How to move plane icon with framer motion? - javascript

I have a react paper plane icon that I would like to make a cool effect by making it travel around the HTML document reaching the final position which is the menu button at the top.
This is how my react component called NavPlane looks like:
import React, { Component, useEffect } from "react";
import { useCycle } from "framer-motion";
import { FaPaperPlane } from "react-icons/fa";
import { motion } from "framer-motion";
const PlaneVariants = {
animationOne: {
x: 370,
y: 250,
transition: { ease: [0.17, 0.67, 0.83, 0.67] },
},
animationTwo: {
x: 140,
y: 150,
transition: { duration: 1.0 },
},
animationThree: {
x: 170,
y: 200,
transition: { duration: 1.0 },
},
};
export default function NavPlane() {
const [animation, cycleAnimation] = useCycle(
"animationOne",
"animationTwo",
"animationThree"
);
useEffect(() => {
setTimeout(() => {
cycleAnimation();
}, 1000);
}, []);
return (
<motion.div
className="text-2xl text-gray-600"
variants={PlaneVariants}
animate={animation}
>
<FaPaperPlane />
</motion.div>
);
}
cycleAnimation() was supposed to cycle through 3 animations but only cycling through the first two. The 3rd is only applied when making some change to the code and updating it.
The final goal is to have a movement that goes from right corner of the page to middle, does a knot movement and then travels to the top of the page.
Any ideas how to make it cycle through as many animation variants as I want?

cycleAnimation only advances one step. Initially it will start "animationOne". Once you call cycleAnimation() after 1 second, "animationTwo" will start. You need another timer if you want to play "animationThree"
useEffect(() => {
setTimeout(cycleAnimation, 1000); // start "animationTwo" after 1 second
setTimeout(cycleAnimation, 2000); // start "animationThree" after 2 seconds
}, []);

Related

use gsap scrollTrigger in react

I am trying to imply some animations in an image while scrolling , the image will grow while scrolling down and return to normal when scrolling up . The reference : codepen.
This is my react code :
<ArticleWrapper ref={ref}>
<img id='grow' className='image' src={Img} alt='Image' />
</ArticleWrapper>
I have tried to implement this but it didnt work when I scroll :
const ref = useRef(null);
useEffect(() => {
const element = ref.current;
scrollTrigger: {
trigger: "#grow",
scrub: 1.5,
start: "top center",
end: "+=400",
ease: "power1.out"
},
{
duration: 1,
scale: 1
}
);
}, []);
Any idea how to do that ?

Passing div style as a function argument Javascript/ React

I'm building an application using React, framer-motion and react-intersection-observer.
Inside animation.js I have a function which is imported inside App.js and used as a component in App.js.
I want to apply an aspect ratio to some divs using style as a parameter, but it doesn't work.
<FadeAnimation name={'project-image--image'} style={'--ratio':16/9} />
Failed to set an indexed property on 'CSSStyleDeclaration': Indexed property setter is not supported.
I have other divs with this property and they are displayed correctly
<div className='project-image--image' style={{'--ratio':1/2}}/>
Animation.js
export const container = {
hidden: { opacity: 0, y: 5 },
visible: { opacity: 1, y: 0 }
}
function FadeAnimation({ children, name, delay, duration, style }) {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start("visible");
}
}, [controls, inView]);
return (
<motion.div className={`${name}`} style={{`${style}`}}
ref={ref}
animate={controls}
initial="hidden"
transition={{ duration: duration, delay: delay }}
variants={{
visible: { opacity: 1, y: 0 },
hidden: { opacity: 0, y: 5 }
}}
>
{children}
</motion.div>
);
}
Have you tried:
<FadeAnimation name={'project-image--image'} style={{'--ratio':16/9}} />
(Adding another curly brace)
And then, in the FadeAnimationComponent using it as
<motion.div className={`${name}`} style={style} {/*...*/}/>

Framer Motion opacity keyframe only animates on initial render

I'm using Framer Motion
The box should go from opacity: 0 to 1 and increase in height on every state toggle. However, the height is different based on the condition.
I don't have a clue why "height" is being animated every time - correctly, but "opacity" is only animated in the first render.
I tried [0, 1, 0] & [1, 0, 1] too, but none of them has the desired effect.
I even tried [0, 1, 0.5] to test better, but it stays at 0.5.
Code
https://codesandbox.io/s/angry-raman-bc9sf?file=/src/App.js
import { motion } from "framer-motion";
import { useState } from "react";
export default function App({ href = "#", label, icon, notifCount }) {
const [conditionIsMet, setConditionIsMet] = useState(false);
const notifVariants = {
conditionA: {
opacity: [0, 1],
height: ["40px", "90px"]
},
conditionB: {
opacity: [0, 1],
height: ["40px", "200px"]
}
};
return (
<>
{`Condition is ${conditionIsMet ? "A" : "B"}`}
<button onClick={() => setConditionIsMet(!conditionIsMet)} />
<motion.span
animate={conditionIsMet ? "conditionA" : "conditionB"}
variants={notifVariants}
/>
</>
);
}
I think it's a bug but as a temporary fix you can use opacity: [0, 1.01] for conditionB.
please open an issue for this bug.

Is this the right way to import gsap in vue.js (it works but is it the "right" way?)

I'm quite new to Vue.js and have had some problems getting libraries to work without getting the "error 'X' is not defined no-undef" message.
In this case it is 'Back' that is not defined (which is a part of GSAP)
I figured the only place to "define" Back would be in the import.
Is this just the way to import libraries?
Do I have to write every undefined part in the import like this?
It works but it just seems unnecessary.
<template>
<div id="mainTemplate">
<h2>This is the MainTemplaye.vue Component</h2>
<div ref="box" class="box"></div>
</div>
</template>
<script>
import { TimelineLite, Back } from "gsap";
export default {
name: "MainTemplate",
mounted() {
const { box } = this.$refs;
const timeline = new TimelineLite();
timeline.to(box, 1, { x: 200, rotation: 90, ease: Back.easeInOut, })
timeline.to(box, 0.5, { background: 'green' },'-=0.5')
},
};
</script>
<style>
.box {
height: 60px;
width: 60px;
background: red;
}
</style>
I'm not sure where you're learning from, but you're using the old syntax of GSAP. If you use the new syntax of GSAP you don't have to import anything other than gsap in your case:
import { gsap } from "gsap";
export default {
name: "MainTemplate",
mounted() {
const { box } = this.$refs;
const timeline = gsap.timeline();
timeline.to(box, { duration: 1, x: 200, rotation: 90, ease: 'back.inOut' })
timeline.to(box, { background: 'green' }, '-=0.5')
},
};
The best place to start learning is the official GSAP Getting Started article.

React-Native Animated.spring callback is being delay

I am setting a simple layout on my react-native app with a list of products in which on can click and open a booking flow. When you click on a product, the whole app is sliding to the left, and the product page is sliding from the right to the left.
When I click back from the product page, I am sliding back the app and the product to the right. But because the product page is part of the booking flow, i am suppose to unmount the BookingFlow component by setting a state to false.
Problem is there is a delay in the callback of the animation so it takes 400ms for the BookingFlow component to be unmounted.
I use the callback from Animated.parallel in order to do so:
closeProduct () {
Animated.parallel([
Animated.spring(this.props.translateXApp, {
toValue: 0,
duration: 140,
bounciness: 0,
speed: 14,
easing: Easing.ease,
useNativeDriver: true
}),
Animated.spring(this.translateXProduct, {
toValue: width,
duration: 140,
bounciness: 0,
speed: 14,
easing: Easing.ease,
useNativeDriver: true
})
]).start(() => {
this.props.closeBookingFlow()
})
}
On my app.js here is my code:
<Animated.View style={[styles.translateXView,{transform: [{translateX: this.translateXApp},{scale:this.scallApp}]}]}>
<Application
openCategory={this.openCategory.bind(this)}
openProduct={this.openProduct.bind(this)}
/>
</Animated.View>
{
this.state.showBookingFlow == true?
<BookingFlow
closeBookingFlow = {this.closeBookingFlow.bind(this)}
onRef={ref => (this.bookingFlowRef = ref)}
translateXApp = {this.translateXApp}
/>
:null
}
I found a trick in order to avoid this issue but it is not very proper. I use a timeout outside of the animation which is waiting 400ms.
setTimeout(function(){
that.props.closeBookingFlow()
}, 400);
Is there a way to avoid the delay in the animated callback?
Thanks guys.
I figured out that i needed to add those 2 values to my springs animations:
restSpeedThreshold: 100, restDisplacementThreshold: 40

Categories

Resources