2010-06-29 7 views
28

Ich erstelle ein SVG-Textfeld mit der Raphael-Bibliothek und fülle es mit einer dynamischen Zeichenfolge, die aus einem XML-Dokument extrahiert wird.Wie kann man entweder die Breite des SVG-Textfelds bestimmen oder Zeilenumbrüche nach 'x'-Zeichen erzwingen?

Manchmal ist diese Zeichenfolge länger als die Zeichenfläche, auf der ich die Textbox anlege, also muss ich entweder die Breite der Box begrenzen, was wiederum die Zeilenumbrüche erzwingt (ich kann keinen Beweis dafür finden) möglich) ODER stellen Sie sicher, dass nach einer bestimmten Anzahl von Zeichen ein '\ n' Zeilenumbruch eingefügt wird.

Also (1) ist das die beste Option? Und (2) wie würde ich das tun?

Antwort

46

Es gibt kein Attribut für den Textumbruch, aber es gibt einen einfachen Trick, den Sie verwenden können. Fügen Sie einem Textobjekt jeweils ein Wort hinzu, und fügen Sie einen Zeilenvorschub hinzu, wenn dieser zu groß wird. Sie können die Funktion getBBox() verwenden, um die Breite zu bestimmen. Im Grunde emulieren Sie eine altmodische Schreibmaschine. Hier ist ein Beispiel für Code, der das für Sie erledigt. Sie könnten dies leicht in eine einfache Funktion umwandeln, die den Text und eine Breite übernimmt.

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 Kumpel du hast den Tag gerettet! – chchrist

+0

Ich habe eine Bibliothek geschrieben, die im Wesentlichen genau das, Raphael-Absatz genannt. Siehe meine Antwort unten. –

3

Marke Lösung ist langsam für große Mengen von Text (firefox 11). Ich denke, das liegt daran, dass der Text mehrfach für BBOX gerendert wird. die folgende Funktion ist effizienter für große Mengen von Text, aber vielleicht weniger genau (Code aus 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

Schön, aber 'if (x + l> width) {' sieht wie ein Fehler aus - behandelt die durchschnittliche Buchstabenbreite des letzten Wortes in jedem Test als 1px. Funktioniert viel besser, wenn Sie die 'else'-Klausel verlieren und' x + = l * letterWidth; 'am Anfang jeder' for'-Schleife setzen. Auch "Text-Anker": "Start", "ist unnötig - keine Notwendigkeit, Linksbündigkeit erzwingen.** edit ** habe gerade gesehen, dass Evans Antwort diese berücksichtigt und auf diesen Code reagiert, nicht auf Marks. – user568458

9

Dank für die Antwort. Allerdings fand ich, dass ich ein paar kleine Anpassungen, die für mich zu arbeiten:

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

Die Veränderungen waren:

  • den Vergleich benötigt (l * letterwidth) verwenden ... nicht nur l
  • die if/else nur, wenn ein geändert - so dass ein Zeilenumbruch immer x auf 0
  • gesetzt wird und immer die neuen l * letterwidth auf den Wert x in

hoffe das hilft.

+1

Danke dafür - obwohl ich mir nicht sicher bin, warum du diesen Code oben brauchst: ''text-anchor': 'start''. Ich habe das entfernt und es schien gut zu funktionieren und meine ursprüngliche Formatierung beizubehalten. – rwalter

+1

+1 Dies ist eine Verbesserung des Cancerbero-Codes und die beste Option auf der Seite, wenn die Leistung ein Faktor ist. Eine mögliche Verbesserung: Die Buchstabenbreite ist pro Schriftart und Schriftgröße konstant. Wenn Sie also große Textmengen verwenden, können Sie eine bescheidene Leistungssteigerung erzielen, indem Sie die Buchstabenbreite in einer geeigneten Variablen speichern, anstatt sie erneut zu berechnen der Text attr schaltet für jedes Element. Ich würde empfehlen, sie in einem Objekt zu speichern, das nach Schriftart und Schriftgröße sortiert ist. – user568458

0

Nun, ich löste es ihm ein wenig zwicken

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

Ich weiß es jetzt ein wenig spät ist, aber Sie könnten in meinem Raphael-paragraph Projekt interessiert sein, die dies automatisch tun.

Raphael-Absatz ermöglicht es Ihnen, automatisch umgebrochenen mehrzeiligen Text mit maximalen Beschränkungen für Breite und Höhe, Zeilenhöhe und Textstilkonfiguration zu erstellen. Lange Wörter können abgeschnitten und abgeschnitten werden, wenn sie die vertikalen Grenzen überschreiten. Es ist immer noch ziemlich beta-ish und erfordert eine Menge Optimierung, aber es sollte für Ihre Zwecke funktionieren.

Anwendungsbeispiele und Dokumentation finden Sie auf der GitHub-Seite.