O'Reilly logo

SVG Essentials by J. David Eisenberg

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Document Structure -- Grouping and Referencing Objects

While it is certainly possible to define any drawing as an undifferentiated list of shapes and lines, most non-abstract art consists of groups of shapes and lines that form recognizable named objects. SVG has elements that let you do this sort of grouping to make your documents more structured and understandable.

The g Element

The <g> element gathers all of its child elements as a group, and often has an id attribute to give that group a unique name. Furthermore, each group may have its own <title> and <desc> to identify it for text-based XML applications or to aid in accessibility for visually-impaired users. In addition to the conceptual clarity that comes from the ability to group and document objects, the <g> element also provides notational convenience. Any styles you specify in the starting <g> tag will apply to all the child elements in the group. In Example 4-5, this saves us from having to duplicate the style="fill:none; stroke:black;" on every element shown in Figure 4-4. It is also possible to nest groups within one another, although we won’t show any examples of this until Chapter 5.

You may think of the <g> element as analogous to the Group Objects function in programs such as Adobe Illustrator. It also serves a similar function to the concept of layers in such programs; a layer is also a grouping of related objects.

Example 4-5. Simple use of the g element

<svg width="240px" height="240px" viewBox="0 0 240 240">
<title>Grouped Drawing</title>
<desc>Stick-figure drawings of a house and people</desc>

<g id="house" style="fill: none; stroke: black;">
    <desc>House with door</desc>
    <rect x="6" y="50" width="60" height="60"/>
    <polyline points="6 50, 36 9, 66 50"/>
    <polyline points="36 110, 36 80, 50 80, 50 110"/>
</g>

<g id="man" style="fill: none; stroke: black;">
    <desc>Male human</desc>
    <circle cx="85" cy="56" r="10"/>
    <line x1="85" y1="66" x2="85" y2="80"/>
    <polyline points="76 104, 85 80, 94 104" />
    <polyline points="76 70, 85 76, 94 70" />
</g>

<g id="woman" style="fill: none; stroke: black;">
    <desc>Female human</desc>
    <circle cx="110" cy="56" r="10"/>
    <polyline points="110 66, 110 80, 100 90, 120 90, 110 80"/>
    <line x1="104" y1="104" x2="108" y2="90"/>
    <line x1="112" y1="90" x2="116" y2="104"/>
    <polyline points="101 70, 110 76, 119 70" />
</g>
</svg>
Grouped stick figure drawing

Figure 4-4. Grouped stick figure drawing

The use Element

Complex graphics often have repeated elements. For example, a product brochure may have the company logo at the upper left and lower right of each page. If you were drawing the brochure with a graphic design program, you’d draw the logo once, group all its elements together, then copy and paste them to the other location. The SVG <use> element gives you an analogous copy-and-paste ability with a group that you’ve defined with <g>.

Once you have defined a group of graphic objects, you can display them again with the <use> tag. To specify the group you wish to reuse, give its URI in an xlink:href attribute, and specify the x and y location where the group’s (0, 0) point should be moved to. (We will see another way to achieve this effect in Chapter 5, in Section 5.1.) So, to create another house and set of people as shown in Figure 4-5, you’d put these lines just before the closing </svg> tag:

<use xlink:href="#house" x="70" y="100"/>
<use xlink:href="#woman" x="-80" y="100"/>
<use xlink:href="#man" x="-30" y="100"/>
Re-use of grouped stick figures

Figure 4-5. Re-use of grouped stick figures

The defs Element

You may have noticed some drawbacks with the preceding example:

  • The math for deciding where to place the re-used man and woman requires you to know the positions of the originals and use that as your base, rather than using a simple number like zero.

  • The fill and stroke color for the house were established by the original, and can’t be overriden by the <use>. This means you can’t make a row of multi-colored houses.

  • The document draws all three groups: the woman, the man, and the house. You can’t “store them away” and draw only a set of houses or only a set of people.

The <defs> element solves these problems. By putting the grouped objects between the beginning and ending <defs> tags, you instruct SVG to define them without displaying them. The SVG specification, in fact, recommends that you put all objects that you wish to re-use within a <defs> element so that SVG viewers working in a streaming environment can process data more efficiently. In Example 4-6, the house, man, and woman are defined so that their upper left corner is at (0, 0), and the house is not given any fill color. Since the groups will be within the <defs> element, they will not be drawn on the screen right away, and will serve as a “template” for future use. We have also constructed another group named couple, which, in turn, <use>s the man and woman groups. (Note that the bottom half of Figure 4-6 can’t use couple, since the woman is to the left of the man.)

Example 4-6. Example of the defs element

<svg width="240px" height="240px" viewBox="0 0 240 240">
<title>Grouped Drawing</title>
<desc>Stick-figure drawings of a house and people</desc>

<defs>
<g id="house" style="stroke: black;">
    <desc>House with door</desc>
    <rect x="0" y="41" width="60" height="60"/>
    <polyline points="0 41, 30 0, 60 41"/>
    <polyline points="30 101, 30 71, 44 71, 44 101"/>
</g>

<g id="man" style="fill: none; stroke: black;">
    <desc>Male human</desc> 
    <circle cx="10" cy="10" r="10"/>
    <line x1="10" y1="20" x2="10" y2="44"/>
    <polyline points="1 58, 10 44, 19 58"/>
    <polyline points="1 24, 10 30, 19 24"/>
