Odpowiedzi:
Zawijanie tekstu nie jest częścią SVG1.1, obecnie zaimplementowanej specyfikacji. Powinieneś raczej używać HTML poprzez <foreignObject/>
element.
<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>
Oto alternatywa:
<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>
Zwracając uwagę, że nawet jeśli ForeignObject może zostać zgłoszone jako obsługiwane przez ten ciąg cech, nie ma gwarancji, że HTML może zostać wyświetlony, ponieważ nie jest to wymagane przez specyfikację SVG 1.1. W tej chwili nie ma łańcucha funkcji do obsługi html-in-Foreignobject. Jednak jest nadal obsługiwany w wielu przeglądarkach, więc prawdopodobnie stanie się wymagany w przyszłości, być może z odpowiednim ciągiem funkcji.
Zwróć uwagę, że element „textArea” w SVG Tiny 1.2 obsługuje wszystkie standardowe funkcje SVG, np. Zaawansowane wypełnianie itp., I że możesz określić szerokość lub wysokość jako auto, co oznacza, że tekst może swobodnie przepływać w tym kierunku. ForeignObject działa jako rzutnia przycinająca.
Uwaga: chociaż powyższy przykład jest prawidłową zawartością SVG 1.1, w SVG 2 atrybut „requiredFeatures” został usunięty, co oznacza, że element „switch” będzie próbował wyrenderować pierwszy element „g” niezależnie od obsługi SVG 1.2 ”textArea ' elementy. Patrz specyfikacja elementu przełączającego SVG2 .
xhtml:div
zamiast div
, ale może to być spowodowane d3.js. Nie mogłem znaleźć żadnej użytecznej informacji o TextFlow, czy istnieje (nadal) czy tylko w jakiejś wersji roboczej?
W niektórych przypadkach właściwość textPath może być dobra.
<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>
Opierając się na kodzie @Mike Gledhill, poszedłem o krok dalej i dodałem więcej parametrów. Jeśli masz SVG RECT i chcesz zawinąć w nim tekst, może to być przydatne:
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
};
boxwidth = parseInt(boxObject.getAttribute('width'))
zaakceptowałbym po prostu szerokość w pikselach, podczas gdy boxwidth = parseInt(boxObject.getBBox().width)
zaakceptowałbym dowolny typ jednostki miary
Tę funkcjonalność można również dodać za pomocą JavaScript. Carto.net ma przykład:
http://old.carto.net/papers/svg/textFlow/
Coś jeszcze, co może być przydatne, to edytowalne obszary tekstowe:
Poniższy kod działa poprawnie. Uruchom fragment kodu, co robi.
Może da się go wyczyścić lub sprawić, by działał automatycznie ze wszystkimi tagami tekstowymi w 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>
Opublikowałem następującą instrukcję dodawania fałszywego zawijania słów do elementu „tekst” SVG:
Zawijanie słów SVG - Pokaż korek?
Wystarczy dodać prostą funkcję JavaScript, która podzieli Twój ciąg na krótsze elementy „tspan”. Oto przykład tego, jak to wygląda:
Mam nadzieję że to pomoże !