framer-motion
Version:
A simple and powerful JavaScript animation library
64 lines (62 loc) • 2.16 kB
JavaScript
/**
* Creates a `transformPagePoint` function that accounts for SVG viewBox scaling.
*
* When dragging SVG elements inside an SVG with a viewBox that differs from
* the rendered dimensions (e.g., `viewBox="0 0 100 100"` but rendered at 500x500 pixels),
* pointer coordinates need to be transformed to match the SVG's coordinate system.
*
* @example
* ```jsx
* function App() {
* const svgRef = useRef<SVGSVGElement>(null)
*
* return (
* <MotionConfig transformPagePoint={transformViewBoxPoint(svgRef)}>
* <svg ref={svgRef} viewBox="0 0 100 100" width={500} height={500}>
* <motion.rect drag width={10} height={10} />
* </svg>
* </MotionConfig>
* )
* }
* ```
*
* @param svgRef - A React ref to the SVG element
* @returns A transformPagePoint function for use with MotionConfig
*
* @public
*/
function transformViewBoxPoint(svgRef) {
return (point) => {
const svg = svgRef.current;
if (!svg) {
return point;
}
// Get the viewBox attribute
const viewBox = svg.viewBox?.baseVal;
if (!viewBox || (viewBox.width === 0 && viewBox.height === 0)) {
// No viewBox or empty viewBox - no transformation needed
return point;
}
// Get the rendered dimensions of the SVG
const bbox = svg.getBoundingClientRect();
if (bbox.width === 0 || bbox.height === 0) {
return point;
}
// Calculate scale factors
const scaleX = viewBox.width / bbox.width;
const scaleY = viewBox.height / bbox.height;
// Get the SVG's position on the page
const svgX = bbox.left + window.scrollX;
const svgY = bbox.top + window.scrollY;
// Transform the point:
// 1. Calculate position relative to SVG
// 2. Scale by viewBox/viewport ratio
// 3. Add back the SVG position (but in SVG coordinates)
return {
x: (point.x - svgX) * scaleX + svgX,
y: (point.y - svgY) * scaleY + svgY,
};
};
}
export { transformViewBoxPoint };
//# sourceMappingURL=transform-viewbox-point.mjs.map