SVG 텍스트의 자동 줄 바꿈


108

HTML 텍스트가 요소를 채우는 것과 같은 방식으로 <text>컨테이너에 자동 줄 바꿈되는 내용을 SVG 에 표시하고 싶습니다 . 그것을 할 방법이 있습니까? 나는 s 를 사용하여 선을 아껴두고 싶지 않습니다 .<rect><div><tspan>

답변:


89

텍스트 래핑은 현재 구현 된 사양 인 SVG1.1의 일부가 아닙니다. <foreignObject/>요소 를 통해 HTML을 사용해야합니다 .

<svg ...>

<switch>
<foreignObject x="20" y="90" width="150" height="200">
<p xmlns="http://www.w3.org/1999/xhtml">Text goes here</p>
</foreignObject>

<text x="20" y="20">Your SVG viewer cannot display html.</text>
</switch>

</svg>

5
이것은 스위치를 사용하는 잘못된 방법입니다. svg 사양에 정의 된 기능 문자열 중 하나를 사용해야합니다. 대체는 귀하의 예에서 절대 사용되지 않습니다. w3.org/TR/SVG11/feature.htmlw3.org/TR/SVG11/struct.html#SwitchElement를 참조하십시오 .
Erik Dahlström 2013

22
또한 <foreignObject />는 IE에서 지원되지 않습니다
Doug Amos

3
그러나 모든 엔진이 foreignObject를 렌더링 할 수있는 것은 아닙니다. 특히 바틱은 그렇지 않습니다.
hrabinowitz

69

다음은 대안입니다.

<svg ...>
  <switch>
    <g requiredFeatures="http://www.w3.org/Graphics/SVG/feature/1.2/#TextFlow">
      <textArea width="200" height="auto">
       Text goes here
      </textArea>
    </g>
    <foreignObject width="200" height="200" 
     requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
      <p xmlns="http://www.w3.org/1999/xhtml">Text goes here</p>
    </foreignObject>
    <text x="20" y="20">No automatic linewrapping.</text>
  </switch>
</svg>

foreignObject가 해당 기능 문자열로 지원되는 것으로보고 될 수 있지만 HTML이 SVG 1.1 사양에서 필요하지 않기 때문에 표시 될 수 있다는 보장은 없습니다. 현재 html-in-foreignobject 지원을위한 기능 문자열이 없습니다. 그러나 많은 브라우저에서 여전히 지원되므로 향후 해당 기능 문자열과 함께 필요할 수 있습니다.

SVG Tiny 1.2 의 'textArea'요소 는 모든 표준 svg 기능 (예 : 고급 채우기 등)을 지원하며 너비 또는 높이를 자동으로 지정할 수 있습니다. 즉, 텍스트가 해당 방향으로 자유롭게 흐를 수 있음을 의미합니다. ForeignObject는 클리핑 뷰포트 역할을합니다.

참고 : 위의 예는 유효한 SVG 1.1 콘텐츠이지만 SVG 2에서는 'requiredFeatures'속성이 제거되었습니다. 즉, 'switch'요소가 SVG 1.2 'textArea에 대한 지원 여부에 관계없이 첫 번째'g '요소를 렌더링하려고 시도합니다. '요소. SVG2 스위치 요소 사양을 참조하십시오 .


1
FF에서이 코드를 테스트하고 있었는데 브라우저가 textArea 요소 나 foreignObject 자식을 보여주지 않았습니다. 그런 다음 사양을 읽은 후 requiredFeatures 속성이 목록이 false로 평가 될 때 requiredFeatures 속성을 가진 요소와 해당 하위가 처리되지 않는 방식으로 작동한다는 것을 발견했습니다. 따라서 스위치 요소에 대한 필요성이 없습니다. 스위치 요소를 제거한 후 foreignObject 자식이 표시되었습니다 (내 브라우저 (FF, 8.01)가 svg1.1을 지원하기 때문). 그래서 여기에 스위치 요소가 필요 없다고 생각합니다. 알려주세요.
Rajkamal Subramanian 2012

<g> 요소를 사용하도록 지금 업데이트되었습니다. svg 사양은 시청자에게 알려지지 않은 요소에 대한 'requiredFeatures'를 보도록 지시하지 않았으므로 의도 한대로 작동하려면 알려진 svg 요소를 사용해야합니다.
Erik Dahlström 2014

감사! xhtml:div대신 을 사용해야 div했지만 d3.js 때문일 수 있습니다. TextFlow에 대한 유용한 참조를 찾을 수 없습니다. (여전히) 존재합니까, 아니면 그냥 초안 이었습니까?
johndodo

