2012-12-12 2 views
0

몇 년 전 APNGedit에서 Laughing Man 로고를 그리는 자바 스크립트를 만들었습니다. 그것은 현재 사용되지 않았습니다. mozTextAlongPath잘 보이는 'arcing text?

최근에이 스크립트를 재발견하고 번역, 회전 및 fillText()를 사용하여 다시 작성했습니다. 그러나 이것은 글자 폭을 고려하지 않으며 커닝되지 않습니다 (끔찍한 것처럼 보입니다).

원래 년경 2009

(완벽하지만 괜찮되지 않음) :

original laughing man using mozTextAlongPath

현재 버전 :

new version using 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); 
} 

fixed

+0

여기에서 언급 한 바와 같이 raphael.js를 살펴보십시오. http://stackoverflow.com/questions/2612764/attach-text-on-path-in-raphael – DhruvPathak

답변

1

, 그것은 아크 자체에 문자를 배치 할 어려움이 없다 (다만 원을 중심 바닥을 맞 춥니 다). 그러나 언급 한대로 문제는 커닝입니다.

운 좋게도 우리는 문자의 너비를 알려줄 수있는 measureText()을 가지고 있습니다.

원의 둘레는 간단하게 2πr이고 텍스트의 전체 너비는 ctx.measureText("Your text here");입니다. 이 두 가지 값의 비율을 알아 내면 단어 사이의 간격을 좁히거나 스쿼시해야하는 양을 알 수 있습니다.

개별 문자가 아닌 단어 전체에 간격 지정자를 적용하고 싶을 것입니다. 이렇게하려면 글자의 너비 (그리고 공백의 총 너비를 확장자)를 얻기 위해 공백을 제거한 문장에 measureText()을 사용하십시오.

이제 각 단어의 위치를 ​​계획해야합니다. measureText()을 다시 사용하여 각 단어의 너비를 찾고 서클에서 그 중심점을 그려 보면서 각 단어 사이에 전체 공간 값의 일부를 추가하십시오. 이제 각각의 문자에 measureText()을 사용하고 완벽한 커닝을 얻으려면 올바른 위치에 그립니다.

모두 잘되어있어 완벽하게 간격을 둔 텍스트 원이 있어야합니다.

+0

char로 char을 처리하는 것이 더 좋습니다. 두 가지 방법을 시도했다. 내 테스트에서 실제로 사용하고 있던 캐릭터 중 커닝이 없었고 폭이 가변적이었습니다. "AVA"를 추가하고 현재 및 다음 문자를 측정 한 다음 겹침을 처리하여 커닝이 작동하도록했습니다. 어떤 시점에서 전체 솔루션을 게시하고 'measureText()'및 비율이 내가 필요한 것 때문에 지금 답변을 받아 들일 것입니다. :) – Annan

0

그래서 어떤 이유로 Math.pow(measureText + measureTextOfLastChar, 3/4)

했다, 내가하고 결국 무엇을, 텍스트가 좋은 측정, 현재 및 이전 문자의 폭의 합계의 제곱근은 약간의 간격이 너무 마른 체형 만든 사각형없이 근본적으로 나쁘기는하지만 Math.pow (합계, 3/4)는 어떤 이유로 든 큰 비율을 만듭니다. 내가 CALC 4를했다하지만 Heres는 (커피 스크립트에서) 코드는

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, [email protected](str[n]).width/2, -1 * radius 
    n++ 
    @restore() 

는 내가 무의식적으로 내가 무엇을하고 있었는지 알고, 내가 추측하고 비트를 확인했다

context.fillTextCircle('hiya world', halfWidth, halfHeight, 95, 26) 

사용하여 호출합니다.어쨌든 Math.pow (sum_character_widths, 3/4) 없이는 얻을 수없는 완벽한 문자 간격을 만듭니다.

Math.pow (sum, 3/4)를 루프에 유지하는 것 외에는 모든 것을 변경할 수 있습니다 , 그 부분은 내가 온라인에서 찾은 나머지 것들보다 훨씬 좋았 기 때문이다.