针对文本形状进行测试

时间:2014-10-15 06:30:21

标签: html5-canvas raphael paperjs

我想知道给定点是在文本形状的内部还是外部。正如您在下面提供的示例中所注意到的那样,hitTest只要该点位于true的边界内,就会返回TextItem,而不仅仅是在角色本身里面。 (当您将鼠标指针放在#

的中间时,您可以最好地体验这种行为

Sample: Hit-testing against TextItem

我也尝试根据路径绘制角色(正如Raphaël在他们的font samples中所做的那样)使用路径本身进行命中测试,但偶然发现一些奇怪的行为,其中(某些)角色没有正确绘制。 (如果将路径定义复制到像Inkscape这样的矢量图像软件中,则可以正确绘制文本形状)

Sample: Drawing text as path

找出给定点是在文本形状内部还是外部的最有希望的方法是什么?

2 个答案:

答案 0 :(得分:0)

您可以通过发短信来判断鼠标下方的像素是否透明,从而对文本形状(或任何其他数学上不规则的形状)进行测试。

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

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=canvas.width;
var ch=canvas.height;
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=false;

draw();

var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;

$("#canvas").mousemove(function(e){handleMouseMove(e);});


function draw(){
  ctx.fillStyle=(isHit)?'green':'lightgray';
  ctx.fillText("M",25,250);
  ctx.strokeText("M",25,250);
}


function handleMouseMove(e){
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  isHit=(data[(mouseY*cw+mouseX)*4+3]>10)
  if(!isHit==wasHit){
    draw();
    wasHit=isHit;
  }
}

body{ background-color: ivory; }
#canvas{border:1px solid red;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p>Hit test: Move mouse over letter</p>
<canvas id="canvas" width=300 height=300></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

花了很长时间调试paper.js代码后,我终于找到了解决这个问题的方法。

您应该使用Path

,而不是使用CompoundPath
  

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

我还更新了上面的例子:

http://jsfiddle.net/64v7s6L9/1/