在SVG中将文本修剪为给定的像素宽度

时间:2012-02-11 15:21:49

标签: svg

我正在SVG中绘制文字标签。我有一个固定的宽度(比如200px)。当文字太长时,我该如何修剪呢?

理想的解决方案还会添加文本被剪切的省略号(...)。但我也可以没有它。

8 个答案:

答案 0 :(得分:26)

执行此操作的一种方法是使用textPath元素,因为从路径上掉落的所有字符都将自动剪切掉。请参阅SVG测试套件中的文本路径examples

另一种方法是在svg文本元素上使用CSS3 text-overflow,例如here。 Opera 11支持这一点,但您可能会发现其他浏览器目前仅支持html元素。

你也可以测量文本字符串并自己用脚本插入省略号,我建议在文本元素上使用getSubStringLength方法,增加nchars参数,直到找到合适的长度。

答案 1 :(得分:21)

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

答案 2 :(得分:17)

实施Erik的第三个建议我想出了类似的东西:

//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
    }
}

似乎可以做到这一点:)

答案 3 :(得分:4)

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

答案 4 :(得分:1)

尝试这个,我在图表库中使用此功能:

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 + "...";
    }
  }
}

答案 5 :(得分:0)

我的方法类似于OpherV,但我尝试使用JQuery

&#13;
&#13;
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, desiredSize, 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;
    }
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;

现在,在致电getStringForSize('asdfasdfasdfasdfasdfasdf', 110, '13px','OpenSans-Light')时,您将获得&#34; asdfasdfasdfasd ......&#34;

答案 6 :(得分:0)

linearGradient元素可用于生成纯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解决方案。)

答案 7 :(得分:0)

有几种使用d3和循环的变体来搜索适合的较小文本。无需循环即可实现,并且工作速度更快。 textNode-d3节点。

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