这不是 SVG 1.1 支持的。 SVG 1.2 确实有
textArea
元素,具有自动换行功能,但并非在所有浏览器中都实现。 SVG 2 不打算实现 textArea
,但它确实有 自动换行文本。
但是,鉴于您已经知道应该在哪里换行,您可以将文本分成多个
<tspan>
,每个x="0"
和 dy="1.4em"
来模拟实际的文本行。例如:
<g transform="translate(123 456)"><!-- replace with your target upper left corner coordinates -->
<text x="0" y="0">
<tspan x="0" dy="1.2em">very long text</tspan>
<tspan x="0" dy="1.2em">I would like to linebreak</tspan>
</text>
</g>
当然,由于您想通过 JavaScript 执行此操作,因此您必须手动创建每个元素并将其插入到 DOM 中。
我想你已经设法解决了它,但如果有人正在寻找类似的解决方案,那么这对我有用:
g.append('svg:text')
.attr('x', 0)
.attr('y', 30)
.attr('class', 'id')
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 5)
.text(function(d) { return d.name; })
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 20)
.text(function(d) { return d.sname; })
.append('svg:tspan')
.attr('x', 0)
.attr('dy', 20)
.text(function(d) { return d.idcode; })
有 3 行用换行符分隔。
使用 tspan 解决方案,假设您事先不知道在哪里放置换行符:您可以使用我在这里找到的这个不错的函数: http://bl.ocks.org/mbostock/7555321
自动为给定宽度(以像素为单位)的长文本 svg 进行换行。
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")) || 0,
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
使用 HTML 而不是 javascript
限制:SVG渲染器必须支持HTML渲染
例如,inkscape 无法渲染此类 SVG 文件
<html>
<head><style> * { margin: 0; padding: 0; } </style></head>
<body>
<h1>svg foreignObject to embed html</h1>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 300 300"
x="0" y="0" height="300" width="300"
>
<circle
r="142" cx="150" cy="150"
fill="none" stroke="#000000" stroke-width="2"
/>
<foreignObject
x="50" y="50" width="200" height="200"
>
<div
xmlns="http://www.w3.org/1999/xhtml"
style="
width: 196px; height: 196px;
border: solid 2px #000000;
font-size: 32px;
overflow: auto; /* scroll */
"
>
<p>this is html in svg 1</p>
<p>this is html in svg 2</p>
<p>this is html in svg 3</p>
<p>this is html in svg 4</p>
</div>
</foreignObject>
</svg>
</body></html>
我认为这符合你的要求:
function ShowTooltip(evt, mouseovertext){
// Make tooltip text
var tooltip_text = tt.childNodes.item(1);
var words = mouseovertext.split("\\\n");
var max_length = 0;
for (var i=0; i<3; i++){
tooltip_text.childNodes.item(i).firstChild.data = i<words.length ? words[i] : " ";
length = tooltip_text.childNodes.item(i).getComputedTextLength();
if (length > max_length) {max_length = length;}
}
var x = evt.clientX + 14 + max_length/2;
var y = evt.clientY + 29;
tt.setAttributeNS(null,"transform", "translate(" + x + " " + y + ")")
// Make tooltip background
bg.setAttributeNS(null,"width", max_length+15);
bg.setAttributeNS(null,"height", words.length*15+6);
bg.setAttributeNS(null,"x",evt.clientX+8);
bg.setAttributeNS(null,"y",evt.clientY+14);
// Show everything
tt.setAttributeNS(null,"visibility","visible");
bg.setAttributeNS(null,"visibility","visible");
}
它在
\\\n
上分割文本,并将每个片段放入一个 tspan 中。然后它根据文本的最长长度和行数计算所需框的大小。您还需要更改工具提示文本元素以包含三个 tspan:
<g id="tooltip" visibility="hidden">
<text><tspan>x</tspan><tspan x="0" dy="15">x</tspan><tspan x="0" dy="15">x</tspan></text>
</g>
这假设您的行数永远不会超过三行。如果您想要超过三行,您可以添加更多 tspan 并增加 for 循环的长度。
我对@steco 的解决方案进行了一些调整,将依赖项从
d3
切换到 jquery
并将文本元素的 height
添加为参数
function wrap(text, width, height) {
text.each(function(idx,elem) {
var text = $(elem);
text.attr("dy",height);
var words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat( text.attr("dy") ),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (elem.getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
有关的解决方案不适用于我的情况,因为我需要在我的 React 应用程序中使用动态解决方法(特别是我在多语言应用程序上工作,每种语言文本的断线也可能不同)。因此,我在需要换行的文本中使用了
\n
,然后使用 map
方法使用 tspan
元素创建多行文本,其中我们有一个新行。
const SvgComponent = ({ text }) => {
// Split the text into an array of lines based on line breaks ("\n")
const lines = text.split('\n');
return (
<svg width="200" height="200">
{lines.map((line, index) => (
// Use your desired x and y coordinates and line space
<text key={index} x="10" y={10 + index * 20}>
<tspan>{line}</tspan>
</text>
))}
</svg>
);
};
export default SvgComponent;
当您将带有换行符的文本作为 text prop 传递给此组件时,它将在 SVG 中的新行上渲染每行文本。例如:
<SvgComponent text="Line 1\nLine 2\nLine 3" />