2

My app is dependent on the conversion of some HTML text elements into SVG elements, using Raphael.js.

The text in those HTML objects is given by the user, via a textarea input. Therefore, they can input new lines too. And those new lines need to be accounted for when creating the SVG. For this, I use the following code:

function replaceNL(text) {      
    return text.replace(/[\n\r]/g, "\n");
}

And when adding the SVG to the page:

var obj = paper.text(x,y,replaceNL(this.text));

The problem I've come across is that double (or more) line breaks strings (e.g. "\n\n") have the effect of just one in the .text() method. How can I overcome this?

Andrei Oniga
  • 8,219
  • 15
  • 52
  • 89

1 Answers1

4

This question does come up periodically... (http://stackoverflow.com/questions/12155954/nbsp-in-raphael-js)

If you modify your paper element to preserve spaces, all of the text elements within it will behave in the way you want. Do it like this:

paper.canvas.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space","preserve");

Here's the caveat: Raphael splits the strings passed to text on newlines, and inserts each segment into its own tspan. When the SVG rendering evaluates the tspans, it is sequencing each based on the bounding box of its predecessors. Because an empty tspan has a 0x0 bounding box, the newline -- though emitted -- is functionally invisible.

The rough workaround would be to emit "\n \n" -- the space character produces a bounding box, and thus causes the extra newline to be rendered. Sanity test here.

To control the height of the line breaks between tspans, you need to modify their dy attributes. Raphael does not support this out of the box, but it's easy to write a javascript function to set these manually. Here's the jquery method, given a Raphael text element textElement and your desired spacing, in pixels, as spacing:

$(textElement.node).find( 'tspan' ).attr( 'dy', spacing );
Kevin Nielsen
  • 4,413
  • 21
  • 26
  • I called the `setAttributesNS` method for my SVG canvas like so: `this.canvas = new Raphael(this.elements.ow, this.width, this.height); this.canvas.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space","preserve");`, but I got this error: `Uncaught TypeError: Object # has no method 'setAttributeNS'`. – Andrei Oniga Oct 30 '12 at 19:14
  • I changed the second line to `this.canvas.canvas.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space","preserve");` and the error disappeared, but there was no effect. Multiple new lines still appear as one. :( – Andrei Oniga Oct 30 '12 at 19:16
  • Check out my update. You would still need to fudge slightly by replacing "\n\n" with "\n \n." – Kevin Nielsen Oct 30 '12 at 19:27
  • Fantastic! I changed the function to `return text.replace(/[\n\r]/g, "\n ");`, which rendered the empty tspan visible. BUT, there's another problem now. The line height of the created SVG is not the same as it is in the HTML element :( Any ideas on how to work around this? Please check out [picselbocs.com/projects/cakemyface](http://picselbocs.com/projects/cakemyface/) for a live example (go to 'Customisation' tab to add text object, then click on the 'rotate' icon next to the new object - it is then converted to SVG). – Andrei Oniga Oct 30 '12 at 19:31
  • Another update. I think this might actually do what you need it to =) – Kevin Nielsen Oct 30 '12 at 20:15
  • I'm afraid that it didn't solve the problem, the empty `tspan`'s are still rendered invisible :( – Andrei Oniga Oct 31 '12 at 18:20
  • You'll still need to fudge the line breaks for this to work, I fear. All the latest addition does it to change the dy of non-empty tspans =) It's actually moderately amazing that nobody else has complained about this -- at least that I've seen. But most of my work with multiline text has been handled manually, by making repeated calls to text (or print) and pushing each element into a set. – Kevin Nielsen Oct 31 '12 at 18:29
  • I realize that I wasn't clear enough, sorry. The main problem is that the first empty line is rendered visible, but any others besides that one aren't. For instance, if I were to create 3 empty lines, only 1 would be rendered visible, the other 2 wouldn't be. The good thing (at least so it seems) is that the dy attribute solves the issue of the line height, but a problem still remains with rendering multiple `newlines`. Any ideas? – Andrei Oniga Oct 31 '12 at 18:49
  • I guess it would be possible (theoretically at least) to give the first `tspan` encountered a height equal to the desired line spacing, multiplied with the number of line breaks. But from the start I can say this is severely cumbersome. If you have a more straightforward suggestion, I'd appreciate your help! – Andrei Oniga Oct 31 '12 at 18:54
  • OK, please discard my last messages. Your idea worked, but unfortunately it isn't cross-browser comliant. Firefox does the job as it's supposed to, for example, but Chrome eats up the newlines. And IE9, for some reason, doesn't show anything at all... – Andrei Oniga Oct 31 '12 at 20:14