Framer MotionでSVGにアニメーションを付ける
途中SVGRというSVGをTSXに変換するものを見つけた。これはこれで便利そうだが今回は使わなかった こちらはSVGをReactコンポーネントに変換してSVGの属性をpropsとして扱えるようにしてくれる
Framer Motionのコンポーネントに<motion.svg />や<motion.circle />といったものがあり、これによってFramer Motion側で用意されたアニメーション用の値をpropsで渡すことが出来る
motionコンポーネント群は通常のstringやnumberの他にMotionValue型の値を受け取る。この型はFramer Motionの用意しているHooksがよく返す型
MotionValue型は単なる値の他に加速度を持ったりするらしい
/imo-icon/hr.icon/imo-icon/hr-long.icon
フレームごとに値を更新
useAnimationFrame()を使う
code:sample.tsx
import {
motion,
useAnimationFrame,
useMotionValue,
} from 'framer-motion'
import { wrap } from '@motionone/utils'
export const MotionSample = () => {
const rotate = useMotionValue(0)
useAnimationFrame((time) => {
rotate.set(wrap(0, 360, time / -180))
})
return (
<motion.svg className="fixed top-10 right-0" width={200} height={200}>
<motion.rect
width={50}
height={50}
x={25}
y={25}
style={{ rotate }}
</motion.rect>
</motion.svg>
)
}
https://gyazo.com/285463b39c12fbf48db1bcde2924c782
Framer Motionの作例を見ていたらimport { wrap } from '@motionone/utils'というものを見つけたので使用
wrap(min:number, max:number, v:number)のような感じで値の範囲を作ってくれる
2023/03/08 普通にframer-motionからのインポートも出来た
上記の例だとCSSアニメーションでも出来るけど、違う変数の値を入れたりとかも出来る
…
スクロール量を取得して値を更新
useScroll()を使う
code:sample.tsx
import { motion, useScroll } from 'framer-motion'
export const MotionSample = () => {
const { scrollYProgress } = useScroll()
return (
<motion.svg className="fixed top-10 right-0" width={200} height={200}>
<motion.circle
cx={100}
cy={100}
r={50}
style={{ fill: 'none', stroke: 'black', pathLength: scrollYProgress }}
</motion.circle>
</motion.svg>
)
}
https://gyazo.com/095a89367fcfd16865449badb85121a3
useScroll()で取得できる値はscrollX/YとscrollX/YProgressの2種類がある
scrollX/YProgressは0から1の範囲の値を返す模様