</g>

<g id="woman" style="fill: none; stroke: black;">
    <desc>Female human</desc>
    <circle cx="10" cy="10" r="10"/>
    <polyline points="10 20, 10 34, 0 44, 20 44, 10 34"/>
    <line x1="4" y1="58" x2="8" y2="44"/>
    <line x1="12" y1="44" x2="16" y2="58"/>
    <polyline points="1 24, 10 30, 19 24" />
</g>

<g id="couple">
    <desc>Male and female human</desc>
    <use xlink:href="#man" x="0" y="0"/>
    <use xlink:href="#woman" x="25" y="0"/>
</g>
</defs>

<!-- make use of the defined groups -->
<use xlink:href="#house" x="0" y="0" style="fill: #cfc;"/>
<use xlink:href="#couple" x="70" y="40"/>

<use xlink:href="#house" x="120" y="0" style="fill: #99f;"/>
<use xlink:href="#couple" x="190" y="40"/>

<use xlink:href="#woman" x="0" y="145"/>
<use xlink:href="#man" x="25" y="145"/>
<use xlink:href="#house" x="65" y="105" style="fill: #c00;"/>
</svg>
Result of using groups within defs

Figure 4-6. Result of using groups within defs

The <use> element is not restricted to using objects from the same file in which it occurs; the xlink:href attribute may specify any valid file or URI. This makes it possible to collect a set of common elements in one SVG file and use them selectively from other files. For example, you could create a file named identity.svg that contains all of the identity graphics that your organization uses:

<g id="company_mascot">
   <!-- drawing of company mascot -->
</g>

<g id="company_logo" style="stroke: none;">
   <polygon points="0 20, 20 0, 40 20, 20 40"
      style="fill: #696;"/>
   <rect x="7" y="7" width="26" height="26"
      style="fill: #c9c;"/>
</g>

<g id="partner_logo">
    <!-- drawing of company partner's logo -->
</g>

and then refer to it with:

<use xlink:href="identity.svg#company_logo" x="200" y="200"/>

The symbol Element

The <symbol> element provides another way of grouping elements. Unlike the <g> element, a <symbol> is never displayed, so you don’t have to enclose it in a <defs> specification. However, it is customary to do so, since a symbol really is something you’re defining for later use. Additionally, symbols can specify viewBox and preserveAspectRatio attributes, so that a symbol can fit into the viewport established by the use element. Example 4-7 shows that the width and height are ignored for a simple group (the top two octagons), but are used when displaying a symbol. The edges of the lower right octagon in Figure 4-7 are cut off because the preserveAspectRatio has been set to slice.

Example 4-7. Groups versus symbols

<svg width="200px" height="200px" viewBox="0 0 200 200">
<title>Symbols vs. groups</title>
<desc>Use</desc>

<defs>
<g id="octagon" style="stroke: black;">
    <desc>Octagon as group</desc>
    <polygon points="
        36 25, 25 36, 11 36, 0 25,
        0 11, 11 0, 25 0, 36 11"/>
</g>

<symbol id="sym-octagon" style="stroke: black;"
   preserveAspectRatio="xMidYMid slice" viewBox="0 0 40 40">
    <desc>Octagon as symbol</desc>
    <polygon points="
        36 25, 25 36, 11 36, 0 25,
        0 11, 11 0, 25 0, 36 11"/>
</symbol>
</defs>

<use xlink:href="#octagon" x="40" y="40" width="30" height="30"
	style="fill: #c00;"/>
<use xlink:href="#octagon" x="80" y="40" width="40" height="60"
	style="fill: #cc0;"/>
<use xlink:href="#sym-octagon" x="40" y="80" width="30" height="30"
    style="fill: #cfc;"/>
<use xlink:href="#sym-octagon" x="80" y="80" width="40" height="60"
    style="fill: #699;"/>
</svg>
Groups versus symbols

Figure 4-7. Groups versus symbols

The image Element

While <use> lets you re-use a portion of an SVG file, the <image> element includes an entire SVG or raster file. If you are including an SVG file, the x, y, width, and height attributes establish the viewport in which the referenced file will be drawn; if you’re including a raster file, it will be scaled to fit the rectangle that the attributes specify. You can currently include either JPEG or PNG raster files. Example 4-8 shows how to include a JPEG image with SVG; the result is in Figure 4-8.

JPEG image included in an SVG file

Figure 4-8. JPEG image included in an SVG file

Example 4-8. Use of the image element

<svg width="310px" height="310px" viewBox="0 0 310 310">

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

<image xlink:href="kwanghwamun.jpg"     [3]
    x="72" y="92"     [4]
    width="160" height="120"/>     [5]

</svg>

[1] Create a gray ellipse to simulate a drop shadow.[4]

[2] Create the main blue ellipse. Since it occurs after the gray ellipse, it is displayed above that object.

[3] Specify the URI of the file to include.

[4] Specify the upper left corner of the image.

[5] Specify the width and height to which the image should be scaled. If these aren’t in the same aspect ratio as the original picture, it will appear stretched or squashed.



[4] We’ll see another way to create a drop shadow in Chapter 10 in Section 10.2.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required