Reputation: 229
Here I have a code sample related to moving an element on canvas. To move a circle to an other position on canvas, the below code is checking whether the mousedown event got triggered on the circle element itself or not so that further dragging can be initiated using mousemove. But I dont understand the logic that's been used to know whether or not the mouse is doubleclicked on the correct circle to drag it.
// start dragging
function DragStart(e) {
//coordinates of mouse from mousedown event e{x,y}
e = MousePos(e);
var dx, dy;
//initialCirclePosition is the centre (x,y) of the circle
dx = initialCiclePosition.x - e.x;
dy = initialCiclePosition.y - e.y;
if ((dx * dx) + (dy * dy) < circleRadius * circleRadius) {
//Yes, user is trying to move the circle only
........
}
}
When user holds the mouse control on any element(by clicking on it), mousedown event occurs, Then, when he tries to drag the element, mousemove event occurs. But, before letting mousemove gets triggered, we should find whether or not the user is trying to drag the right element (circle here). If you see the code above, the logic in if() statement was used to check that. I am unable to understand that logic and that's the question is about. Thanks.
Upvotes: 1
Views: 287
Reputation: 105015
An explanation of what your code is testing.
This part of your code...
((dx * dx) + (dy * dy) < circleRadius * circleRadius)
...uses the Pythagorean Theorem to mathematically test if the mouse is inside the circumference of a circle.
(dx * dx) + (dy * dy)
measures the distance between the circle centerpoint and the mouse. It actually measures the centerpoint-to-mouse distance squared, but since Math.sqrt
is an expensive operation, we just compare the mouse distance squared to the circle radius squared. We get the same result but avoid the expensive Math.sqrt
.
Here's a tutorial on determining distances using the Pythagorean Theorem:
https://www.youtube.com/watch?v=We3LG8pK-LU
We can't tell why the test is being done without seeing more of your code.
But, but presumably if the mouse is inside the circle you are deciding that the user intends to drag the circle.
And conversely if the mouse is outside the circle you are deciding that the user intends to execute a click.
An alternative click vs drag test:
This alternative test is nice because you can let the use either click in the circle or drag the circle. This alternative tries to "read the intent" of the user.
In mousedown, save the starting mouseX & mouseY position.
var isDown,startX,startY,itIsADrag;
function handleMouseDown(e){
// save the mouse position at mousedown
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// initially set the "itIsADrag" flag to false
itIsADrag=false;
// set the "isDown" flag to true
isDown=true;
... any other code ...
}
In mousemove, test if the mouse has moved less than about 5 total pixels (or 10px or whatever).
If moved >=5 pixels start a drag operation.
function handleMouseMove(e){
// return if the mouse is not down
if(!isDown){return;}
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// do nothing if the mouse has moved less than 5 total pixels since mousedown
if(!itIsADrag && Math.abs(mouseX-startX)+Math.abs(mouseY-startY)<5){return;}
// Set the dragging flag to true
// This flag prevents the Math.abs test above if we know we're dragging
itIsADrag=true;
// start a drag operation
... do drag stuff ...
}
By the time mouseup occurs, we can just read our itIsADrag
flag to determine if the user clicked or dragged.
function handleMouseUp(e){
if(itIsADrag){
console.log("You have been dragging");
}else{
console.log("You've did a click");
}
// clean up by clearing the isDown flag
isDown=false;
}
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
var isDown=false;
var isDown,startX,startY,itIsADrag;
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// save the mouse position at mousedown
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// initially set the "itIsADrag" flag to false
itIsADrag=false;
// set the "isDown" flag to true
isDown=true;
}
function handleMouseUp(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// report if this was a click or a drag
if(itIsADrag){
alert("You have been dragging");
}else{
alert("You've did a click");
}
// clean up by clearing the isDown flag
isDown=false;
}
function handleMouseOut(e){
// clean up by clearing the isDown flag
isDown=false;
}
function handleMouseMove(e){
// return if the mouse is not down
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// do nothing if the mouse has moved less than 5 total pixels since mousedown
if(!itIsADrag && Math.abs(mouseX-startX)+Math.abs(mouseY-startY)<5){return;}
// Set the dragging flag to true
// This flag prevents the Math.abs test above if we know we're dragging
itIsADrag=true;
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click or drag in the canvas.</h4>
<canvas id="canvas" width=300 height=300></canvas>
Upvotes: 1