准备工作
为了检测行点击,我们需要记录所有路径信息。
以下示例是原始帖子中提供的代码的修改版本,包括一个笔画记录器,它将每个笔画(在鼠标按下和鼠标按下之间)记录到一个包含所有笔画的数组中。
为简单起见,当我们更改模式时,我们会在此处收听鼠标点击。在单击模式下,我们迭代笔画集合并重新构建我们之前记录的路径,然后检查我们的鼠标位置是否在这些行之一中。
可以通过在构建路径之前使用命中区域来优化代码以减少开销,但为了演示,仅包含基本代码:
演示代码
在线演示在这里
要记录我们需要有一些东西来存储线条/笔划:
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;
        }
    }
}
甚至可以毫无问题地检测到复杂的重叠线:

(是的,我知道!我可以随时击败 Dali 和 Munch!Xp )