การตัดบรรทัดอัตโนมัติในข้อความ SVG


111

ฉันต้องการแสดง<text>สิ่งที่จะตัดบรรทัดอัตโนมัติไปยังคอนเทนเนอร์ใน SVG <rect>เช่นเดียวกับข้อความ HTML ที่เติม<div>องค์ประกอบ มีวิธีทำไหม ฉันไม่ต้องการวางตำแหน่งเส้นแบบกระจัดกระจายโดยใช้<tspan>s

คำตอบ:


90

การตัดข้อความไม่ได้เป็นส่วนหนึ่งของ SVG1.1 ซึ่งเป็นข้อมูลจำเพาะที่ใช้งานอยู่ในปัจจุบัน คุณควรใช้ HTML ผ่าน<foreignObject/>องค์ประกอบ

<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.htmlและw3.org/TR/SVG11/struct.html#SwitchElement
Erik Dahlström

22
IE ยังไม่รองรับ <ForeignObject />
Doug Amos

3
แต่โปรดทราบว่าไม่ใช่ทุกเครื่องยนต์ที่สามารถแสดงวัตถุต่างประเทศได้ โดยเฉพาะอย่างยิ่งผ้าบาติกไม่
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 อาจได้รับการรายงานว่าได้รับการสนับสนุนด้วย featurestring นั้น แต่ก็ไม่มีการรับประกันว่า HTML จะสามารถแสดงได้เนื่องจากข้อกำหนด SVG 1.1 นั้นไม่จำเป็น ไม่มี featurestring สำหรับการสนับสนุน html-in-Foreignobject ในขณะนี้ อย่างไรก็ตามยังคงได้รับการสนับสนุนในเบราว์เซอร์จำนวนมากดังนั้นจึงมีแนวโน้มที่จะจำเป็นในอนาคตซึ่งอาจจะมีสตริงคุณลักษณะที่เกี่ยวข้อง

โปรดทราบว่าองค์ประกอบ "textArea"ใน SVG Tiny 1.2 รองรับคุณสมบัติ svg มาตรฐานทั้งหมดเช่นการเติมขั้นสูงเป็นต้นและคุณสามารถระบุความกว้างหรือความสูงเป็นแบบอัตโนมัติซึ่งหมายความว่าข้อความสามารถไหลไปในทิศทางนั้นได้อย่างอิสระ ForeignObject ทำหน้าที่ตัดวิวพอร์ต

หมายเหตุ:แม้ว่าตัวอย่างข้างต้นจะเป็นเนื้อหา SVG 1.1 ที่ถูกต้อง แต่ใน SVG 2 แอตทริบิวต์ "requiredFeatures" ได้ถูกลบออกซึ่งหมายความว่าองค์ประกอบ "switch" จะพยายามแสดงผลองค์ประกอบ "g" แรกโดยไม่คำนึงถึงการรองรับ SVG 1.2 "textArea 'องค์ประกอบ. ดูSVG2 ข้อมูลจำเพาะองค์ประกอบสวิทช์


1
ฉันกำลังทดสอบรหัสนี้ใน FF เบราว์เซอร์ไม่ได้แสดงให้ฉันเห็นทั้งองค์ประกอบ textArea หรือลูก ForeignObject หลังจากอ่านข้อมูลจำเพาะพบว่าแอตทริบิวต์ requiredFeatures ทำงานในลักษณะที่เมื่อรายการประเมินเป็นเท็จองค์ประกอบที่มีแอตทริบิวต์ requiredFeatures และลูกของมันจะไม่ถูกประมวลผล ดังนั้นจึงไม่มีความจำเป็นใด ๆ สำหรับองค์ประกอบสวิตช์ หลังจากที่ฉันลบองค์ประกอบสวิตช์ออกเด็ก ๆ ForeignObject จะมองเห็นได้ (เนื่องจากเบราว์เซอร์ของฉัน (FF, 8.01) รองรับ svg1.1) ดังนั้นฉันคิดว่าไม่จำเป็นต้องมีองค์ประกอบสวิตช์ที่นี่ กรุณาแจ้งให้เราทราบ
Rajkamal Subramanian

