26

For fun I am trying to see how far I can get at implementing an SVG browser client for a RIA I'm messing around with in my spare time.

But have hit what appears to be a HUGE stumbling block. There is no word wrap!!

Does anyone know of any work around (I'm thinking some kind of JavaScript or special tag I don't know)?

If not I'm either going to have to go the xhtml route and start sticking HTML elements in my SVG (ouch), or just come back again in ten years when SVG 1.2 is ready.

Jonas
  • 121,568
  • 97
  • 310
  • 388
ChrisInCambo
  • 8,455
  • 15
  • 50
  • 63

8 Answers8

18

This SVG stuff is baffling, isn't it ?

Thankfully, you can achieve some good results, but it takes more work than using the HTML 5 .

Here's a screenshot of my ASP.Net / SVG app, featuring a bit of "faked" word wrapping.

enter image description here

The following function will create an SVG text element for you, broken into tspan pieces, where each line is no longer than 20 characters in length.

<text x="600" y="400" font-size="12" fill="#FFFFFF" text-anchor="middle">
    <tspan x="600" y="400">Here a realy long </tspan>
    <tspan x="600" y="416">title which needs </tspan>
    <tspan x="600" y="432">wrapping </tspan>
</text>

It's not perfect, but it's simple, fast, and the users will never know the difference.

My createSVGtext() JavaScript function takes three parameters: an x-position, y-position and the text to be displayed. The font, maximum-chars-per-line and text color are all hardcoded in my function, but this can be easily changed.

To display the right-hand label shown in the screenshot above, you would call the function using:

var svgText = createSVGtext("Here a realy long title which needs wrapping", 600, 400);
$('svg').append(svgText);

And here's the JavaScript function:

function createSVGtext(caption, x, y) {
    //  This function attempts to create a new svg "text" element, chopping 
    //  it up into "tspan" pieces, if the caption is too long
    //
    var svgText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    svgText.setAttributeNS(null, 'x', x);
    svgText.setAttributeNS(null, 'y', y);
    svgText.setAttributeNS(null, 'font-size', 12);
    svgText.setAttributeNS(null, 'fill', '#FFFFFF');         //  White text
    svgText.setAttributeNS(null, 'text-anchor', 'middle');   //  Center the text

    //  The following two variables should really be passed as parameters
    var MAXIMUM_CHARS_PER_LINE = 20;
    var LINE_HEIGHT = 16;

    var words = caption.split(" ");
    var line = "";

    for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + " ";
        if (testLine.length > MAXIMUM_CHARS_PER_LINE)
        {
            //  Add a new <tspan> element
            var svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
            svgTSpan.setAttributeNS(null, 'x', x);
            svgTSpan.setAttributeNS(null, 'y', y);

            var tSpanTextNode = document.createTextNode(line);
            svgTSpan.appendChild(tSpanTextNode);
            svgText.appendChild(svgTSpan);

            line = words[n] + " ";
            y += LINE_HEIGHT;
        }
        else {
            line = testLine;
        }
    }

    var svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
    svgTSpan.setAttributeNS(null, 'x', x);
    svgTSpan.setAttributeNS(null, 'y', y);

    var tSpanTextNode = document.createTextNode(line);
    svgTSpan.appendChild(tSpanTextNode);

    svgText.appendChild(svgTSpan);

    return svgText;
}

The logic for word-wrapping is based on this HTML5 Canvas tutorial

I hope you find this useful !

Mike

http://www.MikesKnowledgeBase.com

UPDATE

One thing I forgot to mention.

That "Workflow diagram" screen that I've shown above was originally just written using an HTML 5 canvas. It worked beautifully, the icons could be dragged, popup menus could appear when you clicked on them, and even IE8 seemed happy with it.

But I found that if the diagram became "too big" (eg 4000 x 4000 pixels), then the would fail to initialise in all browsers, nothing would appear - but - as far as the JavaScript code was concerned, everything was working fine.

So, even with error-checking, my diagram was appearing blank, and I was unable to detect when this showstopper problem was occurring.

var canvasSupported = !!c.getContext;
if (!canvasSupported) {
    //  The user's browser doesn't support HTML 5 <Canvas> controls.
    prompt("Workflow", "Your browser doesn't support drawing on HTML 5 canvases.");
    return;
}

var context = c.getContext("2d");
if (context == null) {
    //  The user's browser doesn't support HTML 5 <Canvas> controls.
    prompt("Workflow", "The canvas isn't drawable.");
    return;
}

//  With larger diagrams, the error-checking above failed to notice that
//  the canvas wasn't being drawn.

