关于css:在SVG中添加省略号以溢出文本?

Add ellipses to overflowing text in SVG?

我用的是D3.js。我想找到一个与这个css类等效的svg,如果文本从其包含的div中流出,它会添加省略号:

1
2
3
4
5
6
7
8
.ai-ellipsis {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  -o-text-overflow: ellipsis;
  -moz-binding: url(<q>assets/xml/ellipsis.xml#ellipsis</q>);
}

这是我的SVG:

1
2
3
4
<g class="bar" transform="translate(0,39)">
    <text class="label" x="-3" y="6.5" dy=".35em" text-anchor="start">Construction</text>    
    <rect height="13" width="123"></rect>
</g>

生成如下:

1
2
3
4
5
6
barEnter.append("text").attr("class","label")
        .attr("x", -3).attr("y", function() { return y.rangeBand() / 2})
        .attr("dy",".35em").attr("text-anchor","start")
        .text(function(d) {
            return d.Name;
        });

当前文本溢出并与rect元素重叠。

我有没有办法说"如果文本超过了某个宽度,裁剪它并添加省略号"?


用于溢出文本的包装函数:

1
2
3
4
5
6
7
8
9
10
    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();
        }
    }

用途:

1
text.append('tspan').text(function(d) { return d.name; }).each(wrap);


我不知道SVG有一个等价的CSS类,但是您可以使用foreignObject将HTML嵌入到SVG中。这使您能够访问此功能,并且在一般情况下更加灵活(例如,您可以轻松地执行自动换行)。

请参阅此处以获取完整的示例。


我实现了一个不依赖于d3的本机函数,该函数实现了三种方式的回退:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 +"...";
    }
  }
}


1
2
3
4
function trimText(text, threshold) {
    if (text.length <= threshold) return text;
    return text.substr(0, threshold).concat("...");
}

使用此函数设置SVG节点文本。阈值的值(如20)取决于您。这意味着您将从节点文本中最多显示20个字符。超过20个字符的所有文本将被剪裁并在剪裁文本的末尾显示"…"。

用法,例如:

1
2
var self = this;
nodeText.text(x => self.trimText(x.name, 20)) // nodeText it's the text element of the SVG node


只是更新了由用户2846569提出的wrap函数。getComputedTextLength()通常非常慢,因此…

编辑

我努力应用了用户2846569的建议,并制作了一个"二进制"搜索版本,具有一定的校准和参数化精度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
'use strict';

var width = 2560;

d3.select('svg').attr('width', width);

// From http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript
function randomString(length, chars) {
    var result = '';
    for (var i = length; i > 0; --i)
        result += chars[Math.floor(Math.random() * chars.length)];
    return result;
}

function wrap() {
    var self = d3.select(this),
        textWidth = self.node().getComputedTextLength(),    // Width of text in pixel.
        initialText = self.text(),                          // Initial text.
        textLength = initialText.length,                    // Length of text in characters.
        text = initialText,
        precision = 10, //textWidth / width,                // Adjustable precision.
        maxIterations = 100; // width;                      // Set iterations limit.

    while (maxIterations > 0 && text.length > 0 && Math.abs(width - textWidth) > precision) {

        text = /*text.slice(0,-1); =*/(textWidth >= width) ? text.slice(0, -textLength * 0.15) : initialText.slice(0, textLength * 1.15);
        self.text(text + '...');
        textWidth = self.node().getComputedTextLength();
        textLength = text.length;
        maxIterations--;
    }
    console.log(width - textWidth);
}

var g = d3.select('g');

g.append('text').append('tspan').text(function(d) {
    return randomString(width, 'a');
}).each(wrap);

在jsFiddle上查看。