最近做的项目涉及到 web 绘图,采用 d3 操作 svg
实现。图中通常会用到文本,而 svg
里的 text
元素不像普通 DOM 元素那样能很好地处理文本换行,所以要用到一些技巧。
通常有两种做法。
1.用 tspan
把 text
拆成多行,重新计算每个tspan
的 y
坐标。
<svg xmlns="http://www.w3.org/2000/svg">
<text font-size="14">
<tspan x="0" y="10">较长文文本一行</tspan>
<tspan x="0" y="28">放不下就换行</tspan>
</text>
</svg>
2.用 foreignObject
包裹 DOM 元素,利用 DOM 的文本布局能力自动处理换行。
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="120" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<p style="font-size:14px;margin:0;">较长文文本一行放不下就换行</p>
</body>
</foreignObject>
</svg>
两种方法各有千秋,方法1可以精确控制换行位置,但是需要计算具体的坐标。方法2无需计算内部坐标,但它是根据单词来分割的,针对长英文单词也无能为力。
笔者碰到的就是单个长英文单词也要换行显示,所以只能用方法1。产品需求是文本根据屏幕大小自动适配,如果宽度不够就换行显示。效果如下图所示:
Outperformance 这个单词被截断。原理就是先在 text
元素下插入一个tspan
,将单词里的字母逐个填进去,判断元素宽度是否达到限制。如果超过限制就再插入一个 tspan
,同时计算新 tspan
的 y
坐标。由于事先知道 text
的具体位置,x
保持一致就可以了。代码如下:
function wrapWord(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split('').reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = text.node().getBoundingClientRect().height,
x = +text.attr('x'),
y = +text.attr('y'),
tspan = text.text(null).append('tspan').attr('x', x).attr('y', y);
while (word = words.pop()) {
line.push(word);
const dash = lineNumber > 0 ? '-' : '';
tspan.text(dash + line.join(''));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(''));
line = [word];
tspan = text.append('tspan').attr('x', x).attr('y', ++lineNumber * lineHeight + y).text(word);
}
}
});
}
div或者p标签单行和多行超出显示省略号
❤️ 谢谢支持
喜欢的话别忘了 关注、点赞哦~。
❤️ 谢谢支持
喜欢的话别忘了 关注、点赞哦~。
[外链图片转存中…(img-0Jg62HXk-1718718537686)]