HTML5 Canvas:在画布外拖动

时间:2013-01-14 15:24:14

标签: html5 canvas

我在使用HTML5 Canvas实现拖动功能时遇到问题。我理解缺少场景图等,并设置了一种方法来识别在鼠标事件上拖动矩形。

然而:当鼠标离开Canvas时,问题是丢失鼠标事件。如果我拖动画布外面并释放鼠标按钮,我的代码不会得到一个mouseup事件来相应地改变拖动逻辑。然后拖动的对象仍然粘在我的鼠标上,直到我再次开始拖动。

fabric.js doesn't have this problem,但我无法识别库中的相关代码。它是如何做到的?

2 个答案:

答案 0 :(得分:3)

首先使用布尔变量isMouseDragged,它在mouseDown后设置为true,在mouseUp之后设置为false(或者我将在稍后解释的其他事件)

您可以通过多种方式处理。

if (mouse['isMouseDragged']) {
   mouse['xUp'] = e.clientX - canvas.getBoundingClientRect().left;
   mouse['yUp'] = e.clientY - canvas.getBoundingClientRect().top;
   ...
  1. 在鼠标向上计算您按下和释放按钮的点之间的交点(将其想象为线)和画布边缘之外的鼠标指针(将其想象为另一条线)。将mouseUp位置作为这两行的交集。

    // FIRST OPTION
    if (mouse['mode'] == mouse['INTERSECTION']) {
        if (!mouse['isMouseOver']) {
            var edgeIntersect = mouseDraggedOut(mouse['xDown'], mouse['yDown'], mouse['xUp'], mouse['yUp']);
            mouse['xUp'] = edgeIntersect['x'];
            mouse['yUp'] = edgeIntersect['y'];
        }
    }
    
  2. 将虚拟鼠标指针(坐标)保持在画布内。

    // SECOND OPTION
    if (!mouse['isMouseOver']) {
        if (mouse['mode'] == mouse['LOCK_INSIDE']) {
            var edgeIntersect = mouseDraggedOut(canvas.width / 2, canvas.height / 2, mouse['x'], mouse['y']);
            mouse['x'] = edgeIntersect['x'];
            mouse['y'] = edgeIntersect['y'];
        }
    }
    
  3. 当您离开画布并将isMouseDragged设为false时,在onMouseUp = onMouseOut上设置坐标。

    // THIRD OPTION
    if (mouse['isMouseDragged']) {
       if (mouse['mode'] == mouse['MOUSEOUT_POS']) {
          mouse['xUp'] = mouse['xOut'];
          mouse['yUp'] = mouse['yOut'];
          mouse['isMouseDragged'] = false;
       }
    }
    
  4. 计算画布边缘的相交:

    function mouseDraggedOut(x1, y1, x2, y2) {
    // x1,y1 = mouseDown;  x2,y2 = mouseUp
    
    var x3, y3, x4, y4;
    var thisX, thisY;
    
    if (x2 < 0) {// left edge
        x3 = 0;
        y3 = 0;
        x4 = 0;
        y4 = canvas.height;
        thisX = Math.round(x1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (x2 - x1));
        thisY = Math.round(y1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (y2 - y1));
    
        // I must do this for other checks, else corners (when two conditions are true) couldn't be handled
        // So I'll handle it one after another
        x2 = thisX;
        y2 = thisY;
    }
    
    if (x2 > canvas.width - 1) {// right edge
        x3 = canvas.width - 1;
        y3 = 0;
        x4 = canvas.width - 1;
        y4 = canvas.height - 1;
        thisX = Math.round(x1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (x2 - x1));
        thisY = Math.round(y1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (y2 - y1));
        x2 = thisX;
        y2 = thisY;
    }
    
    if (y2 < 0) {// top edge
        x3 = 0;
        y3 = 0;
        x4 = canvas.width - 1;
        y4 = 0;
        thisX = Math.round(x1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (x2 - x1));
        thisY = Math.round(y1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (y2 - y1));
        x2 = thisX;
        y2 = thisY;
    }
    
    if (y2 > canvas.height - 1) {// bottom edge
        x3 = 0;
        y3 = canvas.height - 1;
        x4 = canvas.width - 1;
        y4 = canvas.height - 1;
        thisX = Math.round(x1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (x2 - x1));
        thisY = Math.round(y1 + (((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))) * (y2 - y1));
    }
    
    return {
        'x' : thisX,
        'y' : thisY
    };
    

    }

    查看源代码:http://jsfiddle.net/WolfeSVK/s2tNr/

答案 1 :(得分:0)

解决方案是附加到mouseleave事件,而不再考虑用于拖动的按钮在逻辑内停止。