SVG: использование getComputedTextLength для переноса текста

Я пытаюсь обернуть текст, getComputedTextLength текстовую строку и используя 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 повторного добавления и так далее.

Ответ 1

Это должно работать:         

    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 в текстовый элемент, а затем добавляя текст к каждому из них.

Результат выглядит примерно так:

<text>
  <tspan>Whatever text</tspan>
  <tspan>you want here.</tspan>
</text>

Чтобы работать с getComputerTextLength, сначала необходимо создать элемент tspan (или text) и убедиться, что он находится в DOM. Также обратите внимание, что для добавления текста в элемент tspan вам необходимо использовать createTextNode() и добавить результат.

Ответ 2

функция обертки для переполнения текста:

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