2
votes

Input:

Some text that contain regular words and special words/char separated with #. Font and fontSize is constant, lets say Arial 14 without any styling. For example:

Lorem ipsum dolor #sit# amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore #et# dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis #aute# irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur #sint# occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Output:

When user clicks #someSeparatedWord# i need to log that word in console (in my example user could click 'sit', 'et', 'aute', 'sint' and it would log only this words). So the problem is in how to get or calculate this word/char canvas coordinates?

1

1 Answers

3
votes

Your # delmiters can't recognize a word because context.fillText paints words on the canvas.

Those words become an unrecognizable part of the canvas bitmap.

What your will have to do is use context.measureText to map the bounding box of every word.

enter image description here

Then you can test a clicked mouseX/mouseY position against those bounding boxes.

Here's example code and a Demo: http://jsfiddle.net/m1erickson/c9nQj/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>
<script>
$(function(){

    $results=$("#results");

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

    var text="Lorem ipsum dolor #sit# amet, consectetur adipisicing elit";

    var words=text.split(" ");
    var wordsBB=new Array(words.length);

    ctx.font="14px arial";

    var length=ctx.measureText(words[0]).width;

    wordsBB[0]={
        x:0,
        y:0,
        width:length,
        height:16
    }

    var accumLength=length;

    for(var i=1;i<words.length;i++){
        var length=ctx.measureText(" "+words[i]).width;
        wordsBB[i]={
            x:accumLength,
            y:0,
            width:length,
            height:16
        }
        accumLength+=length;
    }

    ctx.fillText(text,0,15);
    ctx.lineWidth=0.50;

    for(var i=0;i<words.length;i++){
        var bb=wordsBB[i];
        ctx.strokeRect(bb.x,bb.y,bb.width,bb.height);
    }


    function handleMouseMove(e){
      e.preventDefault();
      var x=parseInt(e.clientX-offsetX);
      var y=parseInt(e.clientY-offsetY);

      $results.text("---");
      for(var i=0;i<wordsBB.length;i++){
          var bb=wordsBB[i];
          if(x>bb.x && x<bb.x+bb.width && y>bb.y & y<bb.y+bb.height){
              $results.text(words[i]);
          }
      }

    }

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


}); // end $(function(){});
</script>
</head>
<body>
    <p>Hover over a word.</p>
    <h2 id="results">---</h2>
    <canvas id="canvas" width=400 height=50></canvas>
</body>
</html>

This Demo uses html canvas. For kineticJS you can do these bounding-box calculations on an off-screen canvas and then use those boundings boxes on your Kinetic.Text node.

Also note that you must do the bounding box calculations line-by-line because the boxes y-coordinate will be different on line1 vs line2, etc.