The idea of the animation its to have a series of circles from big to small and from opaque to clear, that will “get closer” to the viewer, all the circles get rendered correctly but the animation its not apply in any of them and the circles just pop in to the next position without having a smooth transition.
This is the WaveCircle component:
import { useEffect, useState } from "react";
import { motion, animate, useMotionValue, useTransform, interpolate} from "framer-motion";
import PropTypes from "prop-types";
WaveCircles.propTypes = {
circles: PropTypes.oneOfType([
PropTypes.object,
PropTypes.arrayOf(PropTypes.object),
]).isRequired,
};
function WaveCircles({ circles }) {
const [indexOfCircles, setIndexOfCircles] = useState(0);
const progress = useMotionValue(0);
const getIndex = circles.length > 0 ? circles.map((_, i) => i) : [];
const circlesValues = useTransform(progress, getIndex, circles,
(a, b) => ({
cx: interpolate(a.cx, b.cx, progress),
cy: interpolate(a.cy, b.cy, progress),
r: interpolate(a.r, b.r, progress),
opacity: interpolate(a.opacity, b.opacity, progress),
})
);
useEffect(() => {
animate(progress, indexOfCircles, {
duration: 0.5,
ease: "easeInOut",
delay: 0.4,
onComplete: () => {
if (indexOfCircles === circles.length - 1) {
setIndexOfCircles(0);
progress.set(0);
} else {
setIndexOfCircles(indexOfCircles + 1);
}
},
});
}, [circles.length, circlesValues, indexOfCircles, progress]);
return (
<motion.circle
cx={circlesValues.current.cx}
cy={circlesValues.current.cy}
r={circlesValues.current.r}
opacity={circlesValues.current.opacity}
stroke="#6b97ff"
strokeWidth={16}
/>
);
}
export default WaveCircles;
I have an array of objects where the information of each circle is stored, I call the component for each circle (16) and with different positions.
And this is the main component where i call the WaveCircle
import "./hero.css";
import WaveCircles from "../../path/WaveCircle";
export default function Hero() {
return (
<div className="Hero_Container">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 800 800"
className="back_image"
>
<g fill="none">
<WaveCircles
circles={[
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
]}
/>
<WaveCircles
circles={[
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
]}
/>
<WaveCircles
circles={[
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
]}
/>
<WaveCircles
circles={[
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
]}
/>
<WaveCircles
circles={[
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
]}
/>
<WaveCircles
circles={[
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
]}
/>
<WaveCircles
circles={[
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
]}
/>
<WaveCircles
circles={[
{ cx: 447.083, cy: 287.917, r: 233.333, opacity: 0.592 },
{ cx: 437.667, cy: 310.333, r: 216.667, opacity: 0.673 },
{ cx: 428.25, cy: 332.75, r: 200, opacity: 0.755 },
{ cx: 418.833, cy: 355.167, r: 183.333, opacity: 0.837 },
{ cx: 409.417, cy: 377.583, r: 166.667, opacity: 0.918 },
{ cx: 400, cy: 400, r: 150, opacity: 1 },
{ cx: 513, cy: 131, r: 350, opacity: 0.02 },
{ cx: 503.583, cy: 153.417, r: 333.333, opacity: 0.102 },
{ cx: 494.167, cy: 175.833, r: 316.667, opacity: 0.183 },
{ cx: 484.75, cy: 198.25, r: 300, opacity: 0.265 },
{ cx: 475.333, cy: 220.667, r: 283.333, opacity: 0.347 },
{ cx: 465.917, cy: 243.083, r: 266.667, opacity: 0.428 },
{ cx: 456.5, cy: 265.5, r: 250, opacity: 0.51 },
]}
/>
</g>
</svg>
</div>
);
}
This is a short video of the issue: https://vimeo.com/950956125?share=copy
And this is other video but with paths looking smooth(Yes, it has a weird glitch, but the point is that is smooth) : https://vimeo.com/950956988?share=copy
This is the code of the paths:
import { useEffect, useRef, useState } from "react";
import { motion, animate, useMotionValue, useTransform } from "framer-motion";
import { interpolate } from "flubber";
import PropTypes from 'prop-types';
SVGMorph.propTypes = {
paths: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]).isRequired,
opacity: PropTypes.number
};
function SVGMorph({paths, opacity}) {
const onceEffect = useRef(false)
const [indexOfPath, setIndexOfPath] = useState(0)
const progress = useMotionValue(0)
const pathIndex = paths.length > 0 ? paths.map((_, i) => i) : []
const pathValue = useTransform(progress, pathIndex, paths, {
mixer: (a, b) => interpolate(a,b)
})
useEffect(()=>{
if(onceEffect.current){
animate(progress, indexOfPath, {
duration: 0.5,
ease: "easeInOut",
delay: 0.4,
onComplete: ()=>{
if(indexOfPath === paths.length - 1){
setIndexOfPath(0)
progress.set(0)
}else{
setIndexOfPath(indexOfPath + 1)
}
}
})
}
return () => onceEffect.current = true
},[indexOfPath, pathValue, paths.length, progress])
return(
<motion.path d={pathValue} opacity={opacity} />
)
}
export default SVGMorph
And how I call it:
{/* <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1422 800" className="back_image">
<defs>
<linearGradient id="a" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" stopColor="#989898" />
<stop offset="100%" stopColor="#3C3C6E" />
</linearGradient>
</defs>
<g fill="none" stroke="url(#a)" strokeLinecap="round" strokeWidth={2}>
<SVGMorph paths={["M0 572q355.5-392 711-172t711 172", "M0 884Q355.5-5 711 400t711 484", "M0 572q355.5-392 711-172t711 172"]} opacity={1}/>
<SVGMorph paths={["M0 550q355.5-370 711-150t711 150", "M0 850Q355.5-5 711 400t711 450", "M0 550q355.5-370 711-150t711 150"]} opacity={0.96}/>
</g>
</svg> */}
Repo for anyone that wanna try it out: https://github.com/Koppeks/template1
Try animate a circle with framer motion and doesn’t work as expected, jump between position with no animation