0

数年前、私はAPNGedit用のJavascriptスクリプトを作成して、LaughingManのロゴを描画しました。現在は機能していないmozTextAlongPathを使用しました

最近、このスクリプトを再発見し、translations、rotations、fillText()を使用して再作成しました。ただし、これは文字幅を尊重せず、カーニングもされません(ひどいように見えます)。

2009年頃のオリジナル(完璧ではありませんが、大丈夫です):

mozTextAlongPathを使用して元の笑い男

現行版:

fillTextを使用した新しいバージョン

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

修繕

4

2 に答える 2

1

明らかに、円弧自体に文字を配置することは難しくありません(中央の下部を円に揃えるだけです)。ただし、ご指摘のとおり、問題はカーニングです。

幸いなことmeasureText()に、文字の幅、つまりどのカーニングを使用するかを教えてくれるがあります。

円の円周は単純2πrで、テキストの全幅はですctx.measureText("Your text here");。これらの2つの値の比率を取得すると、単語の間隔を空けるか、押しつぶすために必要な量がわかります。

おそらく、個々の文字ではなく、単語全体に間隔修飾子を適用することをお勧めします。これを行うmeasureText()には、スペースを取り除いた文で使用して、文字の幅(さらにはスペースの合計幅)を取得します。

次に、各単語がどこに行くかをプロットする必要があります。もう一度使用measureText()して、各単語の幅を見つけ、その中心点を円上にプロットし、各単語間の合計スペース値の一部を追加します。measureText()次に、個々の文字に使用し、適切な場所に描画して、完璧なカーニングを取得します。

すべてが順調であるため、完全に間隔を空けたテキストの円が必要です。

于 2012-12-12T06:40:25.700 に答える
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)

少し推測して確認していましたが、calc 4を取ったので、無意識のうちに自分が何をしているのかわかりました。とにかく、それはあなたがMath.pow(sum_character_widths、3/4)なしでは得ることができなかった完璧な文字間隔を生み出します

Math.pow(sum、3/4)をループに保持することを除いて、すべてを変更できます。これは、オンラインで見つけた他の部分よりも優れた部分だからです。

于 2013-03-08T21:06:35.357 に答える