อัปเดตทันทีเพื่อใช้องค์ประกอบ <g> ข้อมูลจำเพาะ svg ไม่ได้บอกให้ผู้ชมดู 'requiredFeatures' ในองค์ประกอบที่ไม่รู้จักดังนั้นจึงต้องใช้องค์ประกอบ svg ที่รู้จักเพื่อให้ทำงานได้ตามที่ต้องการ
Erik Dahlström

ขอบคุณ! ฉันจำเป็นต้องใช้xhtml:divแทนdivแต่นั่นอาจเป็นเพราะ d3.js ฉันไม่พบข้อมูลอ้างอิงที่เป็นประโยชน์เกี่ยวกับ TextFlow มี (ยัง) อยู่หรือเป็นเพียงร่างบางส่วน?
johndodo

2
ควรสังเกตว่า textarea ดูเหมือนจะไม่ได้รับการสนับสนุนในอนาคตbugzilla.mozilla.org/show_bug.cgi?id=413360
George Mauer

1
ตัวอย่างใช้ไม่ได้ใน Chrome ยังไม่ได้ทดสอบในเบราว์เซอร์อื่น
posfan12

16

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

4
@Nilloc ไม่ใช่ทุกคนที่ใช้ภาษาอังกฤษวิธีนี้ใช้ได้กับคนจีนญี่ปุ่นหรือเกาหลี
Zang MingJie

@ZangMingJie Wrapping สำหรับภาษาตามอักขระ (โลโกกราฟิก) ดูเหมือนจะเป็นกรณีการใช้งานที่แตกต่างไปจากการแยกคำโดยสิ้นเชิง ซึ่งมีความสำคัญในภาษาโรแมนติก / ละติน / ซิริลลิก / อาหรับ (การออกเสียง) ซึ่งเป็นประเด็นของฉัน
Nilloc

12

จากรหัสของ @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 แต่มันใช้ไม่ได้ใน firefox มันบอกในลิงค์สาธิต ค่าที่ไม่คาดคิด 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)ยอมรับหน่วยการวัดประเภทใดก็ได้
Massimiliano Caniparoli

9

ฟังก์ชันนี้สามารถเพิ่มได้โดยใช้ JavaScript Carto.net มีตัวอย่าง:

http://old.carto.net/papers/svg/textFlow/

สิ่งอื่นที่อาจเป็นประโยชน์สำหรับคุณคือพื้นที่ข้อความที่แก้ไขได้:

http://old.carto.net/papers/svg/gui/textbox/


404 - ลิงก์เหล่านั้นใช้งานไม่ได้
Matthias

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 อัตโนมัติโดยไม่ต้องเปลี่ยน id = "" ใน javascript สำหรับ SVG ที่ไม่ดีจะมีหลายบรรทัดด้วยตัวเอง
ปีเตอร์

ทางออกที่ดี แต่คุณสามารถจัดตำแหน่งให้อยู่ตรงกลางได้หรือไม่?
KrešimirGalić

ควรได้รับการยอมรับคำตอบ tbh. โซลูชันจาวาสคริปต์มีน้อยเพียงพอและเหมาะสม
Zac

4

ฉันได้โพสต์คำแนะนำต่อไปนี้สำหรับการเพิ่มการตัดคำปลอมลงในองค์ประกอบ "ข้อความ" ของ SVG ที่นี่:

SVG Word Wrap - แสดงตัวหยุด?

คุณเพียงแค่ต้องเพิ่มฟังก์ชัน JavaScript ธรรมดาซึ่งจะแยกสตริงของคุณออกเป็นองค์ประกอบ "tspan" ที่สั้นกว่า นี่คือตัวอย่างของลักษณะ:

ตัวอย่าง SVG

หวังว่านี่จะช่วยได้!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.