Some Examples » 14. Drag: 3D transform
14. Drag: 3D transform
This example also uses useTransform()
to transform the drag distance to other values (like the one on the previous page). Here, the x
and y
positions are converted into rotateX
and rotateY
values.
This box is made draggable in all directions but has drag constraints that make it bounce back when you release it. In addition, its drag elastic is set a bit higher than the default so you can drag it further.
Here, we’re tracking both its x
and y
and changing them to 3D rotation values.
- When you drag the box left or right (changing its
x
), you change itsrotateY
(the axis that runs from top to bottom). - And when you drag it up or down (
y
), you change itsrotateX
(the horizontal axis).
Code component
export default function CC_14_Drag_3D_transform(props) {
const x = useMotionValue(0)
const y = useMotionValue(0)
const rotateX = useTransform(y, [-100, 100], [60, -60])
const rotateY = useTransform(x, [-100, 100], [-60, 60])
return (
<div>
<div
style={{
width: 100,
height: 100,
borderRadius: "50%",
background: `radial-gradient(rgba(255,255,255,0),
rgba(255,255,255,0.3))`
perspective: 800,
}}
>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
backgroundColor: "#fff",
left: -25,
top: -25,
position: "relative",
x,
y,
rotateX,
rotateY,
cursor: "grab",
}}
drag
dragConstraints={{ top: 0, right: 0, bottom: 0, left: 0 }}
dragElastic={0.6}
whileTap={{ cursor: "grabbing" }}
/>
</div>
</div>
)
}
Code overrides
export function Drag_3D_transform(Component): ComponentType {
return (props) => {
const { style, ...rest } = props
const x = useMotionValue(0)
const y = useMotionValue(0)
const rotateX = useTransform(y, [-100, 100], [60, -60])
const rotateY = useTransform(x, [-100, 100], [-60, 60])
return (
<Component
{...rest}
drag
dragConstraints={{ top: 0, right: 0, bottom: 0, left: 0 }}
dragElastic={0.6}
style={{ ...style, x, y, rotateX, rotateY }}
/>
)
}
}
Without a CSS perspective
value, you wouldn’t see any 3D effect, so the box’s parent layer (that unassuming small circle in the back) has this code override.
export function Circle(Component): ComponentType {
return (props) => {
const { style, ...rest } = props
return <Component {...rest} style={{ ...style, perspective: 800 }} />
}
}