So, this is why I've had to rewrite the JavaScript code to use SVG instead. It just seems to cope better with larger diagrams.

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
  • Ah heck, I can't spell "really" today!! Perhaps I should modify my function to do some spell-checking on my captions ! – Mike Gledhill Jul 25 '13 at 08:48
  • 1
    Have used this on my own project today, thanks Mike, worked flawlessly! – JasonMHirst Jun 19 '15 at 12:12
  • Cool, good stuff. (Isn't life easier, when there's a working example you can borrow !!) – Mike Gledhill Jun 19 '15 at 12:21
  • @MikeGledhill you bring up a good point. SVG diagrams render much smoother than HTML ones. Maybe because some browsers use GPU for SVG rendering. https://developer.chrome.com/blog/hardware-accelerated-animations/ – user160357 Jul 25 '22 at 11:30
  • 1
    Great solution. I love it! I´m trying to insert the result of the function into a larger SVG element that adds a rect, etc: I´m doing this: var svgText = createSVGtext('{{ thisMarker[3] }}',50,70); var svgMarkup = '' + ' + svgText + ''; but I get: '[object SVGTextElement]' Any ideas? I´m quite new to SVG and JS. Thanks a lot! – PiBer2 Aug 28 '22 at 13:38
  • @PiBer2 Im getting this too... did you figure it out? I guess its not rendering the svg object for outerText and innerText and and just trys to display the entire object which it cant render. – Tom Rudge Oct 26 '22 at 19:09
17

There is also foreignObject tag. Then you can embed HTML in SVG which gives the greatest flexibility. HTML is great for document layout and has been hacked to no end to support application layout, drawing, and everything us developers want. But it's strength is word wrapping and document layout. Let HTML do what it does best, and let SVG do what it does best.

http://www.w3.org/TR/SVG/extend.html

This works for most browsers FireFox, Opera, Webkit, except IE (as of IE11). :-( Story of the web ain't it?

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
11

SVGT 1.2 introduces the textArea element http://www.w3.org/TR/SVGTiny12/text.html#TextInAnArea , but it is only experimentally supported by Opera 10 at the moment. I don't know if other browsers will ever plan on implementing it, though I hope they will.

codedread
  • 1,312
  • 11
  • 18
10

Per this document, it appears that tspan can give the illusion of word wrap:

The tspan tag is identical to the text tag but can be nested inside text tags and inside itself. Coupled with the 'dy' attribute this allows the illusion of word wrap in SVG 1.1. Note that 'dy' is relative to the last glyph (character) drawn.

David Segonds
  • 83,345
  • 10
  • 45
  • 66
  • 1
    David, thanks for your response. I saw TSPAN, and also found a script here to take care of things dynamically - http://www.xml.com/pub/a/2002/09/11/quint.html – ChrisInCambo Jan 24 '09 at 10:00
2

The svg.js library has a svg.textflow.js plugin. It's not ultra fast but it does the trick. It even stores overflowing text in a data attribute so you can use it to create continuously flowing columns. Here the text flow example page.

wout
  • 2,477
  • 2
  • 21
  • 32
  • Link broken. Appears you've merged it into svg.js? https://github.com/wout/svg.js – Steve Bennett Jan 29 '14 at 06:09
  • I've stopped development on this plugin and went another route. The plugin is still available here: https://gist.github.com/wout/6352742 – wout Jan 29 '14 at 09:18
0

I've been looking for a solution about word wrapping in svg so many hours (or many days). If you can in your app, edit your code to put some tspan, or any other method, go in it.

Text wrapping will be implement in the 1.2 version but except opera, no browser fully implement it yet (4 years, the specification are on the W3 ...).

Because I had to use some alignment settings, i couldn't use any of the code that many forum can provide (no foreign object, no carto script or anything).

If I post this message, it's just in order to be usefull to some other people when googling word wrapping svg because this post on the top result and in many case, this post doesn't help.

Here is a cool, easy and light solution : http://dev.w3.org/SVG/profiles/1.1F2/test/svg/text-dom-01-f.svg

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
mickael
  • 1
  • 1
0

An alternative method is to use Andreas Neuman's text box object.

eft
  • 2,509
  • 6
  • 26
  • 24
0

These days, flowPara can do word wrapping, but I have yet to find a browser that supports it properly.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • No, `flowPara` was part of the SVG 1.2 draft but SVG 1.2 was never released, and it wasn't part of SVG 1.1, or SVG Tiny 1.2, or SVG 2. – Fred Jan 30 '23 at 20:56