SVG Essentials/Text

From WikiContent

< SVG Essentials
Revision as of 23:40, 6 March 2008 by Evanlenz (Talk | contribs)
Jump to: navigation, search
SVG Essentials

While it may be true that every picture tells a story, it's perfectly all right to use words to help tell the story. Thus, SVG has several elements that let you add text to your graphics.


Text Terminology

Before we investigate the primary method of adding text, the <text> element, we should define some terms you'll see if you read the SVG specification or if you work with text in any graphic environment:

A character, as far as an XML document is concerned, is a byte or bytes with a numeric value according to the Unicode standard. For example, what we call the letter "g" is the character with Unicode value 103.

A glyph is the visible representation of a character or characters. A single character can have many different glyphs to represent it. Figure 8-1 shows the word "glyphs" written with two different sets of glyphs — look particularly at the initial "g" — it's the same character, but the glyphs are markedly different.

Figure 8-1. Two sets of glyphs

Two sets of glyphs

Multiple characters can reduce to a single glyph; some fonts have separate glyphs for the letter combinations "fl" and "ff" to make their spacing look better (these are called ligatures). Other times, a single character can be composed of multiple glyphs; a print program might create the character é (which has Unicode value 233) by combining the "e" glyph with a non-spacing accent mark "´".

A collection of glyphs representing a certain set of characters. All the glyphs in a font will normally have the following characteristics in common:

Baseline, ascent, and descent
All the glyphs in a font line up on the baseline. The distance from the baseline to the top of the character is the ascent; the distance from the baseline to the bottom of the character is the descent. The total height of the character is also called the em-height. The em-box is a square that has a width as large as an em-height.

The upper dotted line in Figure 8-2 is used to determine the cap-height, which is the height of a capital letter above the baseline. The lower dotted line is used to determine the ex-height, which, logically enough, is the distance from the baseline to the top of a lower case letter "x."

Figure 8-2. Glyph measurements

Glyph measurements

Simple Attributes and Properties of the text Element

The simplest form of the <text> element requires only two attributes, x and y, which define the point where the baseline of the first character of the element's content is placed. The default style for text, as with all objects, is to have a fill color of black and no outline. This, as it turns out, is precisely what you want for text. If you set the outline as well as the fill, the text looks uncomfortably thick. If you set only the outline, you can get a fairly pleasant set of outlined glyphs, especially if you lower the stroke width. Example 8-1 uses the placement and stroke/fill characteristics for <text>; the result is Figure 8-3.

Example 8-1. Text placement and outlining

<!-- guide lines -->
<path d="M 20 10, 20 120 M 10 30 100 30 M 10 70 100 70
   M 10 110 100 110" style="stroke: gray;"/>

<text x="20" y="30">Simplest Text</text>
<text x="20" y="70" style="stroke: black;">Outlined/filled</text>
<text x="20" y="110" style="stroke: black; stroke-width: 0.5;
    fill: none;">Outlined only</text>

Figure 8-3. Text placement and outlining

Text placement and outlining

Many of the other properties that apply to text are the same as they are in the Cascading Style Sheets standard. The following is a list of the CSS properties and values that are implemented in the Apache Batik viewer version 1.0:

The value is a whitespace-separated list of font family names or generic family names. The generic family names are serif, sans-serif, and monospace. Serif fonts have little "hooks" at the ends of the strokes; sans-serif fonts don't. In Figure 8-1, the word at the left is in a serif font and the word on the right is in a sans-serif font. Both serif and sans-serif fonts are proportional; the width of a capital M is not the same as the width of a capital I. A monospace font, which may or may not have serifs, is one where all the glyphs have the same width, like the letters of a typewriter.
The value is the baseline-to-baseline distance of glyphs if you were to have more than one line of text. (In SVG, you can't have multi-line <text> content, so the concept is somewhat abstract.) If you use units on this attribute, as in style="font-size: 18pt", the eighteen-point size will be converted to user units before being rendered, so it can be affected by transformations.
The two most commonly used values of this property are bold and normal. You need the normal value in case you want to place non-bold text in a group that has been set to style="font-weight: bold".
The two most commonly used values of this property are italic and normal.
Possible values of this property are none, underline, overline, and line-through.
The value of this property is a length, either in explicit units such as pt or in user units. Make this a positive number to increase the space between words, set it to normal to keep normal space, or make it negative to tighten up the space between words. The length you specify is added to the normal spacing.
The value of this property is a length, either in explicit units such as pt or in user units. Make this a positive number to increase the space between individual letters, set it to normal to keep normal space, or make it negative to tighten up the space between letters. The length you specify is added to the normal spacing.

Example 8-2 uses these styles to produce Figure 8-4, with effects you'd expect from any competent text application.

Example 8-2. Text weight, style, decoration, and spacing attributes

<g style="font-size: 18pt">
<text x="20" y="20" style="font-weight:bold;">bold</text>
<text x="120" y="20" style="font-style:italic;">italic</text>
<text x="20" y="60" style="text-decoration:underline;">under</text>
<text x="120" y="60" style="text-decoration:overline;">over</text>
<text x="200" y="60" 
<text x="20" y="90" style="word-spacing: 10pt;">more word space</text>
<text x="20" y="120" style="word-spacing: -3pt;">less word space</text>
<text x="20" y="150" style="letter-spacing: 5pt;">wide letter space</text>
<text x="20" y="180" style="letter-spacing: -2pt;">narrow letter space</text>

Figure 8-4. Text weight, style, decoration, and spacing

Text weight, style, decoration, and spacing

Text Alignment

The <text> element lets you specify the starting point, but you don't know, a priori, its ending point. This would make it difficult to center or right-align text, were it not for the text-anchor property. You set it to a value of start, middle, or end. For fonts that are drawn left-to-right, these are equivalent to left, center, and right alignment. For fonts that are drawn in other directions (see Section 8.7) these have a different effect. Example 8-3 shows three text strings, all starting at an x-location of 100, but with differing values of text-anchor. A guide line is drawn to show the effect more clearly in the result, Figure 8-5.

Example 8-3. Use of text-anchor

<g style="font-size: 14pt;">
<path d="M 100 10 100 100" style="stroke: gray; fill: none;"/>
<text x="100" y="30" style="text-anchor: start">Start</text>
<text x="100" y="60" style="text-anchor: middle">Middle</text>
<text x="100" y="90" style="text-anchor: end">End</text>

Figure 8-5. Result of using text-anchor

Result of using text-anchor

The tspan element

Another consequence of not knowing a text string's length in advance is that it is difficult to construct a string with varying text attributes, such as this sentence, which switches among italic, normal, and bold text. If you had only the <text> element, you'd need to experiment to find where each differently styled segment of text ended in order to space them properly. To solve this problem, SVG provides the <tspan>, or text span element. Analogous to the XHTML <span> element, <tspan> is a tabula rasa that may be embedded in text content, and upon which you may impose style changes. The <tspan> remembers the text position, so you don't have to. Thus, Example 8-4, which produces the display in Figure 8-6.

Example 8-4. Using tspan to change styles

<text x="10" y="30" style="font-size:12pt;">
    Switch among
    <tspan style="font-style:italic">italic</tspan>, normal,
    and <tspan style="font-weight:bold">bold</tspan> text.

Figure 8-6. Styles changed with tspan

Styles changed with tspan

In addition to changing presentation properties such as font size, color, weight, etc., you can also use attributes with <tspan> to change the positioning of individual letters or sets of letters. If, for example, you want superscripts or subscripts, you can use the dy attribute to offset characters within a span. The value you assign to this attribute is added to the vertical position of the characters, and continues to affect text even outside the span. Negative values are allowed. A similar attribute, dx, offsets characters horizontally. Example 8-5 uses vertical offsets to create the "falling letters" in Figure 8-7.

Example 8-5. Using dy to change vertical positioning within text

<text x="10" y="30" style="font-size:12pt;">
    F <tspan dy="4">a</tspan>
    <tspan dy="8">l</tspan>
    <tspan dy="12">l</tspan>

Figure 8-7. Vertical positioning with dy

Vertical positioning with dy

If you wish to express the offsets in absolute terms rather than relative terms, you use the x and y attributes. This is handy for doing multi-line runs of text. In fact, you must do it this way, since, as you will see in Section 8.9, SVG never displays newline characters in text. (The lack of a newline will be remedied in SVG 1.1.) If your SVG viewer allows text selection, putting multiple lines into a single <text> element, as we have done in Example 8-6 will allow the selection to include all the lines. You should always use <tspan>s within a <text> element to group related lines, not only to allow them to be selected as a unit, but also because it adds structure to your document.

Example 8-6. Use of absolute positioning with tspan

<text x="10" y="30" style="font-size:12pt;">
    They dined on mince, and slices of quince,
    <tspan x="20" y="50">Which they ate with a
        runcible spoon;</tspan>
    <tspan x="10" y="70">And hand in hand, on the edge
        of the sand,</tspan>
    <tspan x="20" y="90">They danced by the light of the moon.</tspan>

There's no visual evidence in Figure 8-8 that all the text is in one <text> element, but trust us — they're all connected.

Figure 8-8. Absolutely positioned poetry

Absolutely positioned poetry

You may also rotate a letter or series of letters within a <tspan> by using the rotate attribute, whose value is an angle in degrees.

If you have to modify the positions of several characters, you can do it easily by specifying a series of numbers for any of the x, y, dx, dy, and rotate attributes. The numbers you specified will be applied, one after another, to the characters within the <tspan>. This is shown in Example 8-7.

Example 8-7. Use of multiple values for dx and dy in a text span

<text x="30" y="30" style="font-size:14pt">
<tspan dx="0 4 -3 5 -4 6" dy="0 -3 7 3 -2 -8">Shaken</tspan>

Although Figure 8-9 doesn't show it, the effects of dx and dy persist after the <tspan> ends. If more text were placed after the closing </tspan>, it would be at the same offsets as the letter n. It would not return to the baseline established by the first capital S.

Figure 8-9. Multiple horizontal and vertical offsets

Multiple horizontal and vertical offsets


If you have nested <tspan> elements, the x, y, dx, dy, and rotate attribute values are not inherited by the inner elements.

Although you can use the dy attribute to produce superscripts and subscripts, it's easier to use the baseline-shift style, as we have done in Example 8-8. This style property has values of super and sub. You may also specify a length, such as 0.5em, or a percentage, which is calculated in terms of the font size. baseline-shift's effects are restricted to the span in which it occurs.

Example 8-8. Use of baseline-shift

<text x="20" y="25" style="font-size: 12pt;">
C<tspan style="baseline-shift: sub;">12</tspan>
H<tspan style="baseline-shift: sub;">22</tspan>
O<tspan style="baseline-shift: sub;">11</tspan> (sugar)

<text x="20" y="70" style="font-size: 12pt;">
6.02 x 10<tspan baseline-shift="super">23</tspan>
(Avogadro's number)

In Figure 8-10, the subscripted numbers appear too large. In an ideal case we'd set the font-size as well, but we wanted this example to concentrate on only one concept.

Figure 8-10. Subscripts and superscripts

Subscripts and superscripts

Setting textLength

Although we said that there's no a priori way to determine the endpoint of a segment of text, you can explicitly specify the length of text as the value of the textLength attribute. SVG will then fit the text into the given space. It does so by adjusting the space between glyphs and leaving the glyphs themselves untouched, or it can fit the words by adjusting both the spacing and glyph size. If you want to adjust space only, set the value of the lengthAdjust to spacing (this is the default). If you want SVG to fit the words into a given length by adjusting both spacing and glyph size, set lengthAdjust to spacingAndGlyphs. Example 8-9 uses these attributes to achieve the results of Figure 8-11.

Example 8-9. Use of textLength and lengthAdjust

<g style="font-size: 14pt;">
<path d="M 20 10 20 70 M 220 10 220 70" style="stroke: gray;"/>
<text x="20" y="30" 
    textLength="200" lengthAdjust="spacing">Two words</text>
<text x="20" y="60" 
    textLength="200" lengthAdjust="spacingAndGlyphs">Two words</text>
<text x="20" y="90">Two words 
    <tspan style="font-size: 10pt;">(normal length)</tspan></text>

<path d="M 20 100 20 170 M 100 100 100 170" style="stroke: gray;"/>
<text x="20" y="120" 
    textLength="80" lengthAdjust="spacing">Two words</text>
<text x="20" y="160" 
    textLength="80" lengthAdjust="spacingAndGlyphs">Two words</text>

Figure 8-11. Effects of varying textLength and lengthAdjust

Effects of varying textLength and lengthAdjust

Vertical Text

When you use SVG to create charts, graphs, or tables, you will often want labels running down the vertical axes. One way to achieve vertically-oriented text is to use a transformation to rotate the text 90 degrees. Another way to achieve the same effect is to change the value of the writing-mode style property to the value tb (meaning top to bottom).

Sometimes, though, you want the letters to appear in a vertical column with no rotation. Example 8-10 does this by setting the glyph-orientation-vertical property with a value of zero. (Its default value is 90, which is what rotates top-to-bottom text 90 degrees.) In Figure 8-12, this setting tends displays the inter-letter spacing as unnaturally large. Setting a small negative value for letter-spacing solves this problem.

Example 8-10. Producing vertical text

<text x="10" y="20" transform="rotate(90,10,20)">Rotated 90</text>
<text x="50" y="20" style="writing-mode: tb;">Writing Mode tb</text>
<text x="90" y="20" style="writing-mode: tb;
    glyph-orientation-vertical: 0;">Vertical zero</text>

Figure 8-12. Vertical text

Vertical text

Internationalization and Text

Unicode and Bidirectionality

XML is based on the Unicode standard (fully documented at the Unicode Consortium's web site, This lets text display in any language that the underlying viewer software can displaying, as you can see in Figure 8-13. Some languages such as Arabic and Hebrew are written right to left, so when text in these languages is mixed with text written left to right, as English is, the text is bidirectional, or bidi for short. The system software knows which characters go in which direction and works out their positions accordingly. Example 8-11 also overrides the implicit directionality of a segment of text by setting its direction style property to rtl, which stands for right-to-left. If you wish to change the direction of Hebrew or Arabic text, set it to ltr, which is left-to-right. You must also explicity override the underlying Unicode bidirectionality algorithm by setting the unicode-bidi style property to bidi-override.

Example 8-11. International text using Unicode

<g style="font-size: 14pt;">

<text x="10" y="30">Greek: </text>
<text x="100" y="30">

<text x="10" y="50">Russian:</text>
<text x="100" y="50">

<text x="10" y="70">Hebrew:</text>
<text x="100" y="70">
    &#x5d0;&#x5d1;&#x5d2;&#x5d3;&#x5d4; (written right to left)

<text x="10" y="90">Arabic:</text>
<text x="100" y="90">
    &#x627;&#x628;&#x629;&#x62a; (written right to left)

<text x="10" y="130">
   This is 
      <tspan style="direction: rtl; unicode-bidi: bidi-override;
        font-weight: bold;">right-to-left</tspan> 

Figure 8-13. Multilingual text

Multilingual text

The switch Element

The ability to display multiple languages in a single document is useful for such things as a brochure for an event that receives international visitors. Sometimes, though, you would like to create one document with content in two languages, say, Spanish and Russian. People viewing the document with Spanish system software would see the Spanish text, and Russians would see Russian text.

SVG provides this capability with the <switch> element. This element searches through all its children until it finds one whose systemLanguage attribute has a value that matches the language the user has chosen in the viewer software's preferences. The value of systemLanguage is a single value or comma-separated list of language names. A language name is either a two-letter language code, such as ru for Russian, or a language code followed by a country code, which specifies a sublanguage. For instance, fr-CA denotes Canadian French, while fr-CH denotes Swiss French.

Once a matching child element is found, all its children will be displayed. All the other children of the <switch> will be bypassed. Example 8-12 shows text in UK English, US English, Spanish, and Russian. Since a match of language code alone is considered a match, and country codes are used only to "break a tie," the text for UK English must come first.

Example 8-12. Use of the switch element

<circle cx="40" cy="60" r="20" style="fill: none; stroke: black;"/>
<g font-size="12pt">
    <g systemLanguage="en-UK">
        <text x="10" y="30">A circle</text>
        <text x="10" y="100">without colour.</text>
    <g systemLanguage="en">
        <text x="10" y="30">A circle</text>
        <text x="10" y="100">without color.</text>
    <g systemLanguage="es">
        <text x="10" y="30">Un c&#xed;rculo</text>
        <text x="10" y="100">sin color.</text>
    <g systemLanguage="ru">
        <text x="10" y="30">
        <text x="10" y="100">&#x431;&#x435;&#x437;

Figure 8-14 is a combination of screenshots taken with the language set to each of the choices in Example 8-12.

Figure 8-14. Combined screenshots as seen with different language preferences

Combined screenshots as seen with different language preferences

Using a Custom Font

Sometimes you need special symbols that are not represented in Unicode, or you want a subset of the Unicode characters without having to install an entire font. An example is Figure 8-15, which needs only a few of the over 2,000 Korean syllables. You can create a custom font as described in Appendix E and give its starting <font> tag a unique id. Here is the relevant portion of a file that contains six of the Korean syllables exported from the Batang TrueType font. The file is called kfont.svg:

<font id="kfont-defn" horiz-adv-x="989" vert-adv-y="1200"
    <font-face font-family="bakbatn"
        panose-1="2 3 6 0 0 1 1 1 1 1"
        ascent="800" descent="-200" baseline="0" />
        <missing-glyph horiz-adv-x="500" />
        <!-- glyph definitions go here -->

Figure 8-15. Korean syllables from an external font

Korean syllables from an external font

Once that is done, Example 8-13 can reference the font in that external file. For the sake of consistency, the value of the font-family that you use in this SVG file should match the value in the external file.

Example 8-13. Use of an external font

    <font-face font-family="bakbatn">
            <font-face-uri xlink:href="kfont.svg#kfont-defn"/>

<text font-size="28" x="20" y="40" style="font-family: bakbatn;">
    &#xc11c;&#xc6b8; - &#xb300;&#xd55c;&#xbbfc;&#xad6d;

Text on a Path

Text does not have to go in a straight horizontal or vertical line. It can follow any arbitrary path; simply enclose the text in a <textPath> element that uses an xlink:href attribute to refer to a previously defined <path> element. Letters will be rotated to stand "perpendicular" to the curve (that is, the letter's baseline will be tangent to the curve). Text along a gently curving and continuous path is easier to read than text that follows a sharply angled or discontinuous path.


The path you reference in the <textPath> element will not be displayed. That's why Example 8-14 has to draw the paths with <use> elements.

Example 8-14. Examples of textPath

<path id="curvepath"
    d="M30 40 C 50 10, 70 10, 120 40 S 150 0, 200 40"
    style="stroke: gray; fill: none;"/>

<path id="round-corner"
    d="M250 30 L 300 30 A 30 30 0 0 1 330 60 L 330 110"
    style="stroke: gray; fill: none;"/>

<path id="sharp-corner"
    d="M 30 110 100 110 100 160"
    style="stroke: gray; fill: none;"/>
<path id="discontinuous" 
    d="M 150 110 A 40 30 0 1 0 230 110 M 250 110 270 140"
    style="stroke: gray; fill: none;"/>

<use xlink:href="#curvepath"/>
<text style="font-size: 12;">
    <textPath xlink:href="#curvepath">
    Following a cubic Bézier curve.

<use xlink:href="#round-corner"/>
<text style="font-size: 12;">
    <textPath xlink:href="#round-corner">
    Going 'round the bend

<use xlink:href="#sharp-corner"/>
<text style="font-size: 12;">
    <textPath xlink:href="#sharp-corner">
    Making a quick turn

<use xlink:href="#discontinuous"/>
<text style="font-size: 12;">
    <textPath xlink:href="#discontinuous">
    Text along a broken path

Example 8-14 produces Figure 8-16; Figure 8-17 shows you what it looks like if we draw the text without the underlying paths.

Figure 8-16. Text along a path (with paths shown)

Text along a path (with paths shown)

Figure 8-17. Text along a path (paths not shown)

Text along a path (paths not shown)

You may adjust the beginning point of the text along its path by setting the startOffset attribute to a percentage or to a length. For example, startOffset="25%" will start the text one-fourth of the distance along the path, and startOffset="30" will start the text at a distance of thirty user units from the beginning of the path. If you wish to center text on a path, as in Example 8-15, set textanchor="middle" on the <text> element and startOffset="50%" on the <textPath> element. Text that falls beyond the ends of the path will not be displayed, as shown in the left half of Figure 8-18.

Example 8-15. Text Length and startOffset

<path id="short-corner" transform="translate(40,40)"
    d="M0 0 L 30 0 A 30 30 0 0 1 60 30 L 60 60"
    style="stroke: gray; fill: none;"/>

<path id="long-corner" transform="translate(140,40)"
    d="M0 0 L 50 0 A 30 30 0 0 1 80 30 L 80 80"
    style="stroke: gray; fill: none;"/>

<use xlink:href="#short-corner"/> 
<text style="font-size: 12;">
    <textPath xlink:href="#short-corner">
    This text is too long for the path.

<use xlink:href="#long-corner"/>  
<text style="font-size: 12; text-anchor: middle;">
    <textPath xlink:href="#long-corner" startOffset="50%">

Figure 8-18. Effects of long text and startOffset

Effects of long text and startOffset

Whitespace and Text

You may change the way that SVG handles whitespace (blanks, tabs, and newline characters) within text by changing the value of the xml:space attribute. If you specify a value of default (which, coincidentally, is the default value), SVG will handle whitespace as follows:

  • Remove all newline characters
  • Change all tabs to blanks
  • Remove all leading and trailing blanks
  • Change any run of intermediate blanks to a single blank

Thus, this string, where \t represents a tab and \n represents a newline, and an underscore represents a blank, this text:


will render as:


The other setting of xml:space is preserve. With this setting, SVG will simply convert all newline and tab characters to blanks, and then display the result, including leading and trailing blanks. the same text:


then renders as:



SVG's handling of whitespace is not like that of HTML. SVG's default handling eliminates all newlines; HTML changes internal newlines to a space. SVG's preserve method converts newlines to blanks; HTML's <pre> element does not. There is no newline in SVG 1.0; this bothers people until they realize that SVG text is oriented towards graphic display, not textual content (as in XHTML).

Case Study -- Adding Text to a Graphic

Figure 8-19 adds Korean and English text to the Korean national symbol shown in Figure 6-5. The text is centered along an elliptical path. The additional SVG in Example 8-16 is shown in boldface.

Example 8-16. Text case study

    <font-face font-family="bakbatn">
            <font-face-uri xlink:href="kfont.svg#kfont-defn"/>
    <path id="upper-curve" d="M -8 154 A 162 130 0 1 1 316 154"/>
    <path id="lower-curve" d="M -21 154 A 175 140 0 1 0 329 154"/>

<ellipse cx="154" cy="154" rx="150" ry="120" style="fill: #999999;"/>
<ellipse cx="152" cy="152" rx="150" ry="120" style="fill: #cceeff;"/>

<!-- large light red semicircle fills upper half,
     followed by small light red semicircle that dips into
     lower left half of symbol -->
<path d="M 302 152 A 150 120, 0, 1, 0, 2 152
    A 75 60, 0, 1, 0, 152 152" style="fill: #ffcccc;"/>

<!-- light blue semicircle rises into upper right half of symbol -->
<path d="M 152 152 A 75 60, 0, 1, 1, 302 152" style="fill: #cceeff;"/>

<text font-family="bakbatn" style="font-size: 28; text-anchor: middle;">
    <textPath xlink:href="#upper-curve" startOffset="50%">
    &#xc11c;&#xc6b8; - &#xb300;&#xd55c;&#xbbfc;&#xad6d;

<text style="font-size: 14pt; text-anchor: middle;">
    <textPath xlink:href="#lower-curve" startOffset="50%">
    Seoul - Republic of Korea


Figure 8-19. Text along path added to graphic

Text along path added to graphic

Personal tools