如何选择HTML5画布形状?

3
我有一个HTML5画布,在上面绘制了几个形状。
我想要的是,当鼠标点击任何形状时,该形状应该被选中(至少能告诉选中的是哪种形状)。
谢谢。

1
你可以使用像 fabric.js 这样的画布库来实现。 - kangax
3个回答

6
尝试使用现有的画布库(或创建自己的库),该库具有在选择形状时触发事件的功能。

下面的示例使用Kinetic JS库,而示例来自HTML5 Canvas区域事件示例:
var triangle = new Kinetic.Shape(function(){
    var context = this.getContext();
    context.beginPath();
    context.lineWidth = 4;
    context.strokeStyle = "black";
    context.fillStyle = "#00D2FF";
    context.moveTo(120, 50);
    context.lineTo(250, 80);
    context.lineTo(150, 170);
    context.closePath();
    context.fill();
    context.stroke();
});

triangle.on("mouseout", function(){
    writeMessage(messageLayer, "Mouseout triangle");
});

triangle.on("mousemove", function(){
    var mousePos = stage.getMousePosition();
    var x = mousePos.x - 120;
    var y = mousePos.y - 50;
    writeMessage(messageLayer, "x: " + x + ", y: " + y);
});

shapesLayer.add(triangle);

var circle = new Kinetic.Shape(function(){
    var canvas = this.getCanvas();
    var context = this.getContext();
    context.beginPath();
    context.arc(380, canvas.height / 2, 70, 0, Math.PI * 2, true);
    context.fillStyle = "red";
    context.fill();
    context.lineWidth = 4;
    context.stroke();
});

circle.on("mouseover", function(){
    writeMessage(messageLayer, "Mouseover circle");
});
circle.on("mouseout", function(){
    writeMessage(messageLayer, "Mouseout circle");
});
circle.on("mousedown", function(){
    writeMessage(messageLayer, "Mousedown circle");
});
circle.on("mouseup", function(){
    writeMessage(messageLayer, "Mouseup circle");
});

shapesLayer.add(circle);

stage.add(shapesLayer);
stage.add(messageLayer);


此外,我还添加了一些鼠标悬停检测,如果光标在形状内部且不使用任何JavaScript库。

基于矩形的鼠标悬停检测:

function isCursorWithinRectangle(x, y, width, height, mouseX, mouseY) {
    if(mouseX > x && mouseX < x + width && mouseY > y && mouseY < y + height) {
        return true;
    }
    return false;
}


基于圆形的鼠标悬停检测:

function isCursorWithinCircle(x, y, r, mouseX, mouseY) {
    var distSqr = Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2);

    if(distSqr < r * r) {
        return true;
    }
    return false;
}

4

有一种非常简单的方法可以使用像素精度选择复杂形状,而不涉及边界矩形或数学计算。

这个想法是将所有形状都复制到一个隐藏的次要画布上,并为每个形状分配一个唯一的颜色。当您在原始画布上执行mouseover或click事件时,您将保存与可见画布相关的鼠标(x,y)坐标,然后使用相同的坐标查找隐藏画布上的像素颜色。因为每个形状在隐藏画布上具有唯一的颜色,该颜色对应于用户选择的确切形状。

请注意,这仅支持大约1670万个形状,因为RGB只有24位颜色,但这应该足够了。

以下是一个使用D3和Canvas的简单示例:http://bl.ocks.org/syntagmatic/6645345


还有一个 alpha 通道,我们可以从中获得约 4b 种不同的颜色。 - N1gthm4r3
可以和不可以。如果你绘制重叠的对象,就不能使用 alpha 通道,因为 RGBA 颜色会混合在一起。 - geofflee
更新:我已经使用这种方法一段时间了,我注意到如果鼠标在形状的边缘上,那么它的颜色将与形状的颜色不同,然后其他对象将被选中。但是,我使用的距离为4,对我来说似乎还可以。但是在未来,我认为我必须创建一些距离函数来消除错误选择。 - N1gthm4r3
问题是由于抗锯齿。据我所知,您不能真正禁用抗锯齿,因此没有简单的解决方案。https://dev59.com/TnVC5IYBdhLWcg3wvT_g - geofflee

3
<代码>

Canvas没有像DOM那样的界面来处理其上的元素。它只用于绘图。

您需要将资产创建为对象,并使用绘图循环来绘制它们。然后您就可以忘记canvas元素,可以与对象一起工作,包括它们的偏移量等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接