Câu trả lời:
Gói văn bản không phải là một phần của SVG1.1, thông số kỹ thuật hiện được triển khai. Bạn nên sử dụng HTML thông qua <foreignObject/>
phần tử.
<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>
Đây là một giải pháp thay thế:
<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>
Lưu ý rằng mặc dù ForeignObject có thể được báo cáo là được hỗ trợ với chuỗi tính năng đó, nhưng không có gì đảm bảo rằng HTML có thể được hiển thị vì điều đó không được yêu cầu bởi đặc tả SVG 1.1. Không có chuỗi đặc điểm nào để hỗ trợ html-in-Foreignnobject vào lúc này. Tuy nhiên, nó vẫn được hỗ trợ trong nhiều trình duyệt, vì vậy nó có khả năng được yêu cầu trong tương lai, có lẽ với một chuỗi tính năng tương ứng.
Lưu ý rằng phần tử 'textArea' trong SVG Tiny 1.2 hỗ trợ tất cả các tính năng svg tiêu chuẩn, ví dụ như điền nâng cao, v.v. và bạn có thể chỉ định chiều rộng hoặc chiều cao là tự động, nghĩa là văn bản có thể chảy tự do theo hướng đó. ForeignObject hoạt động như một khung nhìn cắt bớt.
Lưu ý: mặc dù ví dụ trên là nội dung SVG 1.1 hợp lệ, nhưng trong SVG 2, thuộc tính 'requiredFeatures' đã bị xóa, có nghĩa là phần tử 'switch' sẽ cố gắng hiển thị phần tử 'g' đầu tiên bất kể có hỗ trợ cho SVG 1.2 'textArea 'các phần tử. Xem thông số kỹ thuật phần tử công tắc SVG2 .
xhtml:div
thay vì div
, nhưng đó có thể là do d3.js. Tôi không thể tìm thấy bất kỳ tài liệu tham khảo hữu ích nào về TextFlow, nó (vẫn) tồn tại hay chỉ là trong bản nháp nào đó?
TextPath có thể tốt cho một số trường hợp.
<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>
Dựa trên mã của @Mike Gledhill, tôi đã tiến thêm một bước nữa và thêm nhiều thông số hơn. Nếu bạn có SVG RECT và muốn văn bản nằm bên trong nó, điều này có thể hữu ích:
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'))
, sẽ chỉ chấp nhận chiều rộng tính bằng pixel, trong khi boxwidth = parseInt(boxObject.getBBox().width)
, sẽ chấp nhận bất kỳ loại đơn vị đo nào
Chức năng này cũng có thể được thêm vào bằng JavaScript. Carto.net có một ví dụ:
http://old.carto.net/papers/svg/textFlow/
Một cái gì đó khác cũng có thể hữu ích cho bạn là các vùng văn bản có thể chỉnh sửa:
Đoạn mã sau đang hoạt động tốt. Chạy đoạn mã những gì nó làm.
Có thể nó có thể được dọn dẹp hoặc làm cho nó tự động hoạt động với tất cả các thẻ văn bản trong 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>
Tôi đã đăng hướng dẫn sau để thêm một số gói từ giả mạo vào phần tử "văn bản" SVG tại đây:
SVG Word Wrap - Hiển thị nút chặn?
Bạn chỉ cần thêm một hàm JavaScript đơn giản để chia chuỗi của bạn thành các phần tử "tspan" ngắn hơn. Dưới đây là một ví dụ về nó trông như thế nào:
Hi vọng điêu nay co ich !