文本换行不是当前实现的规范 SVG1.1 的一部分。
如果您要在 Web 上使用 SVG 图形,可以通过 <foreignObject/>
元素将 HTML 嵌入到 SVG 中。例子:
<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>
如果您的目标是一个不支持 HTML 的纯 SVG 渲染器,或者希望您的图形可以使用专业的矢量图形处理软件(Adobe Illustrator、Inkscape 等)进行编辑,那么此解决方案可能不适合您。
这是一个替代方案:
<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' element 支持所有标准 svg 功能,例如高级填充等,并且您可以将宽度或高度指定为自动,这意味着文本可以在该方向上自由流动。 ForeignObject 充当剪辑视口。
注意: 虽然上面的示例是有效的 SVG 1.1 内容,但在 SVG 2 中,'requiredFeatures' 属性已被删除,这意味着 'switch' 元素将尝试渲染第一个 'g' 元素,而不管支持 SVG 1.2 'textArea' 元素。请参阅SVG2 switch element spec。
xhtml:div
而不是 div
,但这可能是因为 d3.js。我找不到任何关于 TextFlow 的有用参考,它(仍然)存在还是只是在一些草稿中?
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>
xmlns:xlink="http://www.w3.org/1999/xlink"
属性对其工作至关重要。
在@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
};
boxwidth = parseInt(boxObject.getAttribute('width'))
,将只接受以像素为单位的宽度,而 boxwidth = parseInt(boxObject.getBBox().width)
,将接受任何类型的度量单位
以下代码工作正常。运行代码片段它的作用。
也许它可以被清理或使其自动与 SVG 中的所有文本标签一起使用。
函数 svg_textMultiline() { var x = 0;变量 y = 20;可变宽度 = 360;变线高度 = 10; /* 获取文本 */ var element = document.getElementById('test'); var text = element.innerHTML; /* 将单词拆分成数组 */ var words = text.split(' '); varline = ''; /* 为测试创建一个 tspan */ element.innerHTML = '
也可以使用 JavaScript 添加此功能。 Carto.net 有一个例子:
http://old.carto.net/papers/svg/textFlow/
其他可能对您有用的东西是可编辑的文本区域:
http://old.carto.net/papers/svg/gui/textbox/
我已经发布了以下演练,用于在此处向 SVG“文本”元素添加一些虚假的自动换行:
您只需要添加一个简单的 JavaScript 函数,它将您的字符串拆分为更短的“tspan”元素。这是它的外观示例:
https://i.stack.imgur.com/Bpvui.png
希望这可以帮助 !
我尝试了所有答案,只有我创建了菜鸟解决方案,但它会在没有未知代码行的情况下解决问题另一个文本标签等等。您只需要简单的 JavaScript if 语句并更改文本内容
if (data['clinic']['cicovidcliniccity'].length > 35 && data['clinic']['cicovidcliniccity'].length < 75) {
const cname = data['clinic']['cicovidcliniccity'];
const ctext2_shodow = document.querySelector("#c_text2_shdow");
ctext2.textContent = cname.substring(1, 35)
ctext2_shodow.textContent = cname.substring(35, cname.length);
}
if (data['clinic']['cicovidcliniccity'].length > 75 && data['clinic']['cicovidcliniccity'].length < 110) {
const cname1 = data['clinic']['cicovidcliniccity'];
const ctext2_shodow = document.querySelector("#c_text2_shdow");
const ctext3_shodow = document.querySelector("#c_text3_shdow");
ctext2.textContent = cname1.substring(1, 35)
ctext2_shodow.textContent = cname1.substring(35, 75);
ctext3_shodow.textContent = cname1.substring(75, cname1.length);
}