SVG:使用getComputedTextLength来换行文本

14

我试图通过构建文本字符串并使用getComputedTextLength来确定文本是否超出允许的宽度,以实现文本换行。然而,我找不到一种简单的方法来逐步构建文本,并且能够与getComputedTextLength配合使用。

总的想法是:

  str = svgDocument.createTextNode(myText[word]); // first word on new line
  word++;
  obj = text.cloneNode(true);                     // new text element for this line
  obj.appendChild(str);
  svgDocument.documentElement.appendChild(obj);   // reqd for getComputedTextLength?
  for( ; word < myText.length; word++) {
     next_width = obj.getComputedTextLength();    // get current line width
     if(next_width >= extent)
        break;
     str += " ";                                  // add next word to the line
     str += myText[word];
     ...
  }

有人能告诉我如何让这个工作起来吗?假设str是复制而不是在obj中被引用的,但是我也尝试了将obj.removeChild(str)obj.appendChild(str)放在循环中,但是appendChild会崩溃。我还尝试过各种组合,移动documentElement.appendChild,删除obj并重新附加它等等。

2个回答

21
这应该可以运行:
    var svgNS = "http://www.w3.org/2000/svg";
    var width = 200;

    function init(evt)
    {
        if ( window.svgDocument == null ) {
            svgDocument = evt.target.ownerDocument;
        }
        create_multiline("Whatever text you want here.");
    }

    function create_multiline(text) {
        var words = text.split(' ');                        
        var text_element = svgDocument.getElementById('multiline-text');
        var tspan_element = document.createElementNS(svgNS, "tspan");   // Create first tspan element
        var text_node = svgDocument.createTextNode(words[0]);           // Create text in tspan element

        tspan_element.appendChild(text_node);                           // Add tspan element to DOM
        text_element.appendChild(tspan_element);                        // Add text to tspan element

        for(var i=1; i<words.length; i++)
        {
            var len = tspan_element.firstChild.data.length;             // Find number of letters in string
            tspan_element.firstChild.data += " " + words[i];            // Add next word

            if (tspan_element.getComputedTextLength() > width)
            {
                tspan_element.firstChild.data = tspan_element.firstChild.data.slice(0, len);    // Remove added word

                var tspan_element = document.createElementNS(svgNS, "tspan");       // Create new tspan element
                tspan_element.setAttributeNS(null, "x", 10);
                tspan_element.setAttributeNS(null, "dy", 18);
                text_node = svgDocument.createTextNode(words[i]);
                tspan_element.appendChild(text_node);
                text_element.appendChild(tspan_element);
            }
        }


    }
]]>
</script>

<text x="10" y="50" id="multiline-text"> </text>

它的工作原理是向文本元素添加tspan元素,然后向每个tspan元素添加文本。

结果类似于:

<text>
  <tspan>Whatever text</tspan>
  <tspan>you want here.</tspan>
</text>
为了让getComputerTextLength工作,您需要先创建tspan(或文本)元素,并确保它在DOM中。此外,请注意,在向tspan元素添加文本时,您需要使用createTextNode()方法并将结果附加到元素上。

嗨Peter - 谢谢你的代码。今天我看了一下我的原始代码,发现我的基本问题是不理解如何在文本节点中增加文本。我用appendChild实现了基本的换行,但你的tspan方法看起来很好 - 我会去看看的。谢谢 - Al - EML
很酷 - tspans 很有用,因为这意味着您可以一次选择多行文本。 - Peter Collingridge
7年后仍然有用,我想这既是好事也是坏事! - kiminoa

4

一个用于处理文本溢出的包装函数:

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

1
OP代表什么? - user2846569
1
原帖作者。D3代表什么? :) - EML
4
D3是一个用于操作SVG的JavaScript库。@RobertLongson,不仅仅是楼主在阅读这个内容,还有其他需要解决方案的人,甚至像我一样使用D3的人。祝好! - user2846569
1
使用纯JS / DOM的问题仍然使用jQuery代码片段回答,但我看到的第一个使用d3.js回答的问题受到批评。用户2846569的答案很有用,因为1)对于对该主题感兴趣的d3用户,他的答案可能很有用,如果他们首先看到这个答案,2)核心d3.js可以被称为“类固醇上的SVG的jQuery” - d3用户和那些需要在SVG中进行文本截断的人之间有很大的重叠; 3)OP或读者可能会学习到,在OP的问题中,相当长,命令式,交织在一起的代码可能可以用更具声明性的d3库来替代。 - Robert Monfera
1
似乎需要SVG可见:例如,如果它被某些具有"display:none;"的东西包裹,则"getComputedTextLength()"将返回0。这是我的浏览器行为。有人可以确认吗? - Nate Anderson
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接