Skip to content Skip to sidebar Skip to footer

Hit Testing Against Text Shapes

I want to know whether a given point is inside or outside of a text shape. As you will notice in the sample I provided below, hitTest will return true as soon as the point is insid

Solution 1:

You can hit-test a text shape (or any other mathematically irregular shape) by texting whether the pixel under the mouse is transparent or not.

You can get the pixel-array for the entire canvas using:

vardata=context.getImageData(0,0,canvas.width,canvas.height).data;

Then you can fetch the opacity (alpha) value for the pixel under the mouse like this:

var pixelIsTransparent = data[(mouseY*canvas.width+mouseX)*4+3]==0

If the pixel is not transparent then you're over the text shape.

If you have other non-text drawings on the canvas then those non-text drawings might give false-positives for your hit-tests. A workaround for that is to use a second in-memory canvas containing only your text-shape and then do hit testing against the pixels on that second canvas.

Here's example code and a Demo:

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);});


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


functionhandleMouseMove(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;}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><p>Hit test: Move mouse over letter</p><canvasid="canvas"width=300height=300></canvas>

Solution 2:

After spending quite some time debugging paper.js code I finally found the solution for this problem.

Instead of using Path you are supposed to use CompoundPath:

A compound path contains two or more paths, holes are drawn where the paths overlap. All the paths in a compound path take on the style of the backmost path and can be accessed through its item.children list.

I also updated the example from above:

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

Post a Comment for "Hit Testing Against Text Shapes"