I am trying to implement a nice drag and drop on a canvas representing 3 discs.
I want to change the position of each mass with the mouse. My main problem is that the ax length for each of these three spheres limits me.
At the moment, I have implemented the following function when the mouse moves inside the canvas (the indexMass value indicates which mass moves: 1, 2 or 3 and t1, t2, t3 respectively correspond to the angle of mass 1, 2, 3 ):
// Happens when the mouse is moving inside the canvas function myMove(event) { if (isDrag) { var x = event.offsetX; var y = event.offsetY; if (indexMass == 1) { // Update theta1 value t1 = t1 + 0.1*Math.atan(y/x); } else if (indexMass == 2) { // Update theta2 value t2 = t2 + 0.1*Math.atan(y/x); } else if (indexMass == 3) { // Update theta3 value t3 = t3 + 0.1*Math.atan(y/x); } // Update drawing DrawPend(canvas); } }
As you can see, I did for each corner:
t = t + 0.1*Math.atan(y/x);
with:
var x = event.offsetX; var y = event.offsetY;
But this effect is not very pleasant. When the ball is selected with the mouse (with a mouse click), I would like the cursor to be attached to this sphere or sphere in order to follow the " delta " coordinates of the mouse when I am no longer on the sphere.
To summarize, I don’t know how to create a beautiful and user-friendly drag and drop, if someone can help me or give me some advice, that would be great.
thanks
UPDATE 1
@ Blindman67: thanks for your help, the code snippet is rather complicated for me, I didn’t understand all this. But I'm on the right track.
I start with the first problem: rotate the selected drive when the mouse remains very closed to it or above it when dragging.
At the moment, I have changed my myMove function (which is called when I click and drag the mouse to drag and drop), for example:
// Happens when the mouse is moving inside the canvas function myMove(event) { // If dragging if (isDrag) { // Compute dx and dy before calling DrawPend var lastX = parseInt(event.offsetX - mx); var lastY = parseInt(event.offsetY - my); var dx = lastX - window['x'+indexMass]; var dy = lastY - window['y'+indexMass]; // Change angle when dragging window['t'+indexMass] = Math.atan2(dy, dx); // Update drawing DrawPend(canvas); // Highlight dragging disk fillDisk(indexMass, 'pink'); } }
where indexMass is the index of the dragged disk, and window['x'+indexMass] , window['y'+indexMass] are the current coordinates of the selected disk center.
After that, I calculate dx, dy respectively, from the coordinates, by clicking the mouse when running drag ( mx, my , returned by the getMousePos function ), and the coordinates of the mouse with the move.
Finally, I change the angle of the disk to set, for the global variable (theta of the selected disk), ie window['t'+indexMass] :
// Change angle when dragging window['t'+indexMass] = Math.atan2(dy, dx);
I took your piece of code using Math.atan2 .
But the result of this function does not create a good drag and drop animation, I would like to know where this could have come from.
Right now I would like to implement only drag and drop without changing the axis length, I will see a later version for this function.
UPDATE 2
I keep looking for a solution to drag the selected mass with the mouse.
To try to synthesize what I did earlier, I think the following method is good, but this drag and drop method does not work very well: the selected drive does not match the mouse correctly , and I don’t know why.
In myMove function (function called when the drag myMove function ), I decided:
- Calculate dx, dy between the coordinates of the mouse and the selected coordinates of the disk, i.e.:
var dx = parseInt (event.offsetX - window ['x' + indexMass]);
var dy = parseInt (event.offsetY - window ['y' + indexMass]);
indexMass represents the index of the selected drive.
Increase the position of the selected disk (stored in temporary variables tmpX, tmpY ) by dx, dy .
Calculate the new angle theta (identified in the global variable code window['t'+indexMass]
Calculate the new positions of the selected disk with this new theta value, for example, using disk1 ( indexMass=1 and theta = t1 ):
x1= x0 +l1 * sin(t1) y1= y0 +l1 * sin(t1)
I have to make you notice that I want to drag with the mouse so as not to change the length of the axes with the mouse, this is a limitation.
Here's the whole myMove function (called when drag starts):
// Happens when the mouse is moving inside the canvas function myMove(event) { // If dragging if (isDrag) { console.log('offsetX', event.offsetX); console.log('offsetY', event.offsetY); var dx = parseInt(event.offsetX - window['x'+indexMass]); var dy = parseInt(event.offsetY - window['y'+indexMass]); console.log('dx', dx); console.log('dy', dy); // Temp variables var tmpX = window['x'+indexMass]; var tmpY = window['y'+indexMass]; // Increment temp positions tmpX += dx; tmpY += dy; // Compute new angle for indexMass window['t'+indexMass] = Math.atan2(tmpX, tmpY); console.log('printf', window['t'+indexMass]); // Compute new positions of disks dragComputePositions(); // Update drawing DrawPend(canvas); // Highlight dragging disk fillDisk(indexMass, 'pink'); } }
UPDATE 4 - Bounty:
The problem is solved! I forgot to consider the position of the "indexMass-1" drive to calculate the new angle using the Math.atan2 function.