useTransform
Create a new motion value that transforms the output of one or more other motion values.
useTransform
creates a MotionValue
that takes the output of one or more other MotionValue
s and changes it some way.
#Usage
Import from Framer Motion.
import { useTransform } from "framer-motion"
#Transform function
useTransform
can accept a function which returns a new value.
const x = useMotionValue(1)const y = useMotionValue(1)
const z = useTransform(() => x.get() + y.get()) // 2
Any MotionValue
s read in this function via the get()
method will be subscribed to automatically. If these MotionValue
s change, the function will be run on the following frame to calculate a new value.
import { frame } from "framer-motion"
const x = useMotionValue(1)const y = useMotionValue(1)
const z = useTransform(() => x.get() + y.get()) // 2
x.set(2)
frame.render(() => console.log(z.get())) // 3
#Mapping
useTransform
can also map a motion value from one range of values to another.
To illustrate, look at this x
motion value:
const x = useMotionValue(0)
We can use useTransform
to create a new motion value called opacity
. By defining an input range and an output range we can say, "when x
is 0
, opacity
should be 1
. When x
is 100
, opacity
should be 0."
const opacity = useTransform( x, // Map x from these values: [0, 100], // Into these values: [1, 0])
Now, if x
gets set to 50
, opacity
will be 0.5
.
Both ranges must always be the same length.
The input range must always be a linear series of numbers, either counting up or counting down.
The output range must all be of the same type, but can be any type supported by Framer Motion, for instance numbers, colors, shadows etc.
const backgroundColor = useTransform( x, [0, 100], ["#f00", "#00f"])
It's possible to provide more than two values to each range. For instance, with the following mapping, we fade opacity
out whenever x
goes outside of the 0-100
range.
const opacity = useTransform( x, [-100, 0, 100, 200], [0, 1, 1, 0])
By setting clamp: false
, the ranges will map perpetually. For instance, in this example we're saying "for every 100px scrolled, rotate another 360deg":
const { scrollY } = useScroll()const rotate = useTransform( scrollY, [0, 100], [0, 360], { clamp: false })
#Options
When passing ranges, we can also pass an object of options as the final argument.
useTransform(value, input, output, options)
#clamp: boolean
Default: true
If true
, will clamp output to within the provided range. If false
, will carry on mapping even when the input falls outside the provided range.
const y = useTransform(x, [0, 1], [0, 2])const z = useTransform(x, [0, 1], [0, 2], { clamp: false })
useEffect(() => { x.set(2) console.log(y.get()) // 2, input clamped console.log(z.get()) // 4})
#ease: EasingFunction | EasingFunction[]
An easing function, or list of easing functions, to use to ease the mixing between each value in the provided ranges.
These must be JavaScript functions. All named easings can be imported from "framer-motion"
:
import { cubicBezier, circOut } from "framer-motion"
// In your componentconst y = useTransform(x, [0, 1], [0, 2], { ease: circOut })
const z = useTransform( x, [0, 1], [0, 2], { ease: cubicBezier(0.17, 0.67, 0.83, 0.67) })
#mixer: (from: T, to: T) => (p: number) => any
A function to use to mix between each set of output value.
This can be used to inject more advanced mixers than Framer Motion's default, for instance Flubber for morphing SVG paths.
from
and to
will be each set of values, for instance given an output range ["#000", "#f00", "#333"]
two mixers will be created, one between "#000"
and "#f00"
and one between "#f00"
and "#333"
.
p
is an eased progress value between 0
and 1
that defines how much we should mix between from
and to
.