I am making app with framer motion and I need to drag svg inside another svg but my problem is that viwebox size is not equal to window size so when I drag element my 1px movement of mouse on the screen is like 100 px. I know in JavaScript we can calculate x and y with screenX, sceenY and CTM (current transform matrix). Is possible to make somehow framer motion drag function to calculate that?
<svg viewBox="0 0 40 20">
<motion.circle drag cx="5" cy="5" r="0.5"strokeWidth="0.1"/>
</svg>
P.S. I cannot change viewbox size and its 100% of width and height of screen
this is current state of the app where you can see the problem when you try to drag player object. https://waterpolo.klaktech.com
CodePudding user response:
In Framer Motion, you can use the transformMatrix
property of the drag
gesture to get the current transform matrix of the element being dragged. You can then use this matrix to calculate the new position of the element based on the movement of the mouse cursor.
Here is an example of how you can use the transformMatrix
property to drag an element inside an SVG element with a viewBox:
import { motion, useTransform } from "framer-motion";
// Define the dimensions of the viewBox
const viewBoxWidth = 40;
const viewBoxHeight = 20;
// Create a ref to store the transform matrix of the element being dragged
const transformMatrix = useTransform(dragState.xy, (xy) => {
// Get the current transform matrix of the element
const matrix = drag.transformMatrix.current;
// Calculate the new x and y position of the element
const x = xy.x * matrix.a xy.y * matrix.c matrix.e;
const y = xy.x * matrix.b xy.y * matrix.d matrix.f;
// Return the new transform matrix
return `matrix(${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, ${x}, ${y})`;
});
return (
<svg viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}>
<motion.circle
drag
cx="5"
cy="5"
r="0.5"
strokeWidth="0.1"
style={{ transform: transformMatrix }}
/>
</svg>
);
In this example, the useTransform
hook is used to create a motion value that tracks the current position of the element being dragged. This motion value is then used to calculate the new position of the element based on the movement of the mouse cursor. The updated transform matrix is then applied to the element using the style
property of the motion.circle
component.
CodePudding user response:
It is possible to use the property in Framer Motion to calculate the movement of the SVG element relative to the viewbox。 To do this, you will need to use the property to define the bounds within which the element can be dragged。 You can then use the property to adjust the elasticity of the element's movement.dragdragConstraints
movement.dragElastic
Here is an example of how this could be implemented in your code:
<svg viewBox="0 0 40 20">
<motion.circle
drag
dragConstraints={{ left: 0, right: 40, top: 0, bottom: 20 }}
dragElastic={0.1}
cx="5"
cy="5"
r="0.5"
strokeWidth="0.1"
/>
</svg>
This will constrain the movement of the element to the bounds of the viewbox and give it some elasticity so that it bounces back when released。 <motion.circle>
Hope this helps!