如何在 javascript 中分行 svg 文本?

这就是我所知道的:

<path class="..." onmousemove="show_tooltip(event,'very long text
\\\n I would like to linebreak')" onmouseout="hide_tooltip()" d="..."/>


<rect class="tooltip_bg" id="tooltip_bg" ... />
<text class="tooltip" id="tooltip" ...>Tooltip</text>


<script>
<![CDATA[
function show_tooltip(e,text) {
var tt = document.getElementById('tooltip');
var bg = document.getElementById('tooltip_bg');


// set position ...


tt.textContent=text;


bg.setAttribute('width',tt.getBBox().width+10);
bg.setAttribute('height',tt.getBBox().height+6);


// set visibility ...
}
...

现在我的很长的工具提示文本没有换行符,即使我使用 alert () ; 它显示文本实际上有两行。(不过,它包含一个“”,顺便问一下,我该如何删除它?)
我无法让 CDATA 在任何地方工作。

168178 次浏览

这不是 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 中。

我想这就是你想要的:

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 循环的长度。

我想你已经设法解决了这个问题,但是如果有人正在寻找类似的解决方案,那么这个方法对我很有效:

 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);
}
}
});
}

我通过@steco 稍微调整了一下解决方案,将依赖项从 d3切换到 jquery,并添加 text 元素的 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);
}
}
});
}

使用 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>