SVG의 textPath 요소에 텍스트 균등 배치 정보

18564 단어 HTML5SVG
SVG에서 경로상의 문자의 균등 배치를 브라우저(Win10의 Firefox, Chrome, Edge)에 관계없이 실현하는 방법에 대해 조사했습니다.

SVG에서는 text 요소에 textLength 속성을 설정하여 문자 간격을 조정할 수 있습니다.
textLength 의 값은 텍스트의 폭을 나타내고 텍스트가 거기에 맞추어 자동적으로 배치되기 때문에… … 아마.
<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg">
      <text x="0" y="20">
         This is a pen.
      </text>
      <text x="0" y="60" textLength="300">
         This is a pen.
      </text>
</svg>



text 요소는 textPath 요소와 결합하여 경로를 따라 텍스트를 배치 할 수 있습니다.
<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg">
        <path d="M 30 160 Q 150 0 300 160" stroke="black" fill="none" id="path1"></path>
        <text>
        <textPath href="#path1">This is a pen.</textPath>
        </text>
</svg>



이 주제는 경로를 사용할 때 문자 간격을 조정하는 방법입니다.
보통으로 생각해 text 요소의 textLength 속성을 사용하면 좋다고 생각하지만, 무려 textPath 요소에도 textLength가 있다.
어느 쪽을 사용하면 좋을지 모르겠다.
몰라서 시험해 보았다.
<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg" style="font-family: Times New Roman;font-size: 14px;">
      <g>
        <path d="M 30 160 Q 150 0 300 160" stroke="black" fill="none" id="path1"></path>
        <text>
        <textPath href="#path1">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 200 Q 150 40 300 200" stroke="black" fill="none" id="path2"></path>
        <text textLength="300">
        <textPath href="#path2">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 240 Q 150 80 300 240" stroke="black" fill="none" id="path3"></path>
        <text>
        <textPath href="#path3" textLength="300">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 280 Q 150 120  300 280" stroke="black" fill="none" id="path4"></path>
        <text textLength="300">
        <textPath href="#path4" textLength="300">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 320 Q 150 160  300 320" stroke="black" fill="none" id="path5"></path>
        <text textLength="150">
        <textPath href="#path5" textLength="300">This is a pen.</textPath>
        </text>
      </g>
</svg>



실행 결과

Firefox에서는 text 요소의 textLength 속성의 값이 사용된다.
Chrome에서는 textPath 요소의 textLength 속성의 값이 사용된다.
그래서 Firefox와 Chrome에서 외형을 맞추고 싶다면 두 속성에 같은 값을 설정하면 좋을 것 같다.

문제는 Edge이다. 어느 쪽의 값도 사용되지 않는지 무엇 하나 외형이 변하지 않는다. 동기가 느껴지지 않는다.
3개의 브라우저 사이에서 외형을 가지려면 textLength에서는 안 된다.
원래 SVG에 자세하지 않기 때문에 패스상의 균등 배치에 textLength를 사용하는 것이 진정한 방법인지도 모른다.

textLength 이외에도 문자간의 간격을 설정하는 방법이 있다.
그것은 text 요소의 letter-spacing 속성. 이름 그대로 문자간의 간격치를 나타내고 있다.
균등 배치가 목적이기 때문에 먼저 이쪽을 시도하면 좋았다…
<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg" style="font-family: Times New Roman;font-size: 14px;">
      <g>
        <path d="M 30 160 Q 150 0 300 160" stroke="black" fill="none" id="path1"></path>
        <text letter-spacing="20">
        <textPath href="#path1">This is a pen.</textPath>
        </text>
      </g>
</svg>



저기를 세우면 이쪽이 서지 않고. 사이좋게 할 생각이 없는 세 사람이다.
그렇다면 textLength와 조합해 보자.
<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg" style="font-family: Times New Roman;font-size: 14px;">
      <g>
        <path d="M 30 160 Q 150 0 300 160" stroke="black" fill="none" id="path1"></path>
        <text letter-spacing="20">
        <textPath href="#path1">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 200 Q 150 40 300 200" stroke="black" fill="none" id="path2"></path>
        <text textLength="150" letter-spacing="20">
        <textPath href="#path2">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 240 Q 150 80 300 240" stroke="black" fill="none" id="path3"></path>
        <text letter-spacing="20">
        <textPath href="#path3" textLength="250">This is a pen.</textPath>
        </text>
      </g>
      <g>
        <path d="M 30 280 Q 150 120  300 280" stroke="black" fill="none" id="path4"></path>
        <text textLength="150" letter-spacing="20">
        <textPath href="#path4" textLength="250">This is a pen.</textPath>
        </text>
      </g>
</svg>



실행 결과

대답이 보였다. 각 브라우저에서의 속성의 채용 규칙은 다음과 같이 된다고 생각된다.
(◎: 최우선, ○: 우선, ×: 사용되지 않음)
- Firefox : ○text.textLength ×textPath.textLength ×text.letter-spacing
- Chrome : ×text.textLength ◎textPath.textLength ○text.letter-spacing
- Edge : ×text.textLength ×textPath.textLength ○text.letter-spacing

간단히 말해서, 그려야 할 문자열의 간격이 w이고 그 간격으로 그릴 때 문자열의 폭이 y이면
text 요소와 textPath 요소의 textLength 속성에 y를, text 요소의 letter-spacing 속성에 w를 설정하면
3개의 브라우저상에서 외형이 갖추어져야 한다.

이번은 y=300에 고정하고 있지만, 그 경우의 w는 무엇일까?
조금 움직여 보았는데, letter-spacing이 설정되어 있지 않을 때는 letter-spacing=0이 되는 것 같다.
그렇다면 letter-spacing 및 textLength 속성이 설정되지 않은 경우 문자열의 너비를 계산할 수 있다면
y와의 차이로부터 w의 값을 계산할 수 있을 것 같다.
다음 코드는 X를 계산하는 코드입니다.
const textLength = 300;
const svgText = document.getElementById('text1');
const svgTextPath = document.getElementById('textPath1');

//letter-spacing=0のときのテキストの幅
const box = svgText.getBBox();
//元々のテキストの幅とtextLengthのギャップ
const diff = textLength - box.width;
//テキストの長さ
const number = svgTextPath.textContent.length;
//文字間の隙間の数はテキスト長-1だからギャップ/テキスト長-1で割れば大丈夫だろう…
const w = diff / (number - 1);

//Edge用属性
svgText.setAttribute("letter-spacing", `${w}`);
//Firefox用属性
svgText.setAttribute("textLength", `${textLength}`);
//Chrome用属性
svgTextPath.setAttribute("textLength", `${textLength}`);



실행 결과

좋은 느낌으로 외형이 갖추어졌다. Firefox와 Chrome에서 조금 어긋난다고 생각하지 말라.
그렇다고 해도 2018년도 되어 이런 사양의 차이에 사고팔고하는 것은 어떤 것일까?
어쩌면 더 간단하고 합당한 방법이 있을지도. 아니, 원해.
이상입니다.

좋은 웹페이지 즐겨찾기