没有JS库的画布上的HTML5拖放路径

时间:2013-09-23 07:46:08

标签: javascript html5 canvas html5-canvas

我想在HTML5画布上拖放路径。
如果我们点击形状,我没有发现任何类似SVG提供事件的事情 任何人都知道如何处理路径项上的事件?我想在没有任何java脚本库的情况下这样做。

以下是我当前绘制路径的代码:

var canvas = document.getElementById("html5Canvas");
var context = canvas.getContext("2d");
var drawing = false;

canvas.addEventListener("mousedown", startDraw, false);
canvas.addEventListener("mousemove", continueDraw, false);
canvas.addEventListener("mouseup", endDraw, false


function startDraw(event) 
{
    drawing = true;
    context.moveTo(event.clientX, event.clientY);    
}

function continueDraw(event) 
{
    if (drawing)
    {
        context.lineTo(event.clientX, event.clientY);    
        context.stroke();    
    }
}

function endDraw(event) 
{
    if (drawing)
    {
        context.lineTo(event.clientX, event.clientY);    
        context.stroke();    
        drawing = false;
    }
}

感谢。

1 个答案:

答案 0 :(得分:11)

制剂

为了检测线路点击,我们需要记录所有路径信息。

以下示例是原始帖子中提供的代码的修改版本,包括一个笔划记录器,用于记录每个笔划(鼠标向下和鼠标向下)到包含所有笔划的数组。

为简单起见,我们在改变模式时会听到鼠标点击。在单击模式下,我们迭代笔划集合并重新构建我们之前记录的路径,然后检查我们的鼠标位置是否在其中一行中。

在构建路径之前使用命中区域可以优化代码以减少开销,但为了演示,仅包含基本代码:

演示代码

<强> ONLINE DEMO HERE

要记录我们需要有一些东西来存储行/笔画:

var lines = [], line;

我们为切换模式时使用的点击添加事件监听器。请注意,通常您可能会分享mousedown / up事件:

canvas.addEventListener("click", checkLine, false);

为了使线条更“可点击”,我们在这里使用更粗的线宽(固定用于演示):

context.lineWidth = 3;

为了记录我们需要修改现有的回调。其中还有一个错误,导致每次鼠标移动时都会重新绘制线条,如果线条较长,最终会减慢绘图速度。

我们还需要调整鼠标位置,使其相对于画布:

function startDraw(event) {

    /// if we are in "click" mode exit from here (for demo)
    if (mode.checked === true) return;

    /// adjust mouse position
    var pos = mouseXY(canvas, event);

    drawing = true;

    /// start a new path
    context.beginPath();
    context.moveTo(pos.x, pos.y);

    /// create a new stroke and push first position to it
    line = [];
    line.push([pos.x, pos.y]);
}

对于我们绘制的每个部分,我们需要重置路径,因此我们不会重绘整行(在最终的渲染/重绘中,您当然只需要一次重绘一行,但不能在绘制时重绘):

function continueDraw(event) {
    if (drawing) {

        /// adjust mouse position
        var pos = mouseXY(canvas, event);

        /// complete one line segment started in mouse down
        context.lineTo(pos.x, pos.y);    
        context.stroke();

        /// reset path and start from where we ended this line
        context.beginPath();
        context.moveTo(pos.x, pos.y);

        /// store current point to stroke/line
        line.push([pos.x, pos.y]);
    }
}

最后当线完成时,我们存储我们的笔画:

function endDraw(event) {
    if (drawing)    {
        var pos = mouseXY(canvas, event);
        context.lineTo(pos.x, pos.y);    
        context.stroke();
        drawing = false;

        /// push stroke/line to line stack
        lines.push(line);
    }
}

我们用它来调整鼠标位置::

function mouseXY(c, e) {
    var r = c.getBoundingClientRect();
    return {x: e.clientX - r.left, y: e.clientY - r.top};
}

检查线路点击次数

要检查一行,我们需要遍历行集合并将每行重建为路径。没有必要绘制这些路径,所以速度还可以。重建路径时,我们使用isPointInStroke

检查调整后的鼠标位置
function checkLine(e) {
    if (mode.checked === false) return;

    var i = 0, line, l, p, pos = mouseXY(canvas, e);

    /// make sure stroke has same width as originally recorded        
    context.lineWidth = 3;

    /// loop through line collection
    for(; line = lines[i]; i++) {

        /// reset path
        context.beginPath();

        /// begin stroke
        context.moveTo(line[0][0], line[0][1]);

        /// iterate through each point stored
        for(l = 1; p = line[l]; l++) {
            /// add a line
            context.lineTo(p[0], p[1]);
        }

        /// then we check the point
        if (context.isPointInStroke(pos.x, pos.y) === true) {
            alert('hit line ' + i); /// show "ID" of line clicked
            return;
        }
    }
}

即使是复杂的重叠线也可以毫无问题地被检测到:

Demo snapshot

(是的,我知道!我可以在任何一天击败Dali和Munch!X-p)