几年前,我为APNGedit制作了一个Javascript脚本,用于绘制笑人标识。它使用了现已失效的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);
}

发布于 2012-12-12 06:40:25
显然,在圆弧上放置字母并不困难(只需将中心底部与圆圈对齐)。然而,正如您所指出的,问题在于解决问题。
幸运的是,我们有了measureText(),它可以告诉我们字母的宽度,因此可以使用什么内核。
圆周仅为2πr,文本的总宽度为ctx.measureText("Your text here");。得到这两个值的比率,你会发现你需要多少空间或挤在一起你的话。
您可能希望将空格修饰符应用于整个单词,而不是单个字母。要做到这一点,在句子中使用measureText(),去掉空格以获得字母的宽度(扩展为空格的总宽度)。
现在你需要画出每个单词的去向。再次使用measureText()查找每个单词的宽度,并在您的圆圈上绘制它的中心点,在每个单词之间添加一部分总空格值。现在,在每个字母上使用measureText(),并在正确的位置绘制它,以获得完美的角化。
一切都很好,你应该有一个完美的圆圈的文本。
发布于 2013-03-08 21:06:35
所以测量文本是好的,我最后做的,是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)我只是在猜测和检查一下,虽然我服用了calc 4,所以我下意识地知道自己在做什么。无论如何,它会产生完美的字符间距,如果没有Math.pow,就无法获得这种间距(sum_character_widths,3/4)。
除了将Math.pow(和,3/4)保存在循环中之外,一切都可以更改,因为这是我在网上找到的其他内容中更好的部分。
https://stackoverflow.com/questions/13834099
复制相似问题