I have an animation on a logo that I want to happen when the logo is being hovered over.
Here's the CodeSandbox Demo.
Current behavior: When you hover over the logo, the correct animation occurs. When you move off the logo, the middle path spins again.
Expected behavior: Animation occurs on hover, reverts back to contracted logo when mouse is no longer hovering
Any ideas?
Logo code:
import { motion, Variants } from "framer-motion";
interface LogoProps {
hover?: boolean;
width?: string;
height?: string;
}
interface CustomVariants {
[key: string]: Variants;
}
const Logo: React.FC<LogoProps> = (props: LogoProps) => {
const customVariants: CustomVariants = {
left: {
rest: {
x: 0
},
hover: {
x: -20,
transition: {
repeat: 1,
repeatType: "reverse",
repeatDelay: 1
}
}
},
right: {
rest: {
x: 0
},
hover: {
x: 20,
transition: {
repeat: 1,
repeatType: "reverse",
repeatDelay: 1
}
}
},
bottom: {
rest: {
y: 0
},
hover: {
y: 20,
transition: {
repeat: 1,
repeatType: "reverse",
repeatDelay: 1
}
}
},
middle: {
rest: {},
hover: {
rotate: -360 * 10,
transition: {
delay: 0.5
}
}
}
};
return (
<motion.svg
width={props.width ?? 60}
height={props.height ?? 60}
viewBox="0 0 158 146"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="verifax-logo"
>
<motion.path
id="side"
d="M14.5017 66.3155C14.5327 75.092 14.8561 82.8129 15.1938 83.3718C15.4639 83.819 22.2984 87.9471 30.187 92.5369L44.6399 100.808L44.6607 85.4447C44.6485 76.9559 44.8577 69.0902 45.0151 67.811C45.3187 66.004 48.3905 64.16 60.19 58.5434C69.5292 53.9863 74.6938 50.9875 74.2886 50.3168C73.8834 49.6461 67.2327 45.5656 59.3629 41.2634L45.1125 33.3279L29.765 41.7966L14.4174 50.2652L14.5017 66.3155Z"
fill="#6200EA"
initial="hover"
animate={props.hover ? "hover" : "rest"}
variants={customVariants.left}
/>
<motion.path
className="side"
d="M61.1382 25.1267C61.3405 25.4616 67.2779 28.8833 74.2679 32.7662C81.4415 36.6965 87.9483 40.5483 88.8361 41.2492C89.724 41.95 90.5114 49.4043 90.4749 58.0574C90.371 66.5989 90.6078 73.9104 90.8101 74.2453C91.0124 74.5802 97.8331 71.2631 106.077 66.7141L120.823 58.5772L120.855 42.4844C120.757 33.6081 120.501 26.0092 120.164 25.451C119.894 25.0045 113.136 20.9935 105.142 16.4739L90.593 8.27822L75.7307 16.4792C67.6029 20.9641 61.0033 24.9034 61.1382 25.1267Z"
fill="#6200EA"
animate={props.hover ? "hover" : "rest"}
variants={customVariants.right}
/>
<motion.path
className="side"
d="M59.6443 33.9735L59.5773 38.4802L70.0055 44.1985L80.5013 50.0285L63.9667 59.5989L47.4321 69.1693L47.5159 80.5954C47.6605 100.331 47.1504 98.974 52.497 96.0239C56.9137 93.5868 57.0599 93.0592 56.9503 84.9252C56.7873 69.52 55.3063 69.8902 74.0554 80.4036L90.9782 89.6898L104.926 81.9938L118.873 74.2978L114.437 71.8288L110.069 69.4716L99.1732 75.0366C93.178 78.1957 88.1425 80.3782 88.0075 80.1547C87.805 79.8194 87.6091 71.2861 87.503 61.3622L87.2685 43.0167L74.2791 35.8808C67.0983 31.9465 60.8736 28.8255 60.4087 29.082C59.9438 29.3386 59.5428 31.4967 59.6443 33.9735Z"
fill="#6200EA"
animate={props.hover ? "hover" : "rest"}
variants={customVariants.middle}
/>
<motion.path
className="side"
d="M59.2076 92.5587L59.4758 108.66L74.4152 116.963L89.4708 125.202L104.821 116.732L120.171 108.262L120.087 92.2088L120.07 76.2673L104.982 84.1454L89.8948 92.0235L75.2068 83.8795C67.0168 79.3053 60.1024 75.8161 59.6372 76.0728C59.2884 76.2653 59.0604 83.8447 59.2076 92.5587Z"
fill="#6200EA"
animate={props.hover ? "hover" : "rest"}
variants={customVariants.bottom}
/>
</motion.svg>
);
};
export default Logo;
Assuming that the goal is to remove the hover out effect for middle, since there is already a variant value rest for this element when not hovering, it seems that a transition of duration: 0 can be set with it so that the hover out effect is finished immediately.
Forked example with modification: codesandbox
middle: {
rest: {
rotate: 0,
transition: {
duration: 0,
},
},
hover: {
rotate: -360 * 10,
transition: {
delay: 0.5,
},
},
}
Related
I have this installed react-particles-js, everything works fine as I see, but now I have created some custom design, and assigned it to the Particle via it params, just like this:
<Particles
params={{
particles: {
number: { value: 35, density: { enable: true, value_area: 800 } },
color: {
value: [
'BB4D10',
'#820E42',
'#BD740F',
'#248592',
'#5F4DAF',
'#8BA00F',
],
},
shape: {
type: 'circle',
stroke: { width: 0, color: '#000000' },
polygon: { nb_sides: 3 },
image: { src: 'img/github.svg', width: 100, height: 100 },
},
opacity: {
value: 1.5,
random: false,
anim: {
enable: false,
speed: 1,
opacity_min: 0.1,
sync: false,
},
},
size: {
value: 9,
random: true,
anim: {
enable: false,
speed: 43.15684315684316,
size_min: 0.1,
sync: false,
},
},
line_linked: {
enable: true,
distance: 100.82952832645452,
color: '#ffffff',
opacity: 1.4,
width: 1,
},
move: {
enable: true,
speed: 2,
direction: 'none',
random: true,
straight: false,
out_mode: 'out',
bounce: false,
attract: { enable: false, rotateX: 600, rotateY: 1200 },
},
},
interactivity: {
detect_on: 'canvas',
events: {
onhover: { enable: true, mode: 'bubble' },
onclick: { enable: false, mode: 'push' },
resize: true,
},
modes: {
grab: { distance: 400, line_linked: { opacity: 1 } },
bubble: {
distance: 109.63042366068159,
size: 13,
duration: 2,
opacity: 8,
speed: 3,
},
repulse: { distance: 200, duration: 0.4 },
push: { particles_nb: 4 },
remove: { particles_nb: 2 },
},
},
retina_detect: true,
}}
style={styling}
/>
After that, I'm trying to add a background color to make it look correctly, but as I can see the styling which I try to pass to the particle it just doesn't work, at least the position applies.
const styling = {
backgroundColor: '#2a2e31',
position: 'absolute',
width: '10%',
};
There are several ways to control the styling:
You can provide a className prop for canvas wrapper, and width prop for the width of canvas:
<Particles
...
style={styling}
width="10%"
className="particles-wrapper"
/>
And, write the CSS:
.particles-wrapper {
background-color: #2a2e31;
height: 100%;
width: 10%; // You may need this or may not depending on your requirement
}
Or, you can add a new div which would wrap the <Particles .. /> and set styling for this div as by default canvas is transparent.
Or, you can use canvasClassName prop and set the style for this class.
Here is a snapshot after using the 1st method from above:
The reason that we need to pass width, height separately is, as seen in source code, those present in props.style is being overwritten like this:
style={{
...this.props.style,
width,
height
}}
The easiest way to set a background to the particles is using the background option.
<Particles params={{
background: {
color: "#000"
},
/* all other options you set */
}} />
This will set a background to the canvas. If you need a transparent one use #ajeet-shah answer.
I have lots of links on my page with the HTML format of:
<div class="heading-column">
<div class="heading-container">
<h2 class="heading-item">
<a href="/find/">Find</h2>
</div>
</div>
</div>
Currently we have some animations happening when they hover over the heading-column element, but they should actually only happen when hovering over the a hyperlink.
I'm trying to figure out how to create some jQuery to monitor all hyperlinks, if one with the class of .heading-item a is hovered over for it to update its parent 3 higher (.heading-column) by adding the css of pointer-events: auto; but as soon as the mouse stops hovering, this css rule should be deleted so that the pointer-events: none; stops the .heading-column animation/hover from happening
I'd greatly appreciate some help
Have you tried:
$(".heading-column a").hover(function(){
// In
$(this).closest(".heading-column").css("pointer-events", "none");
}, function(){
// Out
$(this).closest(".heading-column").css("pointer-events", "auto");
});
Reference: https://api.jquery.com/hover/
Might consider adding and removing a Class too.
See if this helps -
https://codepen.io/VweMWoz
const tl = gsap.timeline({paused: true});
tl.from(
".gsap-swipe",
{
y: 20,
x: 20,
rotate: -40,
duration: 3,
transformOrigin: '30% 80%',
ease: Elastic.easeOut.config(1, 0.5),
}, 0
)
.fromTo(
".swipe",
{
xPercent: -100
},
{
duration: 1,
xPercent: 100,
ease: Sine.easeInOut,
stagger: {
each: 0.15
}
}, 0
)
.from(
".maskSwipe",
{
xPercent: -100,
ease: Sine.easeInOut
},
0.4
)
.from(
"#hello",
{
duration: 1.5,
drawSVG: "0%"
},
1
)
.from(
".swoop",
{
duration: 2,
drawSVG: "0%"
},
1
)
.from(
".line",
{
drawSVG: "0%",
duration: 0.5,
stagger: {
each: 0.2
}
},
1
)
.from(
".shape",
{
scale: 0,
duration: 1.3,
transformOrigin: "50% 50%",
rotate: '+=random(-60, 60)',
ease: Elastic.easeOut.config(1, 0.8),
stagger: {
each: 0.2
}
},
0.2
);
// ScrubGSAPTimeline(tl);
let hover = document.querySelector('.js-hover');
hover.addEventListener('mouseover', playTl);
hover.addEventListener('mouseout', resetTl);
function playTl(){
tl.timeScale(1.25).restart();
}
function resetTl(){
tl.progress(0).pause();
}
I`m using barba.js with Gsap.
The idea is to have a transition from the home page and the about page with a centered logo animation, very simple. I click on my button, the transition comes in, the logo scale from 0 to 1, and go down fading, great!
The first animation works as it should but when I clicked again the scale factor is now missing, unfortunately.
How can I fix this to make it work? have a look at my code pen project:
https://codepen.io/cat999/project/editor/AEeEdg
Here my JS
function delay(n) {
n = n || 2000;
return new Promise((done) => {
setTimeout(() => {
done();
}, n);
});
}
function pageTransition() {
var tl = gsap.timeline();
tl.to(".loading-screen", {
duration: 1,
width: "100%",
left: "0%",
ease: "Expo.easeInOut",
});
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.easeInOut",
delay: 0.3,
});
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: 1, 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(2000);
done();
},
async enter(data) {
contentAnimation();
},
async once(data) {
contentAnimation();
},
},
],
});
});
I am currently playing around with React pose. What I'm trying to do is animate different boxes in from the right, and exit them on the left. However, I can't seem to get the preEnterPose to work the way I want it. It always seems to default to the exit pose.
How can I get the boxes to animate in from the right, and exit on the left? Here is what I am working with
https://codesandbox.io/s/react-pose-enterexit-o2qqi?fontsize=14&hidenavigation=1&theme=dark
import React from "react";
import ReactDOM from "react-dom";
import posed, { PoseGroup } from "react-pose";
import "./styles.css";
const Card = posed.div({
enter: {
x: 0,
opacity: 1,
preEnterPose: {
x: 50
},
delay: 300,
transition: {
x: { type: "spring", stiffness: 1000, damping: 15 },
default: { duration: 300 }
}
},
exit: {
x: -50,
opacity: 0,
transition: { duration: 150 }
}
});
class Example extends React.Component {
state = { isVisible: false, index: 0, items: ["1", "2", "3", "4", "5"] };
componentDidMount() {}
next = () => {
if (this.state.index === this.state.items.length - 1) {
this.setState({
index: 0
});
} else {
this.setState({
index: this.state.index + 1
});
}
};
render() {
const { index, items } = this.state;
return (
<div>
<PoseGroup>
{items.map((id, idx) => {
if (idx === index) {
return (
<Card className="card" key={idx}>
{id}
</Card>
);
}
return null;
})}
</PoseGroup>
<button onClick={this.next}>next</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);
First you update your posed.div as the following.
const Card = posed.div({
preEnterPose: {
x: 50,
opacity: 0,
transition: { duration: 150 }
},
enter: {
x: 0,
opacity: 1,
delay: 300,
transition: {
x: { type: "spring", stiffness: 1000, damping: 15 },
default: { duration: 300 }
}
},
exit: {
x: -50,
opacity: 0,
transition: { duration: 150 }
}
});
Then you set your <PoseGroup>'s preEnterPose props to your key of the pose preEnterPose. And it should work. preEnterPose's default props is set to exit. Read it here
<PoseGroup preEnterPose="preEnterPose">
{items.map((id, idx) => {
if (idx === index) {
return (
<Card className="card" key={idx}>
{id}
</Card>
);
}
return null;
})}
</PoseGroup>
I want to click a button and animate an element with the web animation library, For some reason I cant target with document.getElementById without getting an error.
The error is on document.getElementById and is Object is possibly 'null'.ts(2531)
import React, {useContext} from "react";
const Home: React.FC = () => {
function startAnimation() {
var player = document.getElementById('home').animate([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(.5)', opacity: .5, offset: .3 },
{ transform: 'scale(.667)', opacity: .667, offset: .7875 },
{ transform: 'scale(.6)', opacity: .6, offset: 1 }
], {
duration: 700,
easing: 'ease-in-out',
delay: 10,
iterations: Infinity,
direction: 'alternate',
fill: 'forwards',
});
}
return (
<nav onClick={startAnimation}>
Click Me
</nav>
<main id="home">
Animate me
</main>
);
}
export default Home;
TypeScript allows for type guards. If you check to see if the value is not null, then the error will not occur.
function startAnimation() {
var player = document.getElementById("home");
if (player !== null) {
// This side of the if-statement will never execute if player is null
player.animate(
[
{ transform: "scale(1)", opacity: 1, offset: 0 },
{ transform: "scale(.5)", opacity: 0.5, offset: 0.3 },
{ transform: "scale(.667)", opacity: 0.667, offset: 0.7875 },
{ transform: "scale(.6)", opacity: 0.6, offset: 1 }
],
{
duration: 700,
easing: "ease-in-out",
delay: 10,
iterations: Infinity,
direction: "alternate",
fill: "forwards"
}
);
}
}