Kineticjs文本圈内

时间:2014-02-13 02:11:01

标签: canvas kineticjs

我希望将文字放在一个圆圈内,并将文字包含在内,如下所示:

enter image description here

我所能做的就是将文本放在里面,但它保留了一个方形容器,而不是一个圆圈。

Demo

1 个答案:

答案 0 :(得分:1)

在圈内包装文字

圆形和弦是一个线段,其端点位于圆上。

enter image description here

要在圆圈内水平放置文字,您需要计算该圆圈中水平和弦的宽度。

// r == the circle radius
// h == the vertical distance of the horizontal chord from the top of the circle

var chordWidth = 2*Math.sqrt(h*(2*r-h));

使用context.measureText:

计算任何文本使用的宽度
var textWidth = context.measureText("Measure this text").width;

通过这些计算,您可以将文字“自动换行”到每个和弦上。

您可以通过向文本行添加单词来执行此操作,直到累积的文本短语宽于和弦宽度。然后用超出和弦宽度的单词开始下一行文本。

这是代码和演示:http://jsfiddle.net/m1erickson/jcb3D/

enter image description here

<!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(){

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");

    var text = "'Twas the night before Christmas, when all through the house,  Not a creature was stirring, not even a mouse.";
    var font = "12pt verdana";
    var textHeight = 15;
    var lineHeight = textHeight + 5;
    var lines = [];

    var cx = 150;
    var cy = 150;
    var r = 100;

    initLines();

    wrapText();

    ctx.beginPath();
    ctx.arc(cx, cy, r, 0, Math.PI * 2, false);
    ctx.closePath();
    ctx.strokeStyle = "skyblue";
    ctx.lineWidth = 2;
    ctx.stroke();


    // pre-calculate width of each horizontal chord of the circle
    // This is the max width allowed for text

    function initLines() {

        for (var y = r * .90; y > -r; y -= lineHeight) {

            var h = Math.abs(r - y);

            if (y - lineHeight < 0) {
                h += 20;
            }

            var length = 2 * Math.sqrt(h * (2 * r - h));

            if (length && length > 10) {
                lines.push({
                    y: y,
                    maxLength: length
                });
            }

        }
    }


  // draw text on each line of the circle

  function wrapText(){

      var i=0;
      var words=text.split(" ");

      while(i<lines.length && words.length>0){

          line=lines[i++];

          var lineData=calcAllowableWords(line.maxLength,words);

          ctx.fillText(lineData.text, cx-lineData.width/2, cy-line.y+textHeight);

          words.splice(0,lineData.count);
      };

  }


  // calculate how many words will fit on a line

  function calcAllowableWords(maxWidth,words){

      var wordCount=0;
      var testLine="";
      var spacer="";
      var fittedWidth=0;
      var fittedText="";

      ctx.font=font;

      for(var i=0;i<words.length; i++){

          testLine+=spacer+words[i];
          spacer=" ";

          var width=ctx.measureText(testLine).width;

          if(width>maxWidth){ 
              return({
                  count:i, 
                  width:fittedWidth, 
                  text:fittedText
              }); 
          }

          fittedWidth=width;
          fittedText=testLine;
      }

      // always return the last set of words
      return({
          count:words.length,
          width:width,
          text:testLine,
      });
  }

}); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>