在svg或canvas中将文本换行为圆形 [英] Wrap text to a circle shape in svg or canvas

查看:88
本文介绍了在svg或canvas中将文本换行为圆形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将文本拟合到网站上的圆圈会有什么好的解决方案,所以它会与圆形曲线一起流动,而不是矩形边界框?



这是我想要实现的目标:
页面上有许多黑色圆圈(固定大小),每个圆圈旁边都有一个textarea。
当文本输入到textarea时,它出现在黑色圆圈中,它以两个轴为中心。
如果输入这么多的文本,那条线变得比圆的半径长,减去一个指定的边距值,那么这条线就会像你想象的那样在常规包装中断开,文本块仍然居中。
靠近顶部或底部的线条当然会比靠近中间的线条短。



文本将具有固定的大小,当圆圈时填充了文字,不应显示额外的内容(如隐藏溢出)。



带文字的黑色圆圈实际上是气泡,打算打印



任何一个出色的SVG / Canvas库都支持这个吗?还是我必须从头开始计算我们的方法?

解决方案

有一个建议的CSS功能调用exclusions,可以在定义的区域内传输文本: / p>

 <!doctype html> 
< html lang =en>
< head>

< style>
body {background-color:ivory;填充:20像素; }
canvas {border:1px solid red;}
< / style>
< script src =http://code.jquery.com/jquery-1.9.1.js>< / script>

< script>

$(function(){

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

var text ='圣诞节前一天晚上,在整个房子里,没有一个生物在搅动,甚至没有鼠标。所以圣诞节的故事开始了;
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();


//预先计算每个水平和弦的宽度circle
//这是文本允许的最大宽度

函数initLines(){

for(var y = r * 0.90; Y'GT; -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});
}

}
}


//在圆圈的每一行上绘制文字

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

}


//计算一行中适合的单词数

函数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;

}

}


}); // end $(function(){});

< / script>
< / head>
< body>
< p>文字包裹并剪裁在圆圈内< / p>
< canvas id =canvaswidth = 300 height = 300>< / canvas>
< / body>
< / html>


What would be a good solution for fitting text to a circle on a website, so it flows with the curves of the circle, instead of a rectangular bounding box?

Here's what I'm trying to achieve: There are a number of black circles (of a fixed size) on a page, with a textarea next to each of them. When text is entered into the textarea, it appears in the black circle, where it is centered on both axes. If so much text is entered that line becomes longer than the radius of the circle, minus a specified value for margin, the line will break like you would expect from regular wrapping, with the block of text still being centered. Lines nearer the top or bottom will, of course, be shorter than the ones near the middle.

The text will have a fixed size and when the circle is filled with text, the extra content should not be shown (like overflow hidden).

The black circles with the text are really speech bubbles, which are meant to be printed and glued onto a poster.

Do any of the fantastic SVG/Canvas libraries support this or will I have to figure our a method from scratch?

解决方案

There is a proposed CSS feature call "exclusions" that would make it possible to flow text inside defined areas: http://www.w3.org/TR/css3-exclusions/

This means that SVG and Canvas paths would likely be defined as containers and text would flow/wrap inside the containers.

I did say "proposed" -- it's a ways off from being a reality in browsers.

However...

You can fairly easily wrap text inside a circle using html canvas

The width available to display text on any line changes as you move down the circle.

Here’s how to determine the maximum available width of any horizontal line on a circle

// var r is the radius of the circle
// var h is the distance from the top of the circle to the horizontal line you’ll put text on

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

You fit text to the line by measuring the width of text—adding one word at a time, until you’ve used up all the available width of that line.

Here’s how to use canvas to measure any text using the current context.font:

var width=ctx.measureText("This is some test text.").width;

The rest is just adding text to each line up to the maximum line width and then starting a new line.

If you prefer SVG, you can do similar in SVG using the element.getComputedTextLength method for text metrics.

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/upq6L/

<!doctype html>
<html lang="en">
<head>

  <style>
      body{ background-color: ivory; padding:20px; }
      canvas{ border:1px solid red;}
  </style>
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>

  <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.  And so begins the story of the day of Christmas";
      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;

          }

      }


  });   // end $(function(){});

  </script>
</head>
<body>
    <p>Text wrapped and clipped inside a circle</p>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

这篇关于在svg或canvas中将文本换行为圆形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