代码之家  ›  专栏  ›  技术社区  ›  Jack Roscoe

如何确定SVG文本框宽度,或强制在“x”字符后换行?

  •  28
  • Jack Roscoe  · 技术社区  · 14 年前

    我正在使用Raphael库创建一个SVG文本框,并用从XML文档中提取的动态字符串填充它。

    有时,此字符串比我放置文本框的画布长,因此我需要限制框的宽度,这将强制换行(我找不到任何可能的证据),或者确保在一定数量的字符后插入“\n”换行符。

    所以(1)这是最好的选择吗?我该怎么做?

    5 回复  |  直到 14 年前
        1
  •  47
  •   Mark    14 年前

    文本包装没有属性,但有一个简单的技巧可以使用。一次向文本对象添加一个单词,当它太宽时,添加换行符。可以使用getBBox()函数来确定宽度。基本上,你模仿的是老式打字机。下面是一些代码的示例,可以帮助您完成这项工作。您可以很容易地将其转换为一个简单的函数,该函数接受文本和宽度。

    var r = Raphael(500, 500);
    var t = r.text(100, 100).attr('text-anchor', 'start');
    var maxWidth = 100;
    
    var content = "Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate. ";
    var words = content.split(" ");
    
    var tempText = "";
    for (var i=0; i<words.length; i++) {
      t.attr("text", tempText + " " + words[i]);
      if (t.getBBox().width > maxWidth) {
        tempText += "\n" + words[i];
      } else {
        tempText += " " + words[i];
      }
    }
    
    t.attr("text", tempText.substring(1));
    
        2
  •  9
  •   Evan    13 年前

    谢谢你的回答。然而,我发现我需要一些调整来为我工作:

    function textWrap(t, width) {
        var content = t.attr("text");
        var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        t.attr({
          'text-anchor' : 'start',
          "text" : abc
        });
        var letterWidth = t.getBBox().width / abc.length;
        t.attr({
            "text" : content
        });
    
        var words = content.split(" ");
        var x = 0, s = [];
        for ( var i = 0; i < words.length; i++) {
    
            var l = words[i].length;
            if (x + (l * letterWidth) > width) {
                s.push("\n");
                x = 0;
            }
            x += l * letterWidth;
            s.push(words[i] + " ");
        }
        t.attr({
            "text" : s.join("")
        });
    }
    

    变化如下:

    • 需要使用的比较(l*letterwidth…)。。。不仅仅是我
    • if/else更改为if-这样换行符将始终将X设置为0
    • 始终将新的l*letterwidth添加到x值

    希望这有帮助。

        3
  •  3
  •   cancerbero    13 年前

    mark的解决方案对于大量文本来说速度很慢(firefox 11)。我认为这是因为文本被重新渲染了好几次以获得BBOX。以下函数对于大量文本更有效,但可能不太准确(代码来自 raphaelmarkup project ):

    /**
     * @param t a raphael text shape
     * @param width - pixels to wrapp text width
     * modify t text adding new lines characters for wrapping it to given width.
     */
    rm._textWrapp = function(t, width) {
        var content = t.attr("text");
        var abc="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        t.attr({'text-anchor': 'start', "text": abc});
        var letterWidth=t.getBBox().width / abc.length;
        t.attr({"text": content});
        var words = content.split(" "), x=0, s=[];
        for ( var i = 0; i < words.length; i++) {
            var l = words[i].length;
            if(x+l>width) {
                s.push("\n")
                x=0;
            }
            else {
                x+=l*letterWidth;
            }
            s.push(words[i]+" ");
        }
        t.attr({"text": s.join("")});
    };
    
        4
  •  0
  •   Carlos    11 年前

    好吧,我解决了,稍微调整一下

    var words = server.split( " " );
    var length = words.length;
    var temp_text = "";
    
    for( var i = 0; i < length; i++ ) {
        temp_text = temp_text + ' ' + words[i];
        t.attr( "text", temp_text );
    
        if( t.getBBox().width > width ) {
            temp_text = temp_text.replace(/( *)(\w+)$/, "\n$2");
        }
    }
    
    t.attr( "text", temp_text.trim() );
    
        5
  •  0
  •   Jimmy Breck-McKye    9 年前

    我知道现在有点晚了,但你可能对我的 Raphael-paragraph 自动执行此操作的项目。

    拉斐尔段落允许您创建具有最大宽度和高度限制、线条高度和文本样式配置的自动包装多行文本。它可以用连字符连接长单词,如果超过垂直边界,则将其截断。它仍然是相当测试版,需要很多优化,但它应该为您的目的工作。

    GitHub页面提供了使用示例和文档。