SVG Essentials/Document Structure

From WikiContent

< SVG Essentials
Revision as of 22:37, 4 March 2008 by Docbook2Wiki (Talk)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search
SVG Essentials

We've casually mentioned that SVG lets you separate a document's structure from its presentation. In this chapter, we're going to compare and contrast the two, discuss the presentational aspects of a document in more detail, and then show some of the SVG elements that you can use to make your document's structure clearer, more readable, and easier to maintain.

Contents

Structure and Presentation

As we mentioned in Chapter 1, in Section 1.4.2, one of XML's goals is provide a way to structure data and separate this structure from its visual presentation. Consider the drawing of the cat from that chapter; you recognize it as a cat because of its structure — the position and size of the geometric shapes that make up the drawing. If we were to make structural changes, such as shortening the whiskers, rounding the nose, and making the ears longer and rounding their ends, the drawing would become one of a rabbit, no matter what the surface presentation might be. The structure, therefore, tells you what a graphic is.

This is not to say that information about visual style isn't important; had we drawn the cat with thick purple lines and a gray interior, it would have been recognizable as a cat, but its appearance would have been far less pleasing. These differences are shown in Figure 4-1, albeit without the color differences. XML encourages you to separate structure and presentation; unfortunately, many discussions of XML emphasize structure at the expense of presentation. We'll right this wrong by going into detail about how you specify presentation in SVG.

Figure 4-1. Structure versus presentation

Image:SVG Essentials/I 4 tt56.png

Using Styles with SVG

SVG lets you specify presentational aspects of a graphic in four ways; with inline styles, internal stylesheets, external stylesheets, and presentation attributes. Let's examine each of these in turn.

Inline Styles

Example 4-1 uses inline styles. This is exactly the way we've been using presentation information so far; we set the value of the <style> attribute to a series of visual properties and their values as described in Appendix B, in Section B.1.

Example 4-1. Use of inline styles

<circle cx="20" cy="20" r="10"
    style="stroke: black; stroke-width: 1.5; fill: blue; fill-opacity: 0.6"/>

Internal Stylesheets

You don't need to place your styles inside each SVG element; you can create an internal stylesheet to collect commonly-used styles that you can apply to all occurrences of a particular element, or use as named classes to apply to individual elements. Example 4-2 sets up an internal stylesheet that will draw all circles in a blue double-thick dashed line with a light yellow interior. We have placed the stylesheet within a <defs> element, which we will discuss later in this chapter.

The example then draws several circles. The circles in the second row of Figure 4-2 have inline styles that override the specification in the internal stylesheet.

Example 4-2. Use of internal stylesheet

<svg width="200px" height="200px" viewBox="0 0 200 200">
<defs>
<style type="text/css"><![CDATA[
    circle {
        fill: #ffc;
        stroke: blue;
        stroke-width: 2;
        stroke-dasharray: 5 3
    }     
    ]]></style>
</defs>

<circle cx="20" cy="20" r="10"/>
<circle cx="60" cy="20" r="15"/>
<circle cx="20" cy="60" r="10" style="fill: #cfc"/>
<circle cx="60" cy="60" r="15" style="stroke-width: 1; 
    stroke-dasharray: none;"/>
</svg>

Figure 4-2. Internal stylesheet with SVG

Image:SVG Essentials/I 4 tt57.png

External Stylesheets

If you want to apply a set of styles to multiple SVG documents, you could copy and paste the internal stylesheet into each of them. This, of course, is impractical for a large volume of documents if you ever need to make a global change to all the documents. Instead, you should take all the information between the beginning and ending <style> tags (excluding the <![CDATA[ and ]]>) and save it in an external file, which becomes an external stylesheet. Example 4-3 shows an external stylesheet that has been saved in a file named ext_style.css This stylesheet uses a variety of selectors, including *, which sets a default for all elements that don't have any other style, and it, together with the SVG, produces Figure 4-3.

Example 4-3. External stylesheet

* { fill:none; stroke: black; } /* default for all elements */

rect { stroke-dasharray: 7 3; }

circle.yellow { fill: yellow; }

.thick { stroke-width: 5; }

.semiblue { fill:blue; fill-opacity: 0.5; }

Figure 4-3. External stylesheet with SVG

Image:SVG Essentials/I 4 tt58.png

Example 4-4 shows a complete SVG document (including <?xml ...?>, <?xml-stylesheet ...?>, and the <!DOCTYPE>) that references the external stylesheet.

Example 4-4. SVG file that references an external stylesheet

<?xml version="1.0"?>
<?xml-stylesheet href="ext_style.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
    "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="200px" height="200px" viewBox="0 0 200 200"
    preserveAspectRatio="xMinYMin meet">

<line x1="10" y1="10" x2="40" y2="10"/>
<rect x="10" y="20" width="40" height="30"/>
<circle class="yellow" cx="70" cy="20" r="10"/>
<polygon class="thick" points="60 50, 60 80,  90 80"/>
<polygon class="thick semiblue"
    points="100 30, 150 30, 150 50, 130 50"/>
</svg>

Note

Inline styles will almost always render more quickly than styles in an internal or external stylesheet; stylesheets and classes add rendering time due to look up and parsing.

Presentation Attributes

Although the overwhelming majority of your SVG documents will use styles for presentation information, SVG does permit you to specify this information in the form of presentation attributes. Instead of saying:

<circle cx="10" cy="10" r="5"
    style="fill: red; stroke:black; stroke-width: 2;"/>

You may write each of the properties as an attribute:

<circle cx="10" cy="10" r="5"
    fill="red" stroke="black" stroke-width="2"/>

If you are thinking that this is mixing structure and presentation, you are right. Presentation attributes do come in handy, though, when you are creating SVG documents by converting an XML data source to SVG, as you will see in Chapter 12. In these cases it can be easier to create individual attributes for each presentation property than to create the contents of a single style attribute. You may also need to use presentation attributes if the environment in which you will be placing your SVG cannot support stylesheets.

Presentation attributes are at the very bottom of the priority list. Any style specification coming from an inline, internal, or external stylesheet will override a presentation attribute. In the following SVG document, the circle will be filled in red, not green.

<svg width="200" height="200">
    <defs>
    <style type="text/css"><![CDATA[
        circle { fill: red; }
    ]]></style>
    </defs>
    <circle cx="20" cy="20" r="15" fill="green"/>
</svg>

Again, we emphasize that using style attributes or stylesheets should always be your first choice. Stylesheets let you apply a complex series of fill and stroke characteristics to all occurrences of certain elements within a document without having to duplicate the information into each element, as presentation attributes would require. The power and flexibility of stylesheets allow you to make significant changes in the look and feel of multiple documents with a minimum of effort.

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>

Figure 4-4. Grouped stick figure drawing

Image:SVG Essentials/I 4 tt62.png

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"/>

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

Image:SVG Essentials/I 4 tt64.png

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>

Figure 4-6. Result of using groups within defs

Image:SVG Essentials/I 4 tt65.png

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>

Figure 4-7. Groups versus symbols

Image:SVG Essentials/I 4 tt68.png

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.

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

Image:SVG Essentials/I 4 tt69.png

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.[1]

[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.

Notes

  1. We'll see another way to create a drop shadow in Chapter 10 in Section 10.2.
Personal tools