2010-06-29 23 views
28

我使用Raphael庫創建SVG文本框,並使用從XML文檔中提取的動態字符串填充該文本框。如何確定SVG文本框的寬度,或在'x'字符後強制換行符?

有時候,這個字符串比我放置文本框的畫布長,所以我需要限制盒子的寬度,它本身會強制換行(我找不到任何這個存在的證據可能)或確保在一定數量的字符後插入'\ n'換行符。

所以(1)這是最好的選擇嗎? (2)我會如何做到這一點?

回答

46

沒有文字環繞的屬性,但有一個簡單的技巧可以使用。一次向文本對象添加一個單詞,當它太寬時,添加一個換行符。您可以使用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)); 
+0

Thnx隊友你救了一天! – chchrist 2011-11-11 13:56:02

+0

我已經寫了一個圖書館,基本上做到這一點,命名爲拉斐爾段。請參閱下面的答案。 – 2015-06-21 15:08:32

3

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("")}); 
}; 
+0

不錯,但'if(x + l> width){'看起來像一個錯誤 - 它將每個測試中最後一個單詞的平均字母寬度視爲1px。如果在每個for循環的開始處丟失'else'子句並放入'x + = l * letterWidth;',則效果會更好。另外''文本錨':'開始','是不必要的 - 不需要強制左對齊。**編輯**剛剛看到埃文的回答考慮到了這些問題,並且迴應了這段代碼,而不是馬克的迴應。 – user568458 2012-12-17 10:52:43

9

感謝您的回答。然而,我發現,我需要一些調整,爲我工作:

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語句改爲只是如果 - 這樣一個換行符將始終設置X 0
  • ,總是新的L * letterwidth添加到x值

希望這有助於。

+1

感謝您的支持 - 儘管我不確定爲什麼您需要在頂部使用此代碼:''text-anchor':'start''。我刪除了這個,它似乎工作正常,並保留我原來的格式。 – rwalter 2012-08-02 11:10:09

+1

+1如果性能是一個因素,這是癌症病毒代碼和頁面上最佳選項的改進。一種可能的改進:字體寬度在字體和字體大小不變的情況下保持不變,因此如果您在大量文本中運行該字體,可以將字母寬度存儲在適當的作用域變量中,而不是重新計算,從而獲得適度的性能提升文本attr切換每個元素。我建議將它存儲在一個對象中,以font-family和font-size爲鍵。 – user568458 2012-12-17 10:58:30

0

嗯,我解決它調整它一點點

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

我知道它現在是有點慢半拍,但你可能有興趣在我Raphael-paragraph項目,它會自動完成。

Raphael-paragraph允許您創建具有最大寬度和高度約束,行高和文本樣式配置的自動包裝多行文本。如果它們超過垂直邊界,它可以連字符連字符並截斷它們。它仍然是一個測試版,需要很多優化,但它應該適用於您的目的。

GitHub頁面上提供了使用示例和文檔。

相關問題