我正在 SVG 中绘制文本标签。我有一个可用的固定宽度(比如 200px)。当文字太长时,如何修剪?
理想的解决方案还会在文本被剪切的地方添加省略号 (...)。但没有它我也可以生活。
使用 d3 库
溢出文本的包装函数:
function wrap() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (width - 2 * padding) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
}
用途:
text.append('tspan').text(function(d) { return d.name; }).each(wrap);
实现此目的的一种方法是使用 textPath 元素,因为所有脱离路径的字符都会被自动剪掉。请参阅 SVG 测试套件中的文本路径 examples。
另一种方法是在 svg 文本元素上使用 CSS3 text-overflow,示例此处。 Opera 11 支持这一点,但您可能会发现其他浏览器目前仅在 html 元素上支持它。
您还可以测量文本字符串并自己使用脚本插入省略号,我建议在文本元素上使用 getSubStringLength 方法,增加 nchars 参数,直到找到合适的长度。
实现埃里克的第三个建议,我想出了这样的东西:
//places textString in textObj, adds an ellipsis if text can't fit in width
function placeTextWithEllipsis(textObj,textString,width){
textObj.textContent=textString;
//ellipsis is needed
if (textObj.getSubStringLength(0,textString.length)>=width){
for (var x=textString.length-3;x>0;x-=3){
if (textObj.getSubStringLength(0,x)<=width){
textObj.textContent=textString.substring(0,x)+"...";
return;
}
}
textObj.textContent="..."; //can't place at all
}
}
似乎可以解决问题:)
@user2846569 告诉我如何做到这一点(是的,使用 d3.js )。但是,我必须为工作做一些小改变:
function wrap( d ) {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while ( ( textLength > self.attr('width') )&& text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
}
svg.append('text')
.append('tspan')
.text(function(d) { return d; })
.attr('width', 200 )
.each( wrap );
线性渐变元素可用于生成纯 SVG 解决方案。 此示例淡出截断的文本(无省略号):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<defs>
<linearGradient gradientUnits="userSpaceOnUse" x1="0" x2="200" y1="0" y2="0" id="truncateText">
<stop offset="90%" stop-opacity="1" />
<stop offset="100%" stop-opacity="0" />
</linearGradient>
<linearGradient id="truncateLegendText0" gradientTransform="translate(0)" xlink:href="#truncateText" />
<linearGradient id="truncateLegendText1" gradientTransform="translate(200)" xlink:href="#truncateText" />
</defs>
<text fill="url(#truncateLegendText0)" font-size="50" x="0" y="50">0123456789</text>
<text fill="url(#truncateLegendText1)" font-size="50" x="200" y="150">0123456789</text>
</svg>
(我必须使用线性渐变来解决这个问题,因为我使用的 SVG 渲染器不支持 textPath 解决方案。)
function textEllipsis(el, text, width) {
if (typeof el.getSubStringLength !== "undefined") {
el.textContent = text;
var len = text.length;
while (el.getSubStringLength(0, len--) > width) {}
el.textContent = text.slice(0, len) + "...";
} else if (typeof el.getComputedTextLength !== "undefined") {
while (el.getComputedTextLength() > width) {
text = text.slice(0,-1);
el.textContent = text + "...";
}
} else {
// the last fallback
while (el.getBBox().width > width) {
text = text.slice(0,-1);
// we need to update the textContent to update the boundary width
el.textContent = text + "...";
}
}
}
clipText(textNode, maxWidth, postfix) {
const textWidth = textNode.getComputedTextLength();
if (textWidth > maxWidth) {
let text = textNode.textContent;
const newLength = Math.round(text.length * (1 - (textWidth - maxWidth) / textWidth));
text = text.substring(0, newLength);
textNode.textContent = text.trim() + postfix;
}
}
function getWidthOfText(text, fontSize, fontFamily) {
var span = $('<span></span>');
span.css({
'font-family': fontFamily,
'font-size' : fontSize
}).text(text);
$('body').append(span);
var w = span.width();
span.remove();
return w;
}
function getStringForSize(text, size, fontSize, fontFamily) {
var curSize = getWidthOfText(text, fontSize, fontFamily);
if(curSize > size)
{
var curText = text.substring(0,text.length-5) + '...';
return getStringForSize(curText, size, fontSize, fontFamily);
}
else
{
return text;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
现在拨打
getStringForSize('asdfasdfasdfasdfasdfasdf', 110, '13px','OpenSans-Light')
时,您会收到“asdfasdfasdfasd...”
<clip-path>
,因为我刚刚使用了它,它将文本截断为 100% 简单的 SVG 中的像素。 听起来OP可能更喜欢当前的#2答案,因为它使用
<textPath>
在字母边界处截断,至少在我对Chrome的测试中是这样。这里是基于
MDN 文档页面示例 的 <clip-path>
的片段(您可能需要滚动结果才能看到截断):
<svg viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg">
<clipPath id="myClip" clipPathUnits="userSpaceOnUse">
<rect width="20" height="20"/>
</clipPath>
<rect x="0.5" y="0.5" width="24" height="24" stroke="green" fill="none"/>
<text x="1" y="15" fill="blue" font-size="12" clip-path="url(#myClip)">Truncation at the pixel</text>
</svg>