2
textarea는 앞으로 지원되지 않는 것 같습니다. bugzilla.mozilla.org/show_bug.cgi?id=413360
George Mauer

1
예제는 Chrome에서 작동하지 않습니다. 다른 브라우저에서 테스트하지 않았습니다.
posfan12

15

어떤 경우에는 textPath가 좋을 수 있습니다.

<svg width="200" height="200"
    xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
  <!-- define lines for text lies on -->
  <path id="path1" d="M10,30 H190 M10,60 H190 M10,90 H190 M10,120 H190"></path>
 </defs>
 <use xlink:href="#path1" x="0" y="35" stroke="blue" stroke-width="1" />
 <text transform="translate(0,35)" fill="red" font-size="20">
  <textPath xlink:href="#path1">This is a long long long text ......</textPath>
 </text>
</svg>

3
중간 단어 줄 바꿈 (하이픈 제외)이 허용되는 경우에만 해당됩니다. 나는 그것이 괜찮은 예술 프로젝트 이외의 많은 경우를 생각할 수 없습니다. http://jsfiddle.net/nilloc/vL3zj/
Nilloc 2014 년

4
@Nilloc 모든 사람이 영어를 사용하는 것은 아닙니다.이 방법은 중국어, 일본어 또는 한국어에 완전히 적합합니다.
Zang MingJie

@ZangMingJie 문자 기반 (로고 그래픽) 언어에 대한 랩핑은 단어 분할과는 완전히 다른 사용 사례처럼 보입니다. 모든 낭만 / 라틴 / 키릴 / 아랍어 (음반) 언어에서 중요한 것이 제 요점이었습니다.
Nilloc

11

@Mike Gledhill의 코드를 기반으로 한 단계 더 나아가 더 많은 매개 변수를 추가했습니다. SVG RECT가 있고 그 안에 텍스트를 래핑하려면 다음이 유용 할 수 있습니다.

function wraptorect(textnode, boxObject, padding, linePadding) {

    var x_pos = parseInt(boxObject.getAttribute('x')),
    y_pos = parseInt(boxObject.getAttribute('y')),
    boxwidth = parseInt(boxObject.getAttribute('width')),
    fz = parseInt(window.getComputedStyle(textnode)['font-size']);  // We use this to calculate dy for each TSPAN.

    var line_height = fz + linePadding;

// Clone the original text node to store and display the final wrapping text.

   var wrapping = textnode.cloneNode(false);        // False means any TSPANs in the textnode will be discarded
   wrapping.setAttributeNS(null, 'x', x_pos + padding);
   wrapping.setAttributeNS(null, 'y', y_pos + padding);

// Make a copy of this node and hide it to progressively draw, measure and calculate line breaks.

   var testing = wrapping.cloneNode(false);
   testing.setAttributeNS(null, 'visibility', 'hidden');  // Comment this out to debug

   var testingTSPAN = document.createElementNS(null, 'tspan');
   var testingTEXTNODE = document.createTextNode(textnode.textContent);
   testingTSPAN.appendChild(testingTEXTNODE);

   testing.appendChild(testingTSPAN);
   var tester = document.getElementsByTagName('svg')[0].appendChild(testing);

   var words = textnode.textContent.split(" ");
   var line = line2 = "";
   var linecounter = 0;
   var testwidth;

   for (var n = 0; n < words.length; n++) {

      line2 = line + words[n] + " ";
      testing.textContent = line2;
      testwidth = testing.getBBox().width;

      if ((testwidth + 2*padding) > boxwidth) {

        testingTSPAN = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
        testingTSPAN.setAttributeNS(null, 'x', x_pos + padding);
        testingTSPAN.setAttributeNS(null, 'dy', line_height);

        testingTEXTNODE = document.createTextNode(line);
        testingTSPAN.appendChild(testingTEXTNODE);
        wrapping.appendChild(testingTSPAN);

        line = words[n] + " ";
        linecounter++;
      }
      else {
        line = line2;
      }
    }

    var testingTSPAN = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
    testingTSPAN.setAttributeNS(null, 'x', x_pos + padding);
    testingTSPAN.setAttributeNS(null, 'dy', line_height);

    var testingTEXTNODE = document.createTextNode(line);
    testingTSPAN.appendChild(testingTEXTNODE);

    wrapping.appendChild(testingTSPAN);

    testing.parentNode.removeChild(testing);
    textnode.parentNode.replaceChild(wrapping,textnode);

    return linecounter;
}

document.getElementById('original').onmouseover = function () {

    var container = document.getElementById('destination');
    var numberoflines = wraptorect(this,container,20,1);
    console.log(numberoflines);  // In case you need it

};

감사. Chrome에서 완벽하게 작동합니다. 하지만 파이어 폭스에서는 작동하지 않습니다. 데모 링크에 나와 있습니다. 예기치 않은 값 NaN이 dy 속성을 구문 분석합니다. svgtext_clean2.htm : 117 해결 방법을 찾으려고합니다.
akshayb

나중에 Firefox에서 작동했습니다. 여기 있습니다 :
MSC

1
(지금은 너무 빨리 ENTER를 눌렀습니다.) 나중에 Firefox와 IE에서 작동하게되었습니다. 도움이 필요하면 democra.me/wrap_8_may_2014.htm을 참조하십시오 . 코드에 Firefox에 대한 주석이 있습니다.
MSC

보시다시피, 코드를 많이 확장하여 경계 상자를 위아래로 축소하거나 올바른 위치에서 줄임표로 자릅니다.
MSC

나는 MSC의 코드에서 줄을 수정 것 : boxwidth = parseInt(boxObject.getAttribute('width'))단지 픽셀의 폭을 받아들이, 동안 boxwidth = parseInt(boxObject.getBBox().width), 측정 장치의 모든 유형 받아 들일
마시밀리아노 Caniparoli


7

다음 코드는 잘 작동합니다. 코드 조각을 실행합니다.

정리하거나 SVG의 모든 텍스트 태그와 함께 자동으로 작동하도록 할 수 있습니다.

function svg_textMultiline() {

  var x = 0;
  var y = 20;
  var width = 360;
  var lineHeight = 10;
  
  

  /* get the text */
  var element = document.getElementById('test');
  var text = element.innerHTML;

  /* split the words into array */
  var words = text.split(' ');
  var line = '';

  /* Make a tspan for testing */
  element.innerHTML = '<tspan id="PROCESSING">busy</tspan >';

  for (var n = 0; n < words.length; n++) {
    var testLine = line + words[n] + ' ';
    var testElem = document.getElementById('PROCESSING');
    /*  Add line in testElement */
    testElem.innerHTML = testLine;
    /* Messure textElement */
    var metrics = testElem.getBoundingClientRect();
    testWidth = metrics.width;

    if (testWidth > width && n > 0) {
      element.innerHTML += '<tspan x="0" dy="' + y + '">' + line + '</tspan>';
      line = words[n] + ' ';
    } else {
      line = testLine;
    }
  }
  
  element.innerHTML += '<tspan x="0" dy="' + y + '">' + line + '</tspan>';
  document.getElementById("PROCESSING").remove();
  
}


svg_textMultiline();
body {
  font-family: arial;
  font-size: 20px;
}
svg {
  background: #dfdfdf;
  border:1px solid #aaa;
}
svg text {
  fill: blue;
  stroke: red;
  stroke-width: 0.3;
  stroke-linejoin: round;
  stroke-linecap: round;
}
<svg height="300" width="500" xmlns="http://www.w3.org/2000/svg" version="1.1">

  <text id="test" y="0">GIETEN - Het college van Aa en Hunze is in de fout gegaan met het weigeren van een zorgproject in het failliete hotel Braams in Gieten. Dat stelt de PvdA-fractie in een brief aan het college. De partij wil opheldering over de kwestie en heeft schriftelijke
    vragen ingediend. Verkeerde route De PvdA vindt dat de gemeenteraad eerst gepolst had moeten worden, voordat het college het plan afwees. "Volgens ons is de verkeerde route gekozen", zegt PvdA-raadslid Henk Santes.</text>

</svg>


1
SVG 텍스트의 자동 줄 바꿈 :) 내 자바 스크립트 코드는 텍스트가 길면 줄을 만듭니다. SVG 내의 모든 텍스트 태그에서 작업하면 좋을 것입니다. javascript에서 id = ""를 변경하지 않고 자동으로. 나쁜 SVG에는 그 자체로 여러 줄이 있습니다.
Peter

좋은 솔루션이지만 중앙에 정렬 할 수 있습니까?
Krešimir Galić

대답 tbh를 받아 들여야합니다. 자바 스크립트 솔루션은 충분히 최소한이며 의미가 있습니다.
Zac

4

여기에 SVG "텍스트"요소에 가짜 단어 줄 바꿈을 추가하기위한 다음 연습을 게시했습니다.

SVG Word Wrap-스토퍼 표시?

문자열을 더 짧은 "tspan"요소로 분할하는 간단한 JavaScript 함수를 추가하기 만하면됩니다. 다음은 그 모습의 예입니다.

SVG 예

도움이 되었기를 바랍니다 !

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.