在svg或画布中将文本包装为圆形
在网站上将文本拟合到一个圆,使其与圆的曲线而不是矩形边界框一起流动时,有什么好的解决方案 以下是我努力实现的目标: 页面上有许多黑色圆圈(大小固定),每个圆圈旁边都有一个文本区域。 当文本输入到文本区域时,它会出现在黑色圆圈中,位于两个轴的中心。 如果输入的文字太多,导致线条长度超过圆的半径,减去指定的边距值,线条将像常规换行一样断开,而文本块仍居中。 当然,靠近顶部或底部的线条要比靠近中间的线条短 文本将有一个固定的大小,当圆圈充满文本时,不应显示额外的内容(如溢出隐藏) 带有文字的黑色圆圈实际上是语音泡泡,用于打印并粘贴在海报上在svg或画布中将文本包装为圆形,svg,html5-canvas,Svg,Html5 Canvas,在网站上将文本拟合到一个圆,使其与圆的曲线而不是矩形边界框一起流动时,有什么好的解决方案 以下是我努力实现的目标: 页面上有许多黑色圆圈(大小固定),每个圆圈旁边都有一个文本区域。 当文本输入到文本区域时,它会出现在黑色圆圈中,位于两个轴的中心。 如果输入的文字太多,导致线条长度超过圆的半径,减去指定的边距值,线条将像常规换行一样断开,而文本块仍居中。 当然,靠近顶部或底部的线条要比靠近中间的线条短 文本将有一个固定的大小,当圆圈充满文本时,不应显示额外的内容(如溢出隐藏) 带有文字的黑色圆圈实
是否有任何出色的SVG/Canvas库支持此功能,或者我必须从头开始设计我们的方法?有一个建议的CSS功能调用“排除”,它可以使文本在定义的区域内流动: 这意味着SVG和画布路径可能被定义为容器,文本将在容器中流动/包装 我确实说过“提议”——这离在浏览器中成为现实还有一段距离 然而 您可以使用html画布相当轻松地将文本包装在圆圈内 沿圆向下移动时,任何行上显示文字的可用宽度都会发生变化 下面是如何确定圆上任何水平线的最大可用宽度
// 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));
通过测量文本的宽度,一次添加一个单词,直到用完该行的所有可用宽度,从而使文本适合该行
下面介绍如何使用画布测量使用当前上下文的任何文本。字体:
var width=ctx.measureText(“This is some test text.”).width;
剩下的只是将文本添加到每行中,直到达到最大线宽,然后开始新的一行
如果您喜欢SVG,可以使用element.getComputedTextLength方法在SVG中执行类似的操作
下面是代码和小提琴:
正文{背景色:象牙色;填充:20px;}
画布{边框:1px纯红;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var text=“'t圣诞节的前一天晚上,屋子里到处都是动静,连一只老鼠都没有,于是圣诞节的故事就开始了”;
var font=“12pt verdana”;
var textHeight=15;
var lineHeight=textHeight+5;
var行=[];
var-cx=150;
var-cy=150;
var r=100;
initLines();
wrapText();
ctx.beginPath();
弧(cx,cy,r,0,数学π*2,假);
ctx.closePath();
ctx.strokeStyle=“天蓝色”;
ctx.线宽=2;
ctx.stroke();
//预先计算圆的每个水平弦的宽度
//这是文本允许的最大宽度
函数initLines(){
对于(变量y=r*.90;y>-r;y-=线宽){
var h=数学绝对值(r-y);
如果(y线高度10){
push({y:y,maxLength:length});
}
}
}
//在圆的每一行上绘制文本
函数wrapText(){
var i=0;
var words=text.split(“”);
while(i0){
行=行[i++];
var lineData=calcalowablewords(line.maxLength,words);
ctx.fillText(lineData.text,cx-lineData.width/2,cy line.y+textHeight);
字拼接(0,lineData.count);
};
}
//计算一行可以容纳多少个单词
函数CalcalowableWords(最大宽度,字数){
var-wordCount=0;
var testLine=“”;
var=”;
var fittedWidth=0;
var fittedText=“”;
字体=字体;
对于(var i=0;imaxWidth){
返回({
伯爵:我,
宽度:安装宽度,
文本:fittedText
});
}
fittedWidth=宽度;
fittettext=测试线;
}
}
}); // end$(函数(){});
将文本包装并剪裁在圆内
到目前为止,您尝试了什么?请分享你有问题的代码。我已经做了一系列不同的实验,问题不在于代码本身,而在于方法。一个没有包装的相当粗糙的版本,需要将HTML元素覆盖在一个黑色圆圈的PNG上,并用标记替换textarea中的换行符。这是一个服务性的问题,但不是很优雅,因为它没有包装成非矩形的元素,而是依靠用户来破坏文本。几个小时前发布了一个类似的问题:()也许会有一些有趣的答案。是的,我读到了关于排除的内容,但一个只在启用了实验标志的金丝雀身上起作用的解决方案并没有完全解决这个问题。上面的代码给了我一些可以使用的东西。如果没有足够的文字填充圆圈,我会做一些调整,使文字始终垂直居中。@Lowkey我在找同样的东西。你是否设法使它始终垂直居中?
<!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>