30 Stimmen

Wie kann man entweder die Breite von SVG-Textfeldern bestimmen oder Zeilenumbrüche nach 'x' Zeichen erzwingen?

Ich erstelle ein SVG-Textfeld mit der Raphael-Bibliothek und fülle es mit einer dynamischen Zeichenfolge, die aus einem XML-Dokument extrahiert wird.

Manchmal ist diese Zeichenfolge länger als die Leinwand, auf der ich das Textfeld platziere, so dass ich entweder die Breite des Feldes begrenzen muss, was selbst die Zeilenumbrüche erzwingt (ich kann keinen Hinweis darauf finden, dass dies möglich ist) ODER sicherstellen, dass ein ' \n ' wird nach einer bestimmten Anzahl von Zeichen ein Zeilenumbruch eingefügt.

Ist dies also (1) die beste Option? Und (2) wie würde ich das machen?

48voto

Mark Punkte 5291

Es gibt kein Attribut für den Textumbruch, aber es gibt einen einfachen Trick, den Sie anwenden können. Fügen Sie ein Wort nach dem anderen in ein Textobjekt ein, und wenn es zu breit wird, fügen Sie einen Zeilenumbruch hinzu. Sie können die Funktion getBBox() verwenden, um die Breite zu bestimmen. Im Grunde emulieren Sie damit eine altmodische Schreibmaschine. Hier ist ein Beispiel für einen Code, der dies für Sie erledigt. Sie könnten dies leicht in eine einfache Funktion umwandeln, die den Text und eine Breite annimmt.

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

9voto

Evan Punkte 101

Danke für die Antwort. Allerdings habe ich festgestellt, dass ich ein paar Anpassungen benötigt, um 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 Änderungen waren:

  • der Vergleich musste (l * Buchstabenbreite) ... nicht nur l verwenden
  • das if/else wurde in ein if geändert, so dass ein Zeilenumbruch X immer auf 0 setzt
  • und addieren Sie immer den neuen Wert l * letterwidth zum x-Wert

Ich hoffe, das hilft.

3voto

cancerbero Punkte 6226

Die Lösung von Mark ist bei großen Textmengen langsam (Firefox 11). Ich denke, das liegt daran, dass der Text mehrmals neu gerendert wird, um BBOX zu erhalten. Die folgende Funktion ist effizienter für große Textmengen, aber vielleicht weniger genau (Code von raphaelmarkup projekt ):

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

0voto

Carlos Punkte 192

Nun, ich habe es gelöst, indem ich es ein wenig optimiert habe

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

0voto

Jimmy Breck-McKye Punkte 2893

Ich weiß, es ist etwas verspätet, aber vielleicht interessiert Sie mein Raphael-Paragraph Projekt, das dies automatisch tut.

Mit Raphael-paragraph können Sie automatisch umbrochenen mehrzeiligen Text mit maximalen Breiten- und Höhenbeschränkungen, Zeilenhöhe und Textstilkonfiguration erstellen. Es kann lange Wörter mit Bindestrich trennen und sie abschneiden, wenn sie vertikale Grenzen überschreiten. Es befindet sich noch in der Beta-Phase und muss noch optimiert werden, aber für Ihre Zwecke sollte es funktionieren.

Beispiele für die Verwendung und die Dokumentation finden Sie auf der GitHub-Seite.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X