几年前,我为APNGedit制作了一个Javascript脚本来绘制Laughing Man徽标。它使用了现已解散的mozTextAlongPath
我最近重新发现了这个脚本,并使用翻译,旋转和fillText()重新编写它。但是,这不会影响字符宽度,也不会被调整(看起来很糟糕)。
原作大约2009年(不完美,但没关系):
当前版本:
如何在HTML5画布上以弧形绘制文字并使其看起来不错?
解决方案代码基于Kolink的回答:
ctx.fillStyle = primaryColor;
ctx.font = fontSize + 'px ' + fontFamily;
var textWidth = ctx.measureText(text).width,
charRotation = 0,
character, charWidth, nextChar, nextWidth, bothWidth, kern, extraRotation, charSegment;
for (var i=0, l=text.length; i<l; i++) {
character = nextChar || text[i];
charWidth = nextWidth || ctx.measureText(character).width;
// Rotate so the letter base makes a circle segment instead of a tangent
extraRotation = (Math.PI/2) - Math.acos((charWidth/2) / radius);
ctx.save();
ctx.translate(radius, h/2);
ctx.rotate(charRotation);
ctx.translate(0, -textRadius);
ctx.rotate(extraRotation);
ctx.fillText(character,0,0);
ctx.restore();
nextChar = text[i+1] || '';
nextWidth = ctx.measureText(nextChar).width;
bothWidth = ctx.measureText(character+nextChar).width;
kern = bothWidth - charWidth - nextWidth;
charSegment = (charWidth+kern) / textWidth; // percent of total text size this takes up
charRotation += charSegment * (Math.PI*2);
}
答案 0 :(得分:1)
显然,在圆弧上放置字母并不困难(只需将中心底部对准圆圈)。但是,正如您所指出的,问题是字距调整。
幸运的是,我们有measureText()
,它可以告诉我们字母的宽度,以及使用什么字距。
圆圈的周长只是2πr
,文字的总宽度为ctx.measureText("Your text here");
。获得这两个值的比率,你会发现你需要多少空间或压缩你的单词。
您可能希望将间距修改器应用于整个单词,而不是单个字母。要执行此操作,请在句子上使用measureText()
并删除空格以获取字母的宽度(以及扩展名为空格的总宽度)。
现在你需要绘制每个单词的位置。再次使用measureText()
查找每个单词的宽度并在圆上绘制其中心点,在每个单词之间添加一部分总空间值。现在在每个单独的字母上使用measureText()
并在正确的位置绘制它以获得完美的字距调整。
一切顺利,你应该有一个完美间隔的文字圈。
答案 1 :(得分:0)
因此衡量文本是好的,我最终做的是Math.pow(measureText + measureTextOfLastChar, 3 / 4)
由于某种原因,当前和前一个字符的宽度之和的平方根使得一些间距太粗,并且根本没有平方根,也使它变坏,但是Math.pow(sum,3/4) )由于某种原因创造了一个很大的比例。下面是代码(在coffeescript中)
CanvasRenderingContext2D::fillTextCircle = (str, centerX, centerY, radius, angle) ->
len = str.length
s = undefined
@save()
@translate centerX, centerY
@rotate - (1 + 1 / len) * angle / 2
n = 0
prevWidth = 0
while n < len
thisWidth = @measureText(str[n]).width
@rotate angle / len * Math.pow(thisWidth + prevWidth, 3 / 4) / @measureText(str).width
s = str[n]
prevWidth = @measureText(str[n]).width
@fillText s, -@measureText(str[n]).width / 2, -1 * radius
n++
@restore()
然后使用
调用它context.fillTextCircle('hiya world', halfWidth, halfHeight, 95, 26)
我猜测并检查了一下,虽然我接受了计算4,所以我下意识地知道我在做什么。无论如何,它产生了完美的字符间距,没有Math.pow(sum_character_widths,3/4)
除了在循环中保留Math.pow(总和,3/4)之外,所有内容都可以更改,因为这是我在网上找到的其他内容所做的更好的部分。