Html5 canvas 针对文本形状的命中测试

Html5 canvas 针对文本形状的命中测试,html5-canvas,raphael,paperjs,Html5 Canvas,Raphael,Paperjs,我想知道给定的点是在文本形状的内部还是外部。正如您在下面提供的示例中所注意到的那样,hitTest将在点位于TextItem的边界内时返回true,而不仅仅是在点位于字符本身内时。(当将鼠标指针放在中< < /代码>)时,您可以体验到这种行为最好。 我还尝试了基于路径绘制角色(正如Raphaël在其中所做的那样),以使用路径本身进行命中测试,但偶然发现了一些非常奇怪的行为,其中(某些)角色绘制不正确。(如果将路径定义复制到矢量图像软件(如Inkscape)中,则正确绘制文本形状) 确定给定点

我想知道给定的点是在文本形状的内部还是外部。正如您在下面提供的示例中所注意到的那样,
hitTest
将在点位于
TextItem
的边界内时返回
true
,而不仅仅是在点位于字符本身内时。(当将鼠标指针放在<代码>中< < /代码>)

时,您可以体验到这种行为最好。

我还尝试了基于路径绘制角色(正如Raphaël在其中所做的那样),以使用路径本身进行命中测试,但偶然发现了一些非常奇怪的行为,其中(某些)角色绘制不正确。(如果将路径定义复制到矢量图像软件(如
Inkscape
)中,则正确绘制文本形状)


确定给定点位于文本形状内部还是外部的最有希望的方法是什么

你可以点击测试一个文本形状(或任何其他数学上不规则的形状),方法是输入鼠标下的像素是否透明

您可以使用以下方法获取整个画布的像素阵列:

var data=context.getImageData(0,0,canvas.width,canvas.height).data;
然后,您可以在鼠标下获取像素的不透明度(alpha)值,如下所示:

var pixelIsTransparent = data[(mouseY*canvas.width+mouseX)*4+3]==0
如果像素不是透明的,那么就覆盖了文本形状

如果画布上有其他非文本图形,那么这些非文本图形可能会为命中测试提供误报。解决方法是使用第二个内存画布(仅包含文本形状),然后对第二个画布上的像素进行命中测试

下面是示例代码和演示:

var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var cw=画布宽度;
var ch=画布高度;
var$canvas=$(“#canvas”);
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
ctx.strokeStyle='gray';
ctx.font='300px verdana';
var-wasHit=false;
var isHit=假;
draw();
var data=ctx.getImageData(0,0,canvas.width,canvas.height);
$(“#canvas”).mousemove(函数(e){handleMouseMove(e);});
函数绘图(){
ctx.fillStyle=(isHit)?“绿色”:“浅灰色”;
ctx.fillText(“M”,25250);
ctx.strokeText(“M”,25250);
}
功能手柄移动(e){
e、 预防默认值();
e、 停止传播();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(例如clientY-offsetY);
isHit=(数据[(鼠标*cw+mouseX)*4+3]>10)
如果(!isHit==wasHit){
draw();
wasHit=isHit;
}
}
body{背景色:象牙;}
#画布{边框:1px纯红;}

点击测试:将鼠标移到字母上


在花了相当长的时间调试
paper.js
code之后,我终于找到了这个问题的解决方案

您应该使用
CompoundPath
,而不是使用
Path

复合路径包含两个或多个路径,在路径重叠处绘制孔。复合路径中的所有路径采用最后面路径的样式,可以通过其item.children列表进行访问

我还更新了上面的示例:


我猜可能路径显示错误,因为我认为canvas尚未正确支持SVG中的fillRule。不过我可能错了。你需要使用画布吗?听起来SVG可能更适合(或者两者都适合)?我还使用了一个例子,在
Raphaël
中使用了完全相同的cufon字体,并按照预期呈现了字体。一般来说,我愿意使用其他方法,不幸的是,使用svg进行命中测试的结果完全相同:针对路径的命中测试在svg中工作:-这将是一个可能的解决方案,虽然这是一个很好的解决方法…基本上我想知道你是否可以在画布上覆盖SVG,用于上面的文本,用于需要精细控制路径的位。错过了前面的评论。在Raph/svg中,不确定为什么要添加一个框并在其上放置mousemove。为什么不让mousemove只出现在路径上?