检测 html 5 画布上的点击与拖动

mar*_* sz 2 html javascript canvas mouseevent

我正在尝试用 HTML 5 画布编写一个简单的地图。拖动鼠标移动地图,然后单击选择最近的航点。但是,有一个问题。当我拖动鼠标时,当我释放它时仍然得到click事件。我想只有在点击时没有移动时才能得到它。

我试图在mousemove事件处理程序中检查无移动事件,但没有成功:

function onMove(e) {
    if(e.movementX == 0 && e.movementY == 0) {
        console.log("a"); //never happens...
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:有没有简单的方法可以做到,或者我应该检查新闻发布会和发布活动是否在同一个地方?

这是我的代码:

function onMove(e) {
    console.log("moving");
}

function onClick(e) {
    console.log("clicked");
}

function init() {
    c = document.getElementById("MapCanvas");
    ctx = c.getContext("2d");
    c.addEventListener("click", onClick, true);
    c.addEventListener("mousemove", onMove, true);
}
Run Code Online (Sandbox Code Playgroud)

小智 6

这是解决此问题的一种方法:

因为我们需要知道两个状态,所以我们需要两个标志(有些人更喜欢对象 - 这取决于你):

var isDown = false;    // mouse button is held down
var isMoving = false;  // we're moving (dragging)
Run Code Online (Sandbox Code Playgroud)

然后我们需要找到一种方法来区分拖动和点击。一个典型的方法是在第一个点击点到当前点之间使用半径(长度):如果在外面,我们认为它是一个拖动操作。

所以 -

var radius = 9 * 9     // radius in pixels, 9 squared
var firstPos;          // keep track of first position
Run Code Online (Sandbox Code Playgroud)

(我们对 9 进行平方,所以我们以后不必为每个鼠标移动事件计算平方根)。

然后我们可以定义我们的回调处理程序来考虑这些事情:

canvas.onmousedown = function(e) {
  firstPos = getXY(e); // record click position (see getXY function in demo)
  isDown = true;       // record mouse state
  isMoving = false;    // reset move state
};
Run Code Online (Sandbox Code Playgroud)

下一个处理程序可以设置在window对象上,而不是画布元素本身。这允许我们在按住鼠标按钮的同时移动到画布元素之外。我们需要在addEventListener()这里使用,以便我们也允许其他代码订阅:

window.addEventListener("mousemove", function(e) {
  if (!isDown) return; // we will only act if mouse button is down
  var pos = getXY(e);  // get current mouse position

  // calculate distance from click point to current point
  var dx = firstPos.x - pos.x,
      dy = firstPos.y - pos.y,
      dist = dx * dx + dy * dy;        // skip square-root (see above)

  if (dist >= radius) isMoving = true; // 10-4 we're on the move

  if (isMoving) {
    // handle move operation here
  }
});
Run Code Online (Sandbox Code Playgroud)

最后,我们检测点击以及更新鼠标状态,还有window对象上的:

window.addEventListener("mouseup", function(e) {
  if (!isDown) return;   // no need for us in this case
  isDown = false;        // record mouse state

  if (!isMoving) {
    // it was a click, handle click operation here
  }
});
Run Code Online (Sandbox Code Playgroud)

然后最后的问题是点击航点。进行绝对检查(即 x === 值)很少会成功,因为我们需要将鼠标按钮准确放置在该点上。允许使用航点的宽度和高度的范围(假设航点有一个对象wp):

if (pos.x >= wp.x && pos.x < wp.x + wp.width && 
    pos.y >= wp.y && pos.y < wp.y + wp.height) { ... }
Run Code Online (Sandbox Code Playgroud)

例子

var isDown = false;    // mouse button is held down
var isMoving = false;  // we're moving (dragging)
Run Code Online (Sandbox Code Playgroud)
var radius = 9 * 9     // radius in pixels, 9 squared
var firstPos;          // keep track of first position
Run Code Online (Sandbox Code Playgroud)
canvas.onmousedown = function(e) {
  firstPos = getXY(e); // record click position (see getXY function in demo)
  isDown = true;       // record mouse state
  isMoving = false;    // reset move state
};
Run Code Online (Sandbox Code Playgroud)