Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to either determine SVG text box width, or force line breaks after 'x' characters?

I'm creating an SVG text box using the Raphael library, and filling it with a dynamic string which is extracted from an XML document.

Sometimes, this string is longer than the canvas I am placing the text box on, so I need to either limit the width of the box which will itself force the line breaks (I can't find any evidence of this being possible) OR ensure that a '\n' line break is inserted after a certain amount of characters.

So (1) is this the best option? And (2) how would I do this?

like image 550
Jack Roscoe Avatar asked Jun 29 '10 15:06

Jack Roscoe


People also ask

How can I get SVG text width?

var bbox = textElement. getBBox(); var width = bbox. width; var height = bbox.

How do I put text inside an SVG path?

The <textPath> SVG element is used to render the text along with a certain path. To render text along with a certain path, enclose the text in an <textPath> element that has a href attribute with a reference to the <path> element. Attribute: href: The URL to the path or basic shape on which to render the text.

Does SVG support text?

The SVG <text> element draws a graphics element consisting of text. It's possible to apply a gradient, pattern, clipping path, mask, or filter to <text> , like any other SVG graphics element. If text is included in SVG not inside of a <text> element, it is not rendered.


2 Answers

There isn't an attribute for text wrapping, but there is a simple trick you can use. Add one word at a time to a text object and when it gets too wide, add a line feed. You can use the getBBox() function to determine the width. Basically, you emulate an old fashioned typewriter. Here is a sample of some code that will do this for you. You could easily turn this into a simple function that takes the text and a width.

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)); 
like image 166
Mark Avatar answered Sep 19 '22 15:09

Mark


thanks for the answer. However, I found that I needed a few adjustments to work for me:

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

The changes were:

  • the comparison needed to use (l * letterwidth) ... not just l
  • the if/else changed to just an if - so that a line break will always set X to 0
  • and always add the new l * letterwidth to the x value

hope this helps.

like image 26
Evan Avatar answered Sep 21 '22 15:09

Evan