Reputation: 10204
I'm having trouble animating the SVG Transform string using framer-motion. I tried animating it in the usual (manual) way
import { type FC, useRef, useEffect } from "react"
import { animate } from "motion" // formerly framer-motion
const MyComponent:FC<{initialTransform:string, finalTransform:string}> =
({initialTransform, finalTransform}) => {
const ref = useRef()
useEffect(() => {
animate(ref,
{transform:finalTransform},
// for visibility into what might be going wrong...
{update: (transform) => console.log({transform})})
},[])
return <g ref={ref} transform={initialTransform} >
{... lots of SVG things...}
</g>
}
but (1) the g element's transform attribute is never updated and (2) the update callback is only called with the initial and final transform and isn't tweened the way numbers and css values (like "20px"
) would be.
Upvotes: -1
Views: 42
Reputation: 10204
In the end, I used an SVG transform parser library (that I wrote many years ago) to convert the transform strings to objects that could be tweened with framer-motions's mix
function, like so:
import { type FC, useRef, useEffect } from "react"
import { animate, mix } from "motion" // formerly framer-motion
import { transform as ya_transform } from "ya-svg-transform"
const MyComponent:FC<{initialTransform:string, finalTransform:string}> =
({initialTransform, finalTransform}) => {
const ref = useRef()
useEffect(() => {
const mixer = mix(
// could also use .transforms instead of .matrix
// if you're confident the transform string will
// always contain the same kinds and ordering of
// transforms
ya_transform(initialTransform).matrix,
ya_transform(finalTransform).matrix,
)
animate(0,1,
{update: (n) => {
ref.current?.setAttribute("transform", ya_transform(mixer(n)).render())
})
},[])
return <g ref={ref} transform={initialTransform} >
{... lots of SVG things...}
</g>
}
// and later...
<MyComponent
initialTransform="translate(50,300) skewX(19.8)"
finalTransform="scale(5) rotate(30)"
/>
Upvotes: 0