canvas如何知道mousedown事件是否发生在我们想要的地方?

How to know whether the mousedown event is occured on where we want in canvas?

这里有一个与在 canvas 上移动元素相关的代码示例。 要将圆移动到 canvas 上的其他位置,下面的代码会检查圆元素本身是否触发了 mousedown 事件,以便可以使用 mousemove 启动进一步的拖动。但我不明白用于了解鼠标是否在正确的圆圈上双击以拖动它的逻辑。

// 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
        ........
    }
}

当用户在任何元素上按住鼠标控制(通过单击它)时,mousedown 事件发生,然后,当他试图拖动该元素时,mousemove 事件发生。但是,在让 mousemove 被触发之前,我们应该确定用户是否试图拖动正确的元素(此处画圈)。如果您看到上面的代码,if() 语句中的逻辑用于检查它。我无法理解这种逻辑,这就是问题所在。谢谢

解释您的代码正在测试什么。

您的这部分代码...

((dx * dx) + (dy * dy) < circleRadius * circleRadius)

...使用勾股定理数学测试鼠标是否在圆周内。

(dx * dx) + (dy * dy)测量圆心到鼠标的距离。它实际上测量的是中心点到鼠标距离的平方,但是由于 Math.sqrt 是一项昂贵的操作,我们只是将 鼠标距离的平方 圆半径进行比较平方。我们得到了相同的结果,但避免了昂贵的 Math.sqrt

这里有一个使用勾股定理确定距离的教程:

https://www.youtube.com/watch?v=We3LG8pK-LU


我们不能告诉为什么测试在没有看到更多代码的情况下完成。

但是,如果鼠标 在圆圈内 则可能是您确定用户打算拖动圆圈。

相反,如果鼠标 在圆圈外 ,则表明用户打算执行点击。


另一种点击与拖动测试:

这个替代测试很好,因为您可以让用户单击圆圈或拖动圆圈。此替代方案尝试 "read the intent" 用户。

  1. 在 mousedown 中,保存开始的 mouseX 和 mouseY 位置。

    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 ...
    }
    
  2. 在 mousemove 中,测试鼠标移动的总像素是否少于大约 5 个像素(或 10px 或其他)。

    • 如果移动 <5 像素,则不执行任何操作以预期这是一次点击。
    • 如果移动 >=5 像素,开始拖动操作。

      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 ...
      }
      
  3. 当 mouseup 发生时,我们可以读取 itIsADrag 标志来确定用户是单击还是拖动。

    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;
    }
    

示例代码和演示:

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>