An SVG Primer for Today's Browsers W3C Working Draft — September 2010 This version: http://www.w3.org/Graphics/SVG/IG/resources/svgprimer.html Latest version: http://www.w3.org/Graphics/SVG/IG/resources/svgprimer.html Previous version: http://www.w3.org/Graphics/SVG/IG/resources/svgprimer.html Editor: David Dailey, Slippery Rock University Copyright © 2010 W3C ® ( MIT , ERCIM , Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.

Abstract

Scalable Vector Graphics (SVG) is a Web graphics language. SVG defines markup and APIs for creating static or dynamic images, capable of interactivity and animation, including various graphical effects. It can be styled with CSS, and combined with HTML. This document provides an introduction to SVG, with examples and explanations.

Status of this document This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/. This is a Public Working Draft, designed to aid discussion and solicit feedback. It was developed by the SVG Interest Group, which expects to advance this Working Draft to become an Interest Group Note. Please send comments about this document to public-svg-ig@w3.org (with public archive). Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress. This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. The group does not expect this document to become a W3C Recommendation. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy. This document is a work in progress, and is still under review. It is based on material from 2006, and some portions may be out of date. Please report any errors to the SVG Interest Group or to the editor.

Preface

This is neither an introductory text book, nor a reference manual. Instead, it is aimed so that any of these people:

an upper division undergraduate student with a few semesters under her belt of computing coursework;

a professional web programmer;

a graphic designer with a strong technical bent;

or

a science teacher who wants to build graphical presentations

might be able to pick it up and then do any or all of the following:

work through it over the course of a few days, developing a basic understanding;

be able, in a week or two, to make a decent graphical front-end to a web site that demands innovative and interactive graphics;

at any time during the next year or two of work with SVG, be able to pick up the book, look up a new topic, and with little effort, find an illustration of what they'd like to know about and with a minimum of reading, to be able to make sense of the examples provided.

Over the past 35 years of my involvement with computing, I have had the occasion to use, as both learner and teacher, a wide variety of books on computing and computing languages. I have gained much from many sources, but at the same time my preferences have, no doubt, congealed somewhat. Perhaps some of my preferences will coincide with those of the reader.

While this book is not intended for the beginning computer user, I would hope it is approachable by any of these sorts of people:

Someone with a good deal of HTML and JavaScript experience, but little or no SVG experience.

Someone who has done some work with SVG but little with HTML or JavaScript.

Someone who has programmed in other languages, is conversant with XML, and wishes to learn about SVG.

That is, it aims to provide some of the purpose of an introduction to the topic, and some of the purposes of a reference. At the same time, though, it is not a comprehensive guide to SVG. In fact, in the time following completion of the first draft, new topics that really should be included have arisen, new browsers have come onto the scene, the SVG specification itself has started to grow. In the Afterword I offer suggestions for directions I would hope to see this document grow, over time. The SVG Interest Group, I am hoping, will provide help in bringing these efforts forward.

The book attempts to discuss SVG in broader terms, but at the same time to illustrate how one can write JavaScript programs that use and manipulate SVG. It is not as broad in its coverage of stand-alone SVG as some existing books, though I believe it goes deeper into scripting than many.

Several goals helped to guide the development of this book.

It should be hands-on and practical rather than theoretical. It should illustrate existing technologies rather than future ones. In addition to saying what should work (according to the standards) it should illustrate what does or does not work. Individual sections should be, to every extent possible, self-contained. A reader should be able to skip to chapters relevant to a current concern without having to read all chapters leading up to a particular topic. Examples should be brief. So long as one is familiar with the basic elements being used, then no one should have to read more than a page or two to figure out what is going on with a particular example.

In short, I'd like it to be the book that did not seem to exist when I started learning SVG.

Chapter I - Overview

Laconism

SVG or Scalable Vector Graphics is a relatively new World Wide Web Consortium (W3C) standard, used by a host of companies and organizations, for the creation and display of vector graphic material. SVG is an XML language that allows dynamic creation of content using JavaScript within or outside the context of the World Wide Web.

Polemic

If you ever close your eyes and see pictures that have never been drawn or movies that have not yet been made, then SVG might be for you. Just as typing or drawing or playing a musical instrument, developing hypertexts or carving stone can help you to express a part of what is inside you, so might SVG expand your expressive ability. Think of SVG as an expressive medium. With it you can let your readers' browser build your vector graphics, animate them, and let your readers interact with and change the evolution of those graphics dynamically. Users can draw over them, append to them, or use them to plot user-selected sources of data. And you can do it in an open-standards environment that is rapidly growing in popularity and cross-browser acceptance. It is good for less fanciful endeavors, like business and science, too. It is sort of like HTML, only graphical.

Brief History

The first public draft of SVG was released by the World Wide Web consortium in February of 1999 . During the preceding years, interest in the use of vector graphics had grown. The PostScript page description language developed by Adobe Systems Inc. during the 1980s had given the print-based community a way of describing images in ways which could be rescaled to adapt to the resolution of the display device, usually a printer. It was natural to seek a similar vector-based approach to web-based presentation.

In 1998 an XML-based language, Vector Markup Language (VML) was introduced by Microsoft. It contains many of the same sorts of features, though few programmers adopted VML as a medium of expression and Microsoft seems to have abandoned development of VML.

By the end of 1999, development of SVG had begun in earnest. Within two years, six subsequent working drafts appeared. IBM and Corel each released software that exported SVG. IBM released an SVG viewer and several software initiatives released SVG drawing packages for a variety of operating systems. Since that time support and endorsement has grown. By 2005, A Google search for "SVG" returned over 3.7 million links on the WWW. Table 1 compares these results with other technologies. By February 2009, all these numbers had increased considerably (HTML itself rose almost eightfold), but SVG had risen to 11.9 million web documents moving well ahead of Fortran which had risen to 8.6 million.

Query Number of documents found "HTML" 1,610,000,000 "PHP" 454,000,000 "Java" (includes island) 150,000,000 "Linux" 86,400,000 "Perl" 51,600,000 "JavaScript" 49,900,000 "Unix" 35,200,000 "C++" 28,900,000 "SQL" 21,200,000 "MySQL" 20,300,000 "Pascal" (includes Blaise) 14,500,000 "Visual Basic" 8,330,000 "Fortran" 5,350,000 "SVG" 3,750,000 "COBOL" 2,630,000 "Lisp" (includes stuttering) 2,300,000 SMIL 1,600,000 "awk" 912,000 "VML" 497,000 "ALGOL" 489,000 "SNOBOL" 40,900 Table 1: Number of documents found by search at www.google.com

Advantages of SVG

SVG has some advantages over conventional bitmapped graphics, such as JPEG, GIF, and PNG, used in the browser environment, because of several reasons:

The files are generally much smaller than bitmaps, resulting in quicker download times.

The graphics can be scaled to fit different display devices without the pixelation associated with enlarging bitmaps.

The graphics are constructed within the browser, reducing the server load and network response time generally associated with web imagery. That is, a typically small formulaic description is sent from the server to the client. The client then reconstructs the imagery based on the formulas it receives.

The end-user can interact with and change the graphics without need for complex and costly client-server communications.

It provides native support for SMIL (Synchronized Media Integration Language) meaning that animations, for example, are supported with a more analog notion of timing, hence freeing the programmer from timed loops typically used in JavaScript-based animations.

It responds to JavaScript: the same scripting language used in the HTML environment. This means the two types of documents may converse, share information and modify one another.

SVG is an XML language. This is important for at least three reasons. First, the code tends to adhere to agreed upon standards of how SVG should be written and how client software should respond. Second, like all XML, it is written in text, and can generally be read not only by machines but also by humans. Third, and perhaps most importantly, JavaScript can be used to manipulate both the objects and the Document Object Model, in ways quite similar to how JavaScript is used in conjunction with HTML. If you already know how to use JavaScript and HTML for web-programming, the learning curve will be pretty gentle, particularly in view of the benefits to be gained.

Brief examples

Examples are illustrated briefly, just to give an idea of what SVG looks like. In subsequent chapters, we will explain in detail what is actually going on. If you wish to see actual "live" examples on the web of the following, they can be viewed at this location which is a part of the author's web site where many hundreds of examples (sometimes in varying states of disrepair) can be seen.

The object primitives defined by the W3C's current recommendation 1.1 are the line, rect(angle), circle, ellipse, polyline, polygon, text, and the path. Each is described with an XML tag such as the following example:

SVG code Illustration <line x1="0" y1="100" x2="100" y2="0"

stroke-width="2" stroke="black" />

Your browser appears not to support SVG. The image shown is a png version. Simple line

The above draws a black line (typically anti-aliased when drawn in the browser) of thickness 2 from the point (100, 200) to the point (200, 100). Different browsers have different mechanisms for zooming on SVG, but if one zooms, the visitor will notice that, unlike bitmapped graphics, the line does not become grainy as one zooms in.

SVG code Illustration <rect x="0" y="0" width="200" height="150" fill="#FFFF00" stroke="blue" stroke-width="5" />

Your browser appears not to support SVG. The image shown is a png version. Rectangle

This example draws a rectangle with its upper left corner at (0,0) its lower right corner at (200, 150) with a blue boundary that is 5 units thick and which is filled with yellow (the familiar RGB hexadecimal is used here).

SVG code Illustration <text x="15" y="45" font-size="40" fill="red">some text</text>

Your browser appears not to support SVG. The image shown is a png version. text

The above draws the string "some text" in large red letters and positions the string on the screen.

Other objects are similarly defined and can be appended, one after another into the display window, with the most recently defined element appearing in front of or on top of earlier-defined shapes.

SVG code Illustration <rect x="0" y="0" width="200" height="100"

fill="#FFFF00" />

<ellipse cx="100" cy="50" rx="100" ry="50"

fill="red" />

Your browser appears not to support SVG. The image shown is a png version. rect with ellipse

The above code specifies a red oval inscribed in a yellow rectangle.

One of the most flexible of SVG's primitive objects is the path. <path> uses a series of lines, splines (either cubic or quadratic), and elliptical arcs to define arbitrarily complex curves that combine smooth or jagged transitions.

<path d="M 100 100 L 200 200" stroke="black" stroke-width="12"/>

defines a simple line equivalent to the line defined by

<line x1="200" y1="200" x2="100" y2="100" stroke-width="12" stroke="black" />.

It proceeds by placing the pen down at (100, 100) and then drawing a line to (200, 200).

SVG code Illustration <path d="M 100 200 L 200 300, 300 20,0 400 300, 500 200"

stroke="black" fill="none" stroke-width="5">

Your browser appears not to support SVG. The image shown is a png version. path

Similarly, the code shown above draws a zig-zag in the plane resembling a "W", moving from (100, 200) to (200, 300) and eventually to (500, 200).

SVG code Illustration <path d="M 0 0 L 100 100" stroke="black"

stroke-width="12"/>

<line x1="0" y1="100" x2="100" y2="0"

stroke-width="2" stroke="black" />

Your browser appears not to support SVG. The image shown is a png version. path with line

Likewise, the above defines two crossing lines: one thicker than the other. We use, in one case, a line, in the other a path to accomplish much the same thing.

SVG code Illustration <path d="M 20 40 C 100 -30 180 90 20 160 L 120 160" stroke="black" fill="none" stroke-width="5" />

Your browser appears not to support SVG. The image shown is a png version. more complex path

A more complex path, above, resembles the numeral 2. The "C" portion of the path describes a cubic spline — the path begins at (20, 40) and heads toward (100, -30), based on the tangent at the start point. The curve then heads down to the right toward (180, 90) but with a final destination of (20, 160). To adjoin multiple splines together into a single complex curve in VML, a predecessor to SVG, required a good deal more effort than in SVG.

Getting started

There are several different ways of putting SVG content in a web page. Let's get started without a lot of tedium about why this or why not that. Later in the book, we will look into some of the advantages and disadvantages of various approaches, but for now let's just talk about two major approaches: standalone SVG documents, and HTML documents with SVG in them. Both of these approaches require a common set of preparatory steps.

Getting an SVG viewer (web browser).

There are many ways of seeing and generating SVG content that do not involve web (HTML) browsers. Just as there are HTML browsers that do not recognize SVG, there are SVG browsers that do not comprehend HTML. But among current web browsers that support both HTML and SVG, we are, as of this writing, talking about one of the following five browsers (hereafter referred to as "the five browsers"):

Microsoft Internet Explorer (IE) version 9 or greater , or Internet Explorer version 4 or greater with an SVG plugin : As of this writing, IE9 Beta has native support for much of SVG.

For IE versions 4.0 to 8.0, you will need a plugin created and distributed by Adobe Systems Inc.®. The plugin is an easy and fast install, and can be accomplished by pointing your browser at http://www.adobe.com/svg/viewer/install/main.html. The plugin is for Adobe SVG Viewer 3.03, referred to in this document as ASV, ASV+IE, or ASV+Internet Explorer. Other SVG plugins for early versions of IE have been under development and showing steady progress for several years.

, or : As of this writing, IE9 Beta has native support for much of SVG. For IE versions 4.0 to 8.0, you will need a plugin created and distributed by Adobe Systems Inc.®. The plugin is an easy and fast install, and can be accomplished by pointing your browser at http://www.adobe.com/svg/viewer/install/main.html. The plugin is for Adobe SVG Viewer 3.03, referred to in this document as ASV, ASV+IE, or ASV+Internet Explorer. Other SVG plugins for early versions of IE have been under development and showing steady progress for several years. Firefox (FF) version 1.5 or greater : Since version 1.5 Firefox has offered support for much of the SVG 1.1 specification, though is currently behind ASV+IE and Opera (but ahead of Chrome and Safari) with regard to support for filters. Unlike Opera, ASV+IE and Safari, in early 2009, Firefox does not yet support animation, though nightly builds of the software apparently do.

: Since version 1.5 Firefox has offered support for much of the SVG 1.1 specification, though is currently behind ASV+IE and Opera (but ahead of Chrome and Safari) with regard to support for filters. Unlike Opera, ASV+IE and Safari, in early 2009, Firefox does not yet support animation, though nightly builds of the software apparently do. Opera version 9 or greater : (Version 8 introduced limited support.) Users who are interested in SVG might well consider experimenting with Opera as a browser, since its performance has received considerable praise in the web community.

: (Version 8 introduced limited support.) Users who are interested in SVG might well consider experimenting with Opera as a browser, since its performance has received considerable praise in the web community. Safari 3 or greater : Apple's browser, running either in the Mac OS or under Windows is based, in large part, on the WebKit open source project. Entering the SVG market relatively late (circa 2007), Safari has made very rapid strides in its SVG support, currently supporting some animation, but not yet masks or filters.

: Apple's browser, running either in the Mac OS or under Windows is based, in large part, on the WebKit open source project. Entering the SVG market relatively late (circa 2007), Safari has made very rapid strides in its SVG support, currently supporting some animation, but not yet masks or filters. Chrome: Like Safari, Google's Chrome is based upon the Webkit open source project. Also like Safari, its push into the SVG arena has been both steady and fast - roughly matching Safari in terms of SVG capabilities.

Mention should be made of additional contexts in which SVG can be viewed and or created:

Other (Amaya, Camino, Konqueror, Netscape, Sea Monkey). Support for some of these is native, others rely on same the plugin from Adobe (mentioned above under a.). Most of these others have, as of this writing, limited SVG support, though given Konqueror's historic affiliation with WebKit, this may have changed.

The Batik environment, developed within Apache.org, provides a very sophisticated level of SVG support. The interested reader is advised that the Squiggle browser may already convey more of that sophistication than the author is aware of.

Special mention: KDE. Not a browser, but a desktop environment for Linux, it should be mentioned that the K Desktop environment (KDE) provides native SVG support at the level of the operating system.

Special mention: Inkscape and Illustrator. Inkscape is a free, open-source editor for vector graphics. Both Inkscape and the well-known Illustrator® from Adobe® can read and write SVG files, allowing their modification or creation with a WYSIWYG editor..

Opera, Firefox, Safari, and Chrome users will enjoy SVG support that is native to the browser, while many of the others, including Internet Explorer require a plug-in. Many web browsers and SVG viewers with some HTML capability are able to interpret differing degrees of SVG, JavaScript and HTML, so it is best to check your local supermarket for availability and freshness.

Once you have downloaded, plugged in, or otherwise installed a likely candidate for SVG viewing, it is good to test your browser to make sure it is able to actually interpret SVG. For this you might either

Do a search for the string "svg" in your favorite search engine and then find a few of the early links. Look for a document ending with a .svg extension. If your browser can see any of them, it is a valid browser. If it fails to see certain .svg pages, it could mean either that the page you found is invalid or that your browser doesn't yet support some of the features used in the SVG page. Go to the SVG Wiki, a set of pages maintained by people who know what they are doing, located at http://wiki.svg.org. Go to Wikipedia's entry for SVG. Look at the images shown so far. If you see the text Your browser appears not to support SVG. The image shown is a png version then, well, your browser appears not to support SVG. If you don't see this messager then you're already seeing SVG in your browser!

In writing a book (which even though it is electronic, I hope does not grow stale too quickly), I am reluctant to point the reader to many of the 12 million web pages that either include or discuss SVG, since the average lifespan of a web page (44 days according to the best estimate I can find) is considerably less than the time it takes a project of this size to appear in print. But I suspect strongly that wiki.svg, wikipedia and I will all still be living by the time your eyes reach this book. That's why I will bank on the above URLs as being worth mentioning.

Write and test a small SVG file

Once you have web software installed that is able to see SVG, then it is time to write a bit of your own. For this there are a number of editors that allow SVG markup to be written. The developer can use a simple text editor, although numerous good, and sometimes free, graphical editing packages are available as well. Oxygen and XMLSpy are two commercial SVG text editors. Among the open source or shareware alternatives, Batik seems to have accumulated a fair-sized user community. I myself use an HTML editor/viewer that does not understand SVG (in terms of tag completion or highlighting) but is at least able to view it. Many folks recommend the Firebug plug-in, associated with Firefox, and Opera's tabbed browsing allows one to go back and forth from source code to view quite easily. Ultimately all you need is a text editor that can save files in plain ASCII or Unicode. Save your file with a .svg filename extension.

As a sample file, try the following simple example :

<svg xmlns="http://www.w3.org/2000/svg">

<circle r="50"/>

</svg>

Save it as "simplest.svg." Point your web browser at it to make sure you can see part of a black circle. If so, you are ready to start creating SVG content.

Test it on your web server

If you already have a place on the Web, then put your file in that place. If you can see your file when you point your web browser at it, then congratulations; others can most likely see it too. If you can't see it, it is most likely a server configuration problem. The Web server should send an HTTP header for the svg file type that looks like:

Content-Type: image/svg+xml

If you are your own systems administrator, then it is likely you know where to edit your server's configuration so as to effect such a change. If not, talk to your systems administrator and he or she probably will. If not, please encourage them, ever so respectfully, to have a look at what the SVG server configuration page says about the topic.

Stir up your imagination and finish reading this book.

Let me know if you have any problems!

Chapter II - SVG Basics

The coordinate system

The default coordinate system in SVG is much the same as in HTML. It works as a two-dimensional x-y plane. The origin (where x=0 and y=0) is the upper left-hand corner. As we move right from there, x increases. As we move downward, y increases. Generally, units are measured in pixels. That is, if our browser window has a rectangle of 343 pixels high by 501 pixels wide then the lower right corner of that window will be the point (501,343).

Illustration of cartesian grid

Now, to be sure, things are not always this simple. Sometimes, we have scaling and zoom effects in place which can be affected by a number of considerations, foremost among which might be the viewBox, a rectangle which resets the scale of the units associated with the viewing rectangle. Also, the dimensions of the HTML window may interact with the SVG object if it is embedded in HTML. These considerations will be discussed in more detail later in the book.

Other than that, we can generally assume that when we refer to a point with coordinates (100,100), it will be a point diagonally downward (100√2 pixels) from the upper left corner of the browser's viewable window.

Simple objects

According to the World Wide Web Consortium's Recommendations, the SVG graphics elements are "the element types that can cause graphics to be drawn onto the target canvas. Those are: 'path', 'text', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'image' and 'use'."

These are the primitives, so to speak, and form an appropriate starting point for our discussion. The <polyline> and <polygon> objects don't add anything that the more flexible path cannot do, so those will not be considered in this treatment. It makes sense to discuss <use> along with grouping and transformations (once we have something worth <use>-ing), so I will present the others starting with the simpler objects first.

I offer three recommendations on how one might learn all of this:

Don't just read this book; try the examples. You have my permission and the permission of the publishers to do so. This sort of subject does not enter a passive brain as well as it enters an active one. It will help if you engage yourself actively.

Don't just copy these examples; experiment . Try changing an attribute here and there. Imagine some picture, and see if you can draw it.

these examples; . Try changing an attribute here and there. Imagine some picture, and see if you can draw it. For those fairly comfortable with learning new technologies, skip ahead and read, at the same time, the chapter on SMIL animation. As you are experimenting with a tag and its attributes, try animating the attributes so you can see what they affect and to what degree. It can give you a quicker and clearer understanding.

Colors and drawing order

Before discussing the basic drawing objects, let's first consider the use of color values in SVG and the order in which drawn objects appear on the page.

Colors may be specified in much the same way that they are in HTML/CSS:

color names: any of the HTML name space color terms, including such terms as "aqua", "lightgreen", "salmon", "tomato" and "papayawhip";

6-digit hex RGB values: "#ff0a8f";

3-digit hex RGB values: "#fd2"="#ffdd22";

functional values: either decimal (in the range 0 to 255), such as rgb(255,12,560); or percentage, such as rgb(100%, 50%, 20%).

Accordingly, the color "red" may be defined alternately as "red", "#f00", "#ff0000", "rgb(255,0,0)", or as "rgb(100%,0%,0%)".

Objects appear from back to front in the order they are defined, with objects defined later appearing in front of or above (and occluding if they overlap) those defined earlier. More concerning overlaying objects will be found in the next section "operations: grouping, reusing, scaling, translation and rotation."

<line>

The <line> object draws a line between two specified points: (x1,y1) and (x2,y2). In order to see the line, it must have a stroke (i.e., a color).

The code <line x1="10" y1="10" x2="100" y2="100"> draws an invisible line in most browsers, while in ASV+Internet Explorer, a faint hint of a grey line might be seen (which, curiously, does not expand in size when we zoom in on it).

Hence, a sort of minimal line consists of code such as the following:

<line x1="5" y1="5" stroke="red" x2="90" y2="90" />

Another attribute known as "stroke-width" controls the thickness of the line and, by default, is assigned a value of 1.

The stroke and stroke-width attributes as well as the starting and ending points are varied in the following illustration:

SVG code Illustration <line x1="5" y1="10" x2="99" y2="30" stroke-width=".5" stroke="red"/>



<line x1="5" y1="30" x2="99" y2="50" stroke-width="1" stroke="red"/>



<line x1="5" y1="50" x2="99" y2="70" stroke-width="2.5" stroke="red"/>



<line x1="5" y1="70" x2="99" y2="90" stroke-width="4" stroke="blue"/> The effect of varying stroke widths

A number of other attributes exist for lines, two of which: the stroke-dasharray and the stroke-linecap are worth mentioning in this treatment.

SVG code Illustration <line x1="15" y1="15" x2="140" y2="135" stroke-width="25"

stroke="blue" stroke-linecap="round"/>



<line x1="15" y1="15" x2="140" y2="135" stroke-width="25"

stroke="aqua" stroke-dasharray="8,3,2,18"/>



<line x1="15" y1="155" x2="160" y2="60" stroke-width="25"

stroke="blue"/>



<line x1="15" y1="155" x2="160" y2="60" stroke-width="25"

stroke="orange" stroke-dasharray="8,3,2"/> The effect of other attributes on line elements

The stroke-dasharray gives a flexible way of making dashed lines, shape borders, and paths. In the above illustration, we have made two pairs each consisting of two identical lines (except for the stroke and its dasharray) one on top of the other. The top line of each pair has had its stroke-dasharray applied which takes a sequence of numeric values S=(v1,v2,v3,...,vn) and turns the stroke on and off: on for the first value v1 pixels along the length of the line; off for the next v2 pixels and so forth. If the sum of the values v i in S is less than the length of the line, then the values are repeated again as needed. In the case of the first line, the value of stroke-dasharray="8,3,2,18" has an even number of values so the blue and aqua colored bands repeat aqua 8 pixels, clear 3 pixels, aqua 2 pixels and clear 18 pixels, starting over again with 8 more pixels of aqua. Since the underlying but identically shaped line is blue, the blue of the underlying line is what shows. In the case of the second line, the value of stroke-dasharray="8,3,2" has an odd number of values so the repeating sequence goes like this:

(8 orange, 3 clear, 2 orange, 8 clear, 3 orange, 2 clear, ...).

The first of the two pairs of lines has two lines; both use stroke-linecap, having stroke-linecap="round". This makes the end of the line rounded instead of flat, as in the second example which uses the default or flat value of stroke-linecap.

Another useful aspect of lines involves the <marker> tag which can be used to define arrow or other shapes appropriate for attaching to the beginning or ends of lines. The W3C gives a clear example for those so interested, though it is a bit verbose for our treatment here. Another example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/simpleshapes.svg.

<rect>

The <line>, <rect>-angle, <circle> and <ellipse> elements can all be seen as special cases of what could instead be done with the <path> object. But these are such familiar geometric objects that it is natural to define them separately.

A rectangle is drawn using the <rect> tag, which, by default, produces a rectangle with sides parallel to the edges of the browser window. We will see how to rotate rectangles later on so that they might be parallel to something other than the ground, without having to lift and tilt our monitors. We may also skew them so that they cease to be rectangles at all, but rather become parallelograms.

A <rect> receives a starting point (x,y) a width and a height attribute. If no fill color or pattern is specified, by default, the rectangle will be filled with black.

<rect x="60" y="95" height="30" width="50" />

Common attributes that are used in conjunction with the rectangle include the fill, which specifies its color (or pattern), its stroke and stroke-width (which determine aspects of its border or edge). Here are some rectangles that exemplify these attributes as well as the use of various color reference schemes and the partial overlay and occlusion of objects.

SVG code Illustration <rect x="62" y="25" height="110" width="16"

fill="rgb(100%,50%,50%)" stroke="black"

stroke-width="2"/>



<rect x="35" y="35" height="30" width="50"

fill="red" stroke="black" stroke-width="2"/>



<rect x="5" y="60" height="30" width="50"

fill="#f88" stroke="black" stroke-width="2"/>



<rect x="25" y="70" height="30" width="50"

fill="#ff8888" stroke="black" stroke-width="2"/>



<rect x="65" y="60" height="30" width="50"

fill="#eac" stroke="black" stroke-width="2"/>



<rect x="85" y="70" height="30" width="50"

fill="#eeaacc" stroke="black"

stroke-width="2"/>



<rect x="60" y="95" height="30" width="50"

fill="rgb(255,0,0)" stroke="black"

stroke-width="2"/> A variety of rectangles

Note in the above example that the first rectangle defined, the tall thin one, appears under all subsequent rectangles. Note also, that the colors "#f88" #ff8888" are equivalent and that "rgb(100%,50%,50%)" while visibly similar, is actually a bit darker since half of "ff" is actually "7f" rather than "88".

The fill of a <rect> can also be a more complex. Gradients, masks, patterns, and various filters are all available to alter the way a rectangle appears in SVG. These are more advanced topics and are dealt with later in this book. For something analogous to the stroke-dasharray seen above for the <line> element, consider the <gradient> as discussed in the next chapter.

<circle>

A circle is indeed a special case of an ellipse, so if you prefer parsimony in the amount of syntax you have to learn, please feel free to skip right ahead to the ellipse. The <circle> does have a slightly simpler syntax, so if you prefer keeping your keystrokes few, or if the ellipse's eccentricity troubles you in some fundamental way, then <circle> may be worth your while to learn.

The simplest circle requires only a center point (cx,cy) and a radius, r:

<circle cx="80" cy="50" r="40"/>

This produces a circle of radius 40 pixels filled (by default) with black.

Just as with rectangles, we might play with the stroke, the stroke-width and the stroke-dasharray to create various interesting effects. Note that if we wish a circle to appear to have an empty center, we define some stroke color and then set fill="none" to make it hollow. The illustration below shows the effects of adjusting several of these attributes.

SVG code Illustration <circle cx="80" cy="50" r="40"/>



<circle cx="80" cy="110" r="40" fill="red"/>



<circle cx="80" cy="170" r="40"

fill="yellow" stroke="blue" />



<circle cx="80" cy="160" r="20" fill="red" stroke="black" stroke-width="10"/>



<circle cx="140" cy="110" r="60" fill="none" stroke="#579" stroke-width="30"

stroke-dasharray="3,5,8,13"> Circles with varying fill, stroke, stroke-width and stroke-dasharray A similar example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/circles3.svg.

<ellipse>

The ellipse is just like the circle but has two radii instead of one. rx represents half the distance from the leftmost to the rightmost sides, while ry is the distance from top to center of the ellipse. The ellipse is always aligned with its horizontal axis parallel to the bottom of the window, unless one applies a rotation transform (as discussed later in this chapter). The ellipse can be a considerably more evocative shape than a circle, and given that it is a circle when rx=ry, it is more flexible as well.

Identical clusters of ellipses except for stroke-dasharray. The ellipses on the left use dash array, those on the right do not. This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/ellipses2.svg. SVG code Illustration <ellipse cx="80" cy="110" rx="75" ry="105" fill="#538"/>



<ellipse cx="80" cy="110" rx="60" ry="40" fill="black" stroke="red" stroke-width="25"/>



<ellipse cx="80" cy="110" rx="35" ry="20" fill="#538" stroke="yellow" stroke-width="25"/>



<ellipse cx="80" cy="50" rx="40" ry="30" fill="red" stroke="black" stroke-width="25"/>



<ellipse cx="80" cy="50" rx="30" ry="20" fill="orange" stroke="red" stroke-width="10"/>



<ellipse cx="80" cy="170" rx="40" ry="30" fill="yellow" stroke="orange" stroke-width="25" />



<ellipse cx="80" cy="170" rx="30" ry="20" fill="red" stroke="black" stroke-width="10"/>

The code of the two illustrations is identical except that the figure on the left has had the attribute-value pair stroke-dasharray="3,6"added to four of its seven ellipses.

<path>

If one wanted to learn only one drawing primitive, then the <path> would probably be it. It can be used to replace <rect>, <ellipse>, and <circle>, though it would not be advised unless your mental arithmetic skills are quite good (e.g. simultaneous differential equations). <path> is a very flexible drawing option. It renders the movement of a stylus through two dimensions, with both pen-up and pen-down options, including straight and curved segments joined together at vertices which are either smooth or sharp.

There are many aspects of the <path> that we will not discuss here. Fortunately, the W3C's chapter on paths is thorough and has plenty of illustrations of most of its numerous facets. Here, we cover only absolute rather than relative coordinates, and only the raw path elements rather than their simplified forms (such as "S" as a special case of "C"). We will deal with pen-down, linear, quadratic and cubic forms, and arcs.

Like <rect>, <line> and the other elements, we've seen, <path> has attributes like stroke, stroke-width, stroke-dasharray, and fill. But while the other elements we've looked at have special meanings given to particular coordinates (like "rx" or "x2"), the path has a sequence of such coordinates held in an attribute named "d". This string of coordinates can be of arbitrary length.

Paths: M and L

We begin by specifying where the drawing will begin by inserting as the first element of "d" a notation such as "M x y" for numbers x and y. We might think of "M x y" as meaning "move pen to the coordinate x y." From there, we have options of moving (with pen still down on the canvas) linearly (L), quadratically (Q), cubically (C) or through an elliptic arc (A). For example, d="M 100 100 L 200 200" would succeed in drawing a diagonal line from the point (100,100) to the point (200,200), as shown.

SVG code Illustration <path stroke="black"

d="M 100 100 L 200 200"/> A diagonal line from (100,00) to (200,200)

The pen-down and line modes stay in effect until turned off, so we might concatenate yet other pairs of coordinates into the path.

SVG code Illustration <path d="M 100 100

L 200 200 100 150"/> Concatenated pairs of coordinates

A couple of things should be noted. First, in the above example, we did not specify a stroke since, by default, the figure is filled with black. Second, if we specify that a path has no fill (using fill="none") then the path will not appear to loop back to the beginning. Third, we might, for sake of legibility, be tempted to add commas, between pairs of coordinates. This is just fine, in the general case, though a few cases have been reported in which certain browsers seem to be troubled by large numbers of commas as coordinate delimiters. Fourth, we may assume that L (or line) is the default way of moving to the next point, and it need not be specifed. That is d="M 100 100 L 200 200 100 150" should be equivalent to d="M 100,100 200,200 100,150" . These observations are illustrated as follows. Note that once we specify fill="none" the figure will be invisible, unless we specify a stroke.

SVG code Illustration <path d="M 50,100 150,200 50,150"/>



<path d="M 100 50 L 200 150 100 100" fill="none" stroke="black"/> The effect of adding fill="none" (but note that the stroke attribute is defined) This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/path2.svg

The path will also be unclosed — that is, the two endpoints will not be connected unless we specify that they should be. If we wish a path to be closed, we modify it with the z flag at the end of the path as follows:

open:

<path d="M 100,50 200,150 100,100" fill="none" stroke="black"/>

closed:

<path d="M 100,50 200,150 100,100 z" fill="none" stroke="black"/>

Since paths are, by default, filled with black, it is natural to wonder what happens when the path crosses itself. By default, the union of the regions traversed by the path is filled, unless we specify otherwise.

SVG code Illustration <path d="M 70,290 L 150,150 200,250 40,250 100,150 170,290"/> <path d="M 70,290 L 150,150 200,250 40,250 100,150 170,290" fill-rule="evenodd"/> An example to show the difference between the default and "even-odd" fill rules

Here we show the default fill technique as well as the "even-odd" fill rule on a shape which intersects itself on more than one occasion. The points are labeled just to make it easier to read what might seem a long list of six coordinate pairs.

Another interesting aspect of <path> is that we might combine multiple path segments into a common path definition. That is, a path may have multiple components by having more than one pen-down operation. Note in the figure below that the two path segments are indeed treated as one since the orange fill is applied to the entire figure rather than to the two separate triangular components. The interior of the figure is also transparent, as illustrated by the rotated and reduced version of the image appearing partly inside and partly outside the foreground figure.

SVG code Illustration <path fill="orange"

d="M 10,215 210,215 110, 42 z

M 10,100 210,100 110,273 z"

stroke="purple" stroke-width="3"/> A <path> with fill="green" et cetera... is also included in the drawing.

Paths: Q — Quadratic Bézier curves.

I became aware of Bézier curves in the mid 1980s when I discovered that Adobe Illustrator had the ability to draw amazing curves quickly. I did not know what sort of crazy-fast mathematics would be able to solve all those equations so quickly. A good treatment of the subject may be found at Wikipedia.

Here's basically how a quadratic Bézier works in SVG. We define an initial point (say 100,200) with a pen-down. From there, we set a course heading toward the next point. Instead of going to the next point, we just aim that direction. So, for example, while "M 100 200 L 200 400" actually arrives at the point "200,400", "M 100 200 Q 200 400 … " merely heads that way. Ultimately, in addition to a "heading" we also have a final "destination" and that is the final coordinate pair required of the quadratic Bézier. In the illustration we see that.

"M 100,200 L 200,400 300,200"

draws a red path between (and reaching each of) the three points indicated. Simply replacing the "L" with a "Q" to draw

"M 100,200 Q 200,400 300,200"

produces a curve passing through both endpoints, and becoming tangent to the associated lines of the allied line-path at the endpoints to the segments.

SVG code Illustration <path d="M 100 200 Q 200,400 300,200" fill="none" stroke="blue" />

<path d="M 100 200 L 200,400 300,200" fill="none" stroke="red"/> Bézier curve example

While there is an infinite family of curves tangent both to the line "M 100 200 L 200 300" at (100, 200) and to "M 200 400 L 300 200" at (300,200), there is only one quadratic that shares these properties, even if we allow for rotations (in the sense of parametric equations) of the quadratic. That is, the curve is uniquely defined by those three points in the plane. Likewise, any three non-collinear points in the plane determine one quadratic Bézier curve.

Revisiting the earlier example in which the fill-rule was modified to produce an empty space in the middle of the curve, we may draw the same curve with quadratic splines instead of lines to see the effect.

SVG code Illustration <path fill-rule="evenodd

d="M 70 140 L 150,0 200,100 L 40,100 100,0 L 170,140 70 140"/>



<path fill="red" fill-rule="evenodd"

d="M 70 140 Q 150,0 200,100 Q 40,100 100,0 Q 170,140 70 140"/> An example of a graphic using a quadratic spline

Paths: C — Cubic Bézier curves.

We can imagine raising the degree of the polynomial to allow the satisfaction of increasingly more constraints on a curve. With a cubic Bézier, we are able to change the skewness and kurtosis of a curve tangent to the inscribing polygon at the specified endpoint, because instead of a single "control point" affecting the direction of the curve, we now have two control points.

A family of cubic curves sharing endpoints and tangents

In the above figure, we see the effect of allowing the two control points to move symmetrically along the edges of the triangle in the direction of the vertex at (200,400). All four cubic Béziers are like the quadratic Bézier (in blue) in that they have the same starting and end points and are all tangent to the same lines at those points. Each curve as we move down from the red curve to the sharp red angle has control points which are along the lines, but progressively closer to the vertex.

A sort of limiting case can be seen in the following diagram in which the two control points converge to either the end points of the curve or to the vertex. The lower of the two green curves never gets any lower than what is shown, though the higher green curve will be equivalent to the line when d="M 0,0 C 0,0 400,0 400,0". Effectively then the kurtosis, or peakedness, of the curve can be adjusted anywhere between the ranges shown.

Limiting case for a family of curves

While the above examples adjust the two control points symmetrically, we may adjust the skewness or asymmetry of the curve by adjusting the two control points asymmetrically.

Ultimately, the power of cubic Béziers can be seen in this ability to bend flexibly in 2D. Additionally, they may be stitched together piecewise and smoothly so as to make cubic splines that can approximate any 2D curve with what is usually acceptable accuracy.

The following illustrates a collection of curves each tangent to the same pair of lines at the same pair of endpoints:

Cubic beziers sharing tangents and endpoints

The following demonstrates how Bézier curves may be stitched together smoothly. For this to happen, it is necessary that the slopes of the lines at either side of a segment's endpoint be the same.

Adjoining two cubic curves smoothly This example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/path8a.svg

Observe that the two paths "brown" and "blue" share beginning and end points, initial and final control points, as well as midpoints (150,200). They differ only in terms of the control points surrounding the midpoint. The blue path aims toward (100,100) and then changes direction toward (200,300) passing through the midpoint on its way and there tangent to the line as shown. Because the three relevant points (100,100), (150,200) and (200,300) are collinear, the slopes of both segments are the same at the point where they meet, implying that the curve is smooth (continuously differentiable) at that point. The principle is applied repeatedly in the following illustration in which each labeled endpoint of a cubic Bézier is surrounded by two points collinear with it.

SVG code Illustration <path stroke="black"

stroke-width="3" fill="#eec1c2"

d="M 99 192

C 137 160 204 133 141 124

C 78 115 34 167 47 129

C 60 91 20 65 77 71

C 134 77 206 43 196 101

C 186 159 118 368 119 299

C 120 230 201 169 138 206

C 75 243 53 231 99 192" /> Several smoothly stitched Bézier segments

Paths: A — Elliptical arc.

One other aspect of the <path> deserves mention. That is the elliptical arc. It might seem that an arc would be a very simple topic, but when we realize that given any two points in the plane and two elliptical radii, there often are two ellipses that traverse those points with specified radii and those points specify two different arcs for each ellipse. The arc subcommand of the <path> has the following syntax: A rx ry XAR large-arc-flag sweep-flag x y. The arc begins at the current point (determined by the last coordinate specified, e.g. by the M subcommand), and ends at (x,y). The ellipse will have radii of rx and ry, with the x-axis of the ellipse being rotated by XAR degrees. The particular ellipse (of the two possible) is specified by the large-arc-flag (0 or 1) and the particular segment of the ellipse is specified by the sweep-flag. (0 or 1). The following illustration shows two different ellipses passing through (100,100) and (200,150) each with different choices for its sweep-flag. The yellow arc is identical to the red one, and the blue to the green, except for the sweep-flag. Both ellipses have had zero rotation applied.

Four elliptical arcs sharing endpoints This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/arcs.svg

Opacity

Ordinarily all of our drawn objects are completely opaque. That is, opacity is, by default, 100%. If we wish to make things partly transparent, it is very easy: we simply add opacity=p for some number 0<p<1 as an (attribute, value) pair into the tag we wish to modify. A simple example is the preceding illustration of arc segments in which each of the four arc segments is given an opacity of 0.5, allowing any underlying objects to shine through:

<path d="M100 100 A 30,50 0 0,0 200,150 z"

fill="#080" stroke="#8f8" stroke-width="5" opacity="0.5"/>



<path d="M100 100 A 30,50 0 0,1 200,150 z"

fill="#088" stroke="cyan" stroke-width="5" opacity="0.5"/>



<path d="M100 100 A300,30 0 0,0 200,150 "

fill="#880" stroke="yellow" stroke-width="5" opacity="0.5" />



<path d="M100 100 A300,30 0 0,1 200,150 "

id="red" fill="#800" stroke-width="5" opacity="0.5"/>

<image>

The <image> tag in SVG is much like the <img> tag in HTML: a way of putting the contents of an image file (PNG, JPEG, or SVG formats) into a rectangle on a page. I am not quite sure why a vector graphics language came to have methods for inserting bitmaps. It makes sense, though, since most vector drawing packages give ready access to bitmaps. It certainly expands our graphics repertoire. Additionally, numerous interesting filters exist within SVG which give us considerable power at manipulating bitmapped as well as vector graphics.

Generally we include a tag much like a <rect>. We specify the upper left corner of the rectangle (x,y) we specify its width and height, and we specify the file or URL from which the material will be loaded.

<image xlink:href="filename" x="100" y="100" width="150" height="200" />

SVG code Illustration <image xlink:href="p72.jpg" height="200" width="100" x="100" y="100"/>



<image xlink:href="path6b.svg" height="200" width="100" x="105" y="150"/>



<image xlink:href="p17.jpg" height="100" width="100" x="200" y="100"/>



<image xlink:href="p18.jpg" height="100" width="100" x="200" y="200"/>



<image xlink:href="p11.jpg" height="200" width="100" x="300" y="100"



preserveAspectRatio="xMinYMid"/>



<image xlink:href="path6b.svg" height="200" width="100" x="310" y="150"/> Several uses of the image tag

We observe that:

Images may overlap. Each of the instances of the "path6b.svg" file overlaps with other images.

Transparency, if it exists in the file, is preserved.

By default a bitmapped image stretches to fill the rectangle provided.

We may preserve the aspect ratio of an image.

It is also important to note that as of this writing, Firefox does not appear to support .svg file types in the <image> tag and both Chrome and Safari seem to have some oddities associated with aspect ratios in this context. (Similar issues can be observed vis á vis browser support for the <img> tag in HTML.) SMIL animation (discussed later) does not seem to be supported by content in the <image> tag — that is, a .svg file containing SMIL will not currently be animated when imported via <image>. It is also worth noting that if and when the other browsers do offer support for .svg file types, syntax of the following sort may be preferred since it is namespace-aware:

<image xmlns:xlink=http://www.w3.org/1999/xlink

xlink:href="myfile.svg"

x="10" y="10" width="100" height="100" />

Alternatively, we will frequently include an attribute assignment which reads

xmlns:xlink=http://www.w3.org/1999/xlink

in the opening <svg> tag. This allows the XML definition of all such compound attributes beginning with "xlink" as in xlink:href="url(#r)" to be interpreted properly throughout the document.

<text>

Putting text on a page is a natural thing to do. Future versions of SVG are likely to offer more possibilities than we have at the moment and browser support for text seems to be poised for improvement. Right now one should be aware that there are some problems associated with the appearance of text across browsers.

Nevertheless a few simpler things may be done reliably, simply and consistently. Here's a sort of simplest case:

SVG code Illustration <text x="0" y="100" font-size="80" fill="red">

Doing text</text> Layout and size of text This example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/text2.svg.

The dimensions of the text (obtained by using the method getBBox(), discussed in later chapters) varies a bit between browsers as shown in table 2 below. Interestingly, similar differences remain in effect even when font-family="monospace" is specified (which was unsupported in FF1.5).

Browser Left Top Bottom Right ASV+IE 6.15 42.72 115.79 359.48 FF1.5 6 42 117 358 Opera 9 -0.14 28.47 118.53 337.37 Table 2: Results returned by different browsers for the getBBox() function

Similar results would be observed for HTML since a fundamental premise of the web has been that font support and layout is a choice left to the browser software.

The W3C SVG specification reveals that SVG fonts should be equivalent to those of CSS-2, but it may be important to specify generic font families (specifically serif, sans-serif, cursive, fantasy or monospace) to increase the probability that your visitors' browsers can see them. Even so, as the following illustrates, current browser support for font-families is lagging behind the specifications.

Appearance of fonts in different browsers: ASV+IE, FF1.5 and Opera 9 respectively

The specification also provides dozens of other ways of controlling the appearance of text, some of which have been implemented in existing browsers. Below is a sampling of some effects that are possible in at least some browsers already:

Styling and decoration of text This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/text6.svg.

As of Spring 2009 all five of the primary browsers now support text effects such as shown below.

SVG code Illustration <defs>



<path id="curve" d="M 10 100 C 200 30 300 250 350 50"

stroke="black" fill="none" stroke-width="5" />



</defs>



<text id="T" style="font-family:ariel;font-size:16">



<textPath xlink:href="curve">Hello, here is some text lying along a bezier curve.</textPath>



</text> Text along a Bézier curve

The path above is defined inside a <defs> tag which serves to define the path but without rendering it. Various flags exist which adjust the positioning of the text along the path, many of which seem not yet to be supported by browsers. One exception is the startOffset attribute of the <textPath> which provides a distance in pixels from the beginning of the curve, where the text will actually begin. When animated with SMIL (see Chapter 4), this attribute makes the text appear to crawl along the curve with speed determined by the SMIL.

The rate at which browser improvement is bringing new features forward would render quite out-of-date any attempt to state a list of currently supported features, but suffice it to say, there are major browser differences here at the current time.

Operations: Grouping, Reusing, Scaling, Translation and Rotation

Thus far we have had the opportunity to see much similarity between SVG and HTML: two markup languages with tags and attributes that modify the way those tags look. Where SVG starts to look less like a markup language and more like a programming environment is in its ability to reuse and modify its own content (within its own system). That is, elements can be contained in other elements in such a way that containers modify the appearance of the elements inside them. Specifically we can group and reuse elements in ways that simplify maintenance of code and which shorten the overall length of our documents. The <use> (reuse) and <g> (or group) tags bear similarity to the variables and objects encountered in programming languages. And while those tags can be exemplified with examples drawing just on the "simple objects" discussed earlier in this chapter, their utility becomes, perhaps more pronounced once we have the abilities to transform objects using the isometric planar primitive operations of translation, rotation (including reflection), and scaling.

Transform/translate:

The three easiet ways to move things around in SVG are rotation, scaling and translation. All are considered to be special cases of the transform attribute of a tag. Suppose we have an object, like a complex path, which we have drawn (either by typing coordinates, or with a graphical editor) and once we bring it into our SVG document, we discover, that while we like the shape, it needs to be moved around a bit. That's what transform=translate is for. The syntax looks like this:

transform=translate( dx , dy )

where dx and dy represent the change in the current position on the x and y axes. Using transform=translate(0,0) would leave an object at its current position. Here's a simple example in which a complex path is drawn near a simple ellipse, before and after the application of a translation 100 pixels leftward and 100 pixels up:

transform=translate( dx , dy ) This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/translate.svg. Before translation After translation <path id = "P2" stroke = "black" stroke-width ="2" opacity = ".6" fill = "#c77" d = "M 150 220 C 145 244 146 251 135 260 C 124 269 114 287 134 282 C 154 277 162 279 159 288 C 156 297 135 305 148 308 C 161 311 185 315 172 315 C 159 315 150 309 147 314 C 144 319 159 322 156 327 C 153 332 141 348 153 354 C 165 360 185 361 194 354 C 203 347 214 357 212 368 C 210 379 196 400 204 400 C 212 400 237 396 250 394 C 263 392 279 374 276 353 C 273 332 276 308 286 289 C 296 270 325 240 321 215 C 317 190 304 179 286 158 C 268 137 253 111 216 120 C 179 129 163 144 150 170 C 137 196 150 210 160 212 C 170 214 160 222 150 220 " /> <path id = "P2" stroke = "black" stroke-width = "2" opacity = ".6" fill = "#c77" transform="translate(-100,-100)" d = "M 150 220 C 145 244 146 251 135 260 C 124 269 114 287 134 282 C 154 277 162 279 159 288 C 156 297 135 305 148 308 C 161 311 185 315 172 315 C 159 315 150 309 147 314 C 144 319 159 322 156 327 C 153 332 141 348 153 354 C 165 360 185 361 194 354 C 203 347 214 357 212 368 C 210 379 196 400 204 400 C 212 400 237 396 250 394 C 263 392 279 374 276 353 C 273 332 276 308 286 289 C 296 270 325 240 321 215 C 317 190 304 179 286 158 C 268 137 253 111 216 120 C 179 129 163 144 150 170 C 137 196 150 210 160 212 C 170 214 160 222 150 220 " />

Transform/rotate

If we have drawn an object like an ellipse, centered at (cx,cy) and we wish to rotate it clockwise by r degrees, then transform=rotate( r , cx, cy) is the attribute for us. Following is an example of a figure before and after rotation of 120 degrees. The operation is performed via:

transform="rotate(120,219.5,241)"

The point (219.5, 241) is chosen as the center of rotation, since it represents the midpoint of the bounding rectangle enclosing the un-rotated shape. (Again this point is determined through a JavaScript calculation involving getBBox() , a method that will be discussed later.)

Rotating about the center This example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/transformRotate1.svg.

Transform/scale

Scaling or resizing an object is a wee bit tricky. The syntax of the command is straightforward but since the scaling operation multiplies all (x,y) coordinates by scaling coefficients, objects will typically appear to move away from or toward the origin as they expand or shrink. In order to keep an object more or less "in place" as it is rescaled, we must combine the scale operation with a translation. Another side effect of scaling is that when negative numbers are multiplied by all the coordinates, the object will appear to flip or reflect about one or both axes.

The illustration below shows an ellipse centered at (100,50) (as well as an accompanying text label), before and after a rescale by a factor of 2.5. Note that the ellipse's center (like all the points on the ellipse) has each of its coordinates rescaled by the same factor.

Before rescaling With rescaling <ellipse

cx="100" cy="50" rx="40" ry="20" fill="grey" stroke="black" stroke-width="12" stroke-dasharray="3,5,2"/> <ellipse transform="scale(2.5)" cx="100" cy="50" rx="40" ry="20" fill="grey" stroke="black" stroke-width="12" stroke-dasharray="3,5,2"/> Ellipse, with and without scaling

Note that the scale command resizes not only the object, but also its border or stroke.

If we wish to expand a figure differently in one direction than the other, we simply add a second parameter to the transform as shown in the following in which we rescale by a factor of three horizontally, but only x 1.2 vertically.

Before rescaling With rescaling <path d="M 70 50 L 120,50 120,0 170,100 70,120z" fill="grey" stroke="black" stroke-width="4" stroke-dasharray="1,5"/>/code> <path transform="scale(3,1.2)" d="M 70 50 L 120,50 120,0 170,100 70,120z" fill="grey" stroke="black" stroke-width="4" stroke-dasharray="1,5"/> Rescaling more horizontally than vertically

Note here that the hash marks associated with the dasharray remain no longer perpendicular to the path.

Below is an example in which we scale differentially in the x and y directions, preserving the height by multiplying it by 1.0, but flipping and shrinking horizontally by multiplying by -0.5.

Differential, negative and fractional scaling

To see how we might scale something while keeping it centered about the same point, we use multiple transformations: a scale and a translation, as demonstrated in the next section.

multiple transformations and more

We may combine transformations by simply concatenating as follows:

transform="translate(-100,-50),scale(1.5)"

The operations are performed in the order right to left, so in the above case, the scale is applied first, moving all points 1.5 times further from the origin. Then the figure is moved upward to the left.

In the following, we see how rescaling followed by a translation produces the desired effect of expanding an ellipse but keeping it centered about the same location.

Scale then translate

The original ellipse is centered at (200,100). When we simply rescale it, by a factor of 1.5, the center moves accordingly to (300,150), namely to 1.5 x (200,100). To move the ellipse back to its original center, we then apply a translation: translate (-100,-50), since (300,150) + (-100,-50) = (200,100). This sort of arithmetic is easily automated, if need be, through the use of JavaScript.

There are two other things about transformations that your author would like you to be aware of.

We may skew objects (deform from their rectangle to an arbitrary parallelogram having two sides parallel to the original) in SVG using SkewX and SkewY tranformations. We may perform combinations of skew, rotate, translate, and scale using something called the CTM or current transformation matrix. It comes in handy should a whole collection of transforms be applied to an object and we wish to figure out, where at last, it has ended up. This topic is discussed a bit more when we talk about scripting in a later chapter.

Grouping

Once we start taking the things we have built and moving them around on the screen, it is natural to want some of them to move together as a unit. The group tag, or <g>, is a tag that merely serves to put elements together, so that they might share a common set of transformations or other attributes.

Consider the simple figure drawn below with its code as shown:

SVG code Illustration <rect x="100" y="100" width="100" height="20" fill="#888" />

<rect x="100" y="160" width="100" height="20" fill="#888" />

<ellipse cx="150" cy="140" rx="30" ry="100" fill="#bbb" />

<rect x="100" y="130" width="100" height="20" fill="#888" /> Three rects and an oval

If we wanted to make three copies of it all side by side as in the following illustration, then we could perform two editing replacements: first change all the x="100" statements to x="-20" and the cx="150" to cx="30", then, in the next copy, change the x="100" to x="220"and cx="150" to cx="270". The four statements turn into 12 statements, 8 of which have simple editing applied to effect the change.

Manually editing lots of coordinates <rect x="-20"y="100" width="100"

height="20" fill="#888" />



<rect x="-20" y="160" width="100"

height="20" fill="#888" />



<ellipse cx="30" cy="140" rx="30"

ry="100" fill="#bbb" />



<rect x="-20"y="130" width="100"

height="20" fill="#888" /> <rect x="100" y="100" width="100"

height="20" fill="#888" />



<rect x="100" y="160" width="100"

height="20" fill="#888" />



<ellipse cx="150" cy="140" rx="30"

ry="100" fill="#bbb" />



<rect x="100" y="130" width="100"

height="20" fill="#888" /> <rect x="220" y="100" width="100"

height="20" fill="#888" />



<rect x="220" y="160" width="100"

height="20" fill="#888" />



<ellipse cx="270" cy="140" rx="30"

ry="100" fill="#bbb" />



<rect x="220" y="130" width="100"

height="20" fill="#888" />

If the object being replicated were a complex path, the amount of arithmetic we would have to do might become annoying. Fortunately, the <g> tag saves us some work, since instead we might just duplicate the code twice, placing each copy inside groups: <g>copy1</g>, <g>copy2</g> and then apply a separate transform to each as shown:

Using <g> groups to replicate code with transforms Transform group 120 pixels to the left Original Code Transform group 120 pixels to the right <g transform = translate(-120,0)>

[place a copy of the same code here]

</g> <rect x="100" y="100" width="100"

height="20" fill="#888" />



<rect x="100" y="160" width="100"

height="20" fill="#888" />



<ellipse cx="150" cy="140" rx="30"

ry="100" fill="#bbb" />



<rect x="100" y="130" width="100"

height="20" fill="#888" /> <g transform = translate(120,0)>

[place another copy of the same code here]

</g>

We end up with a few more characters, but considerably less cognitive effort and time will be expended.

Inheriting attributes from the group

The group tag may also be used to define other attributes of elements within the group, such as the color used to fill some or all objects. If an object has an attribute defined as

someNamedAttribute="inherit"

then it will take whatever value of that attribute its containing group has been assigned.

In the following illustration, code is reused more effectively than manually editing each of the six rectangles, by letting the rectangles inherit their fill color from their groups.

Inheriting attributes from the group <g fill="black">

<rect x="100" y="100" width="100" height="20" fill="inherit"/>



<rect x="100" y="160" width="100" height="20"

fill="inherit" />



<ellipse cx="150" cy="140" rx="30" ry="100" fill="#777" />



<rect x="100" y="130" width="100" height="20"

fill="inherit" />

</g> <g transform="translate(120,0)"

fill="#bbb">



<rect x="100" y="100" width="100" height="20"

fill="inherit" />



<rect x="100" y="160" width="100" height="20"

fill="inherit" />



<ellipse cx="150" cy="140" rx="30" ry="100"

fill="#777" />



<rect x="100" y="130" width="100" height="20"

fill="inherit" />



</g>

In the next section we accomplish the same result but with considerably less code, using the <use> tag.

<use>

One more important way to reuse code, and, hence, simplify the process of adjusting it later on, is the <use> tag. This allows us to define an object, give it an identifier (an "id" attribute) and then to reuse that object later on, without having to copy all of its code. Working again with the example used earlier, we will show one more way to not only reuse code, but to simplify it and reduce the overall number of characters.

Reusing code (with modifications) — the <use> tag #1 <g fill="black">

<g id="G">



<rect x="100" y="100" width="100" height="20" fill="inherit" />

<rect x="100" y="160" width="100" height="20" fill="inherit" />

<ellipse cx="150" cy="140" rx="30" ry="100" fill="#777" />

<rect x="100" y="130" width="100" height="20" fill="inherit" />



</g></g> #2 <use xlink:href="G" transform="translate(120,0)" fill="#bbb">

Above we have built the three rectangles and the oval, with the fill color of the rectangles left undefined: that is, to be inherited from their group. We then put all four objects inside a group with id="G". That group can then be referred to within a <use> tag, by simply typing:

xlink:href="G"

This (a hypertext link to the object in this document known as "G") takes all the code within the object "G" and, as a part of the <use>, builds another instance. In this case we have applied a transform to the new instance to slide it to the left, but we have also defined fill="#bbb" so that all objects having the fill="inherit" property (in this case, just the three rectangles) are colored light grey. In the meantime, we must still assign a color to the rectangles of the first instance, so I've wrapped the group "G" in yet another container and given that container its own fill color (black).

Another example may help illustrate the compactness and utility that <use> can bring to our code.

Step 1: We begin with an ellipse and two copies of it, rotated either 30 or 60 degrees.

Re-using an ellipse — Step 1 SVG code Illustration <g stroke="black" stroke-width="2" fill="none" > <ellipse id="g1" cx="100" cy="100" rx="75" ry="40" /> <use xlink:href="g1" transform="rotate(30 100 100)"/> <use xlink:href="g1" transform="rotate(60 100 100)"/> </g>

Step 2: We then take the three ellipses, put them in a group, with id="g2"; and then reuse that group, with a new rotation of 90 degrees applied to the whole group. This means we will now have a whole flower consisting of six ellipses (each with different rotations: 0,30,60,90,120 and 150 degrees). Since we intend to also reuse this flower, we'll wrap it together in its own group with id="g3" and let the stroke and fill properties go up to the outermost container, since all things inside share those attribute values.

Re-using an ellipse — Step 2 SVG code Illustration <g id="g3" stroke="black" stroke-width="2" fill="none"> <g id="g2"> <ellipse id="g1" cx="100" cy="100" rx="75" ry="40" /> <use xlink:href="g1" transform="rotate(30 100 100)"/> <use xlink:href="g1" transform="rotate(60 100 100)"/> </g> <use xlink:href="g2" transform="rotate(90 100 100)"/> </g>

Step 3. Having grouped the six ellipses together into the object "g3", we will now reuse that object three more times, each with a different color and position. To do this we let the stroke property move up to a new top level that contains the first flower, allowing the inner object "g3" to have its own stroke undefined. Each of the <use> tags which reuse "g3" can then impart its own stroke color.

Re-using an ellipse — Step 3 An animated example of this can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/use4.svg. SVG code Illustration <g stroke="black"> <g id="g3" fill="none" stroke-width="2"> <g id="g2"> <ellipse id="g1" cx="100" cy="100" rx="75" ry="40"/> <use xlink:href="#g1" transform="rotate(30 100 100)"/> <use xlink:href="#g1" transform="rotate(60 100 100)"/> </g> <use xlink:href="#g2" transform="rotate(90 100 100)"/> </g> </g> <g stroke="blue" transform="translate(80,0)"> <g id="g3" fill="none" stroke-width="2"> <g id="g2"> <ellipse id="g1" cx="100" cy="100" rx="75" ry="40"/> <use xlink:href="#g1" transform="rotate(30 100 100)"/> <use xlink:href="#g1" transform="rotate(60 100 100)"/> </g> <use xlink:href="#g2" transform="rotate(90 100 100)"/> </g> </g> <g stroke="red" transform="translate(0,80)"> <g id="g3" fill="none" stroke-width="2"> <g id="g2"> <ellipse id="g1" cx="100" cy="100" rx="75" ry="40"/> <use xlink:href="#g1" transform="rotate(30 100 100)"/> <use xlink:href="#g1" transform="rotate(60 100 100)"/> </g> <use xlink:href="#g2" transform="rotate(90 100 100)"/> </g> </g> <g stroke="green" transform="translate(80,80)"> <g id="g3" fill="none" stroke-width="2"> <g id="g2"> <ellipse id="g1" cx="100" cy="100" rx="75" ry="40"/> <use xlink:href="#g1" transform="rotate(30 100 100)"/> <use xlink:href="#g1" transform="rotate(60 100 100)"/> </g> <use xlink:href="#g2" transform="rotate(90 100 100)"/> </g> </g>

Putting SVG in a web page

Chapter 6 discusses the issue of various HTML containers that can be used to display SVG content in an HTML web page. We might use <iframe>, <embed> <object> or even <img> and each will work to some extent in modern versions of the five browsers: Firefox, ASV+Internet Explorer, Opera, Chrome, and Safari. While <object> would be the preferred approach from the perspective of compliance with W3C standards, some problems exist with both it and the <iframe> that make "<embed>" a persistent practical recommendation from some experts. Others point out that this is only for consistency with IE and the ASV plugin and that <object> is preferable.

Later, in Chapter 6, concerning SVG and HTML, ways of using the more "standards-compliant" <object> tag for SVG content in HTML, as well as "in-line" SVG will be discussed. My own experiments (see, for example, here and here) together with certain other factors, lead me to use <embed> as the vehicle of choice, though this issue will be discussed in more detail later.

Given an SVG document, saved with a .svg extension, it may be placed in a web page using an <embed> as follows:

Code Illustration somefileA.svg <svg xmlns="http://www.w3.org/2000/svg">

<circle r="50"/>

</svg> webpage.html <html><body><strong>

Here is a web page with an <br> SVG file embedded in it</strong><br>

<embed src="/somefileA.svg" height="50"></body></html>

This is much as it should appear in any of Firefox, ASV+Internet Explorer, Safari, Opera or Chrome. It is a sort of simplest case, in that fewer keystrokes in the SVG file will probably not do anything in at least one of the browsers.

Notes:

The xmlns variable, which in essence instructs the browser how to interpret the dialect of XML known as SVG is required by the standard though some browsers may allow us to leave out those 34 characters. Some browsers do require it so it is best to get accustomed to including it.

The height="50" attribute in the HTML document may be required in some browsers for the <embed> to be visible.

That the circle appears as a quarter-circle rather than a whole circle derives from the fact that no cx or cy is specified; by default, both are assumed to be zero.

An additional variable should be set if one uses any xlink:href attributes in one's document. This was mentioned in this chapter when discussed the <image> tag, but many SVG authors include an attribute value which reads xmlns:xlink="http://www.w3.org/1999/xlink" in their opening <svg> tag. This allows the XML definition of compound attributes (beginning with "xlink" as in xlink:href="url(# r )") to be interpreted properly by the browser.

A natural question emerges at this point: how might we adjust the <embed> so that the SVG content fits properly? There are several issues associated with this question.

If we as programmers know how big the content in the SVG file is (a sort of smallest rectangle starting at the origin which contains all the drawn objects), then we simply find that amount of real estate in our web page and allocate it to the SVG object through setting attributes on the <embed>. In the example below, we fail to allocate enough space for the <embed> and it appears truncated on the page.

The effect of specifying different dimensions for the embed element Code Illustration somefileA.svg <svg

xmlns="http://www.w3.org/2000/svg">

<circle r="50" cx="100" cy="100"/>

</svg> webpage.html <html><body><strong>

Here is a web page with an <br> SVG

file embedded in it</strong><br>

<embed src="/somefileB.svg" height="100"

width="100"style="border:solid #999 1">

And more <br>just for good measure.

</body></html> We change the <embed> so it's bigger: And now the graphic fits <embed src="/somefile1.svg" height="150" width="150"

style="border:solid #999 1">

Increasing the size of the <embed> allows the graphic to fit in the viewing area. But in this case we had to take what we knew of the radius of the circle and add that to its center to calculate an appropriate size for the <embed>. We might prefer a technique which adjusts to the graphic more automatically. The following accomplishes this by establishing a "viewBox": a relativized coordinate system within the SVG. By centering the circle relative to the SVG space through the viewBox (which is, in this case, a 200 x 200 pixel rectangle) and then letting the height and width attributes of the SVG expand to 100% of the available space, then, the SVG will expand or contract as needed to fit the <embed>. More on the viewBox attribute will be discussed in the section on zooming and panning in a later chapter.

Introducing the viewBox Code Illustration somefileC.svg <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 200 200">

<circle r="50" cx="100" cy="100"/>

</svg> webpage.html <html><body><b>

Here is a web page with an <br> SVG

file embedded in it</b><br>

<embed src="/somefileC.svg"

height="100" width="100" style="border:solid #999 1">

And more <br>just for good measure.

</body></html>

The above solution scales nicely, in the sense that if we define the size of the embed as a percentage of the browser window then the SVG will expand or contract in a more customized way.

HTML Code Appearance in the browser <html><body><strong> Here is a web page with an <br> SVG file embedded in it</strong>



<embed src="/somefileC.svg" width="100%" height="30%" style="border:solid #999 1">

And more <br>just for good measure.



</body></html> SVG scaled to a proportion of size of web page

If we wish to use JavaScript to interact with the SVG document (though these topics are the subject of much to come in later chapters), then we may wish to know the size of the SVG object (if it is specified in absolute terms). To determine its width and height we might use

document.embeds[0].clientWidth

document.embeds[0].clientHeight.

Since users of Internet Explorer and some older browsers will need the Adobe SVG Viewer plugin, it makes good sense to include the following attribute in one's embed tag:

pluginspage="http://www.adobe.com/svg/viewer/install/"

This allows the user to find out what they need in order to actually see the SVG should the browser not be SVG capable.

If one is interested in compliance even with very old browsers (e.g. Netscape Navigator 4 or older) the SVG Wiki suggests wrapping an <object> around an <embed> as follows:

<object data="sample.svgz" type="image/svg+xml" width="400" height="300">

<embed src="/sample.svgz" type="image/svg+xml" width="400" height="300" />

</object>

What does seem to work for both ASV+Internet Explorer and other browsers is the following:

<object id="E" type="image/svg+xml" data="ovals.svg" width="320" height="240">

<param name="src" value="ovals.svg">

</object>

Again, while it seems that the browser developers are beginning to converge on workable solutions to these things, the future may see the use of <embed> decline as support for <object> becomes stronger, consistent with published standards. However, with the HTML standard under current revision (<embed> is in the current HTML5 draft) and with alternatives to the Adobe plugin likely to emerge it is difficult to see how this particular microfuture may develop.

Using events within either HTML or SVG to send messages to the other's scripts and DOM is covered in detail later.

Chapter III - Fancier SVG Effects

As a graphics language, SVG is not limited to just a set of graphic primitives (albeit ones with a rich set of attributes). There are other ways of filling, cropping and distorting objects that greatly enhance our arsenal of tools.



Gradients

The term "gradient" refers to a gradual change of colors, blending from one into the next, generally with the small local changes in color values being imperceptible. It is fairly easy to define a gradient in SVG. First we build a gradient object, then we use it as the fill (or stroke) of another object or set of objects. The gradient object consists of a series of colors (called stop-colors) and the ways those colors will be faded into one another. There are two primary types of gradient: radial, in which the colors surround some central point in concentric bands, and linear in which the transitions all take place perpendicular to some basic line or direction.

<stop> and stop-color

Gradients applied to a path <path d="M 100 200 200 200 150 100 z"

stroke="black" stroke-width="2" fill="url(#g)" /> linear radial <linearGradient id="g"> <stop offset="0" stop-color="white"/> <stop offset="1" stop-color="black"/> </linearGradient> <radialGradient id="g"> <stop offset="0" stop-color="white"/> <stop offset="1" stop-color="black"/> </radialGradient> White is applied from left to right White is applied from center to outside

The object to which the gradient will be applied uses a local url (similar to the xlink:href we saw earlier with the <use> object) as the attribute value of the "fill" attribute, hence demonstrating that an object may have a color or a gradient as its fill, but not both.

Note that in the linear gradient above, two "stops" have been built. This means the gradient has two colors applied to it, one for each stop. Those colors are determined by the stop-color attribute. The offset attribute determines where between 0% and 1=100% of the way from left to right, the associated color (in this case black or white) should be applied. That is, white is applied at the leftmost part of the triangle, while black is applied to the rightmost part. Shades of grey gradually darken as we move to the right, with a grayscale value of 128/256 or 50% occurring halfway across the image or along the line where x=150. For the radial gradient, the midpoint of the bounding rectangle around the path is chosen as the center. From there we apply our first stop-color (zero percent of the way out toward the corners of the bounding box). Black will be applied to the four corners of the bounding rectangle, with shades of grey gradually lightening as we move toward the center.

More <stop>s

The number of stops in a gradient need not be limited to two. The rectangles below are 200 pixels wide. That means the linear gradient is white at 0 pixels and 150 pixels from the left, and black at 50 and 200 pixels.



Four stops apiece for linear and radial gradients applied to <rect> <stop offset="0" stop-color="white"/>

<stop offset=".25" stop-color="black"/>

<stop offset=".75" stop-color="white"/>

<stop offset="1" stop-color="black"/>

Varying angles and centers

Next, we observe that we can change the angle that a linear gradient traverses its fill, or the center point from which the waves of the radial gradient ripple outward.

The linear gradient in the underlying layer has several stops in black, white and grey. Ordinarily the color-bands would run vertically. We have rotated their angle 30 degrees though with a gradientTransform, rotated about the center (50%,50%) of the <rect>. The radial gradient in the foreground has had its fx (the x position of its focus) changed to 95% meaning that instead of concentric rings being centered about the middle of the <rect>, they are now offset to its extreme right side. <linearGradient id="l" gradientTransform="rotate(30 .5 .5)">

<stop offset=".0" stop-color="black"/>

<stop offset=".1" stop-color="white"/>

<stop offset=".2" stop-color="black"/>

<stop offset=".3" stop-color="grey"/>

<stop offset=".4" stop-color="black"/>

<stop offset=".7" stop-color="white"/>

<stop offset=".9" stop-color="black"/>

</linearGradient>

<rect fill="url(#l)" width="200" height="200"/> <radialGradient id="r" fx=".95">

<stop offset=".1" stop-color="white"/>

<stop offset=".6" stop-color="black"/>

<stop offset=".9" stop-color="white"/>

<stop offset="1" stop-color="black"/>

</radialGradient>

<rect fill="url(#r)" y="60" width="200" height="80"/>

Stop-opacity

In addition to specifying the color of a <stop> within a gradient, we may also specify its opacity through an attribute known as stop-opacity. We may thus make gradients act like differential masks, gradually allowing an image underneath to fade in to view.

<stop offset=".8" stop-color="black" stop-opacity="0.5"/>

Stop-opacity (like regular opacity of drawn objects) takes on values between 0 (transparent) and 1.0 (opaque).

Here are some examples in which stop-opacity has been used with gradients to allow differing amounts of what is underneath to be visible along a partly transparent gradient.

Various applications of stop-opacity within gradients Superimposition of three copied but rotated linear gradients. Changing tonalities with a radial gradient over an <image> Two radial gradients superimposed Two radial gradients with spreadMethod="repeat" (see below) These examples may be seen at

http://srufaculty.sru.edu/david.dailey/svg/newstuff/gradient10.svg

http://srufaculty.sru.edu/david.dailey/svg/newstuff/gradient9.svg

http://srufaculty.sru.edu/david.dailey/svg/newstuff/gradient7.svg

http://srufaculty.sru.edu/david.dailey/svg/newstuff/gradient11c.svg

spreadMethod

The spreadMethod determines how the gradient will fill a shape if it happens to "run out" before the image is filled. Suppose, as in the example below left, we have a radial gradient which fills an ellipse but the stops of which are so close to the center that its effect is constrained to a small portion of the ellipse. We might choose to replicate that fill pattern replicating the color transitions multiplicative outward as shown in the example on the right. The two examples are the same except that the latter one has an attribute of spreadMethod="repeat" defined. In order for this method to work, the attribute gradientUnits="userSpaceOnUse" must also be assigned.

spreadMethod is undefined spreadMethod="reflect" <radialGradient id="gradient1" cx="30%" cy="60%" r="31" fx="26%" fy="34%">

<stop offset="0" stop-color="grey"/>

<stop id="OF" offset="0.5" stop color="white"/>

<stop offset="1" stop-color="black"/>

</radialGradient> <radialGradient id="gradient1" cx="30%" cy="60%" r="31" fx="26%" fy="34%"

spreadMethod="reflect" gradientUnits="userSpaceOnUse">

<stop offset="0" stop-color="grey"/>

<stop id="OF" offset="0.5" stop-color="white"/>

<stop offset="1" stop-color="black"/>

</radialGradient>

Patterns

Like a gradient, a pattern defines a fill method that may be applied to a given shape. In the case of a pattern though, we may specify some graphics that fill a given rectangle within a pattern, and then allow the pattern to replicate across the region being filled. An example should make it fairly clear.

We define three identical ellipses in close proximity to one another:

<g id="ovals3" fill="#835" stroke-width=".7" stroke="#006">

<ellipse cx="16" cy="8" rx="4" ry="2"/>

<ellipse cx="8" cy="3" rx="4" ry="2"/>

<ellipse cx="5" cy="11" rx="4" ry="2"/>

</g>



Note that these ellipses all fit inside the rectangle (0,0) to (22,15) without any of the ellipses extending past the edges. Now, we will build a pattern-space: a rectangle of size 22 by 15, in which the three ovals are placed. (We use the patternUnits attribute to make sure the coordinates of the pattern conform to the absolute viewing window rather than to fractions of the object being filled.)

<pattern id="Oval" patternUnits="userSpaceOnUse" width="22" height="15" >

<use xlink:href="ovals3"/>

</pattern>

We then define a region (in this case another ellipse) and let the pattern called "Oval" be used to fill it.

<ellipse fill="url(#Oval)" cx="50%" cy="50%" rx="20%" ry="14%"/>

Now we put it all together:

The definition and use of a <pattern> The pattern itself (scale x 6): <g id="ovals3" fill="#835" stroke-width=".7" stroke="#006"> <ellipse cx="16" cy="8" rx="4" ry="2"/> <ellipse cx="8" cy="3" rx="4" ry="2"/> <ellipse cx="5" cy="11" rx="4" ry="2"/> </g> Applied to a region <defs> <pattern id="Oval" patternUnits="userSpaceOnUse" width="22" height="15" > <use xlink:href="ovals3"/> </pattern> </defs> <ellipse fill="#7ac" cx="50%" cy="50%" rx="20%" ry="14%"/> <ellipse fill="url(#Oval)" cx="50%" cy="50%" rx="20%" ry="14%"/> This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/pattern1d.svg

In the above example, note that another ellipse (the blue one) has been placed under the pattern just to help see how the pattern, when not completely filled, is actually transparent.

The objects we place inside a pattern can be numerous and complex, as shown in the following example, where the objects are ellipses filled with reflected gradients.

A pattern space filled with reflected gradients in ovals.

Masks and clip-paths

While using the stop-opacity of a gradient can allow us to appear to clip or crop an underlying image down to a smaller region in the shape of either a rectangle (in the case of linear gradients) or ellipse (in the case of radial gradients), this technique gives us no easy way to clip down to an arbitrary polygon.

Masks and clip-paths are a more realistic approach to cutting a shape out of an underlying picture.

The <mask> and <clipPath> tags provide similar sets of capabilities. We may think of a <clipPath> as a special case of a <mask> which is slightly simpler to use, but not quite so powerful. As such, we will introduce it first.

the <clipPath>

We use a <clipPath> to carve a shape into another graphic element.

That is, a <clipPath> is a container for a set of graphic elements (any combination of 'path', 'text', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'image' and 'use'), which when applied to another graphic element, through its clip-path attribute, results in the restriction of the visible part of that graphic element to the defined clipPath.

In the example below, an <image> tag is defined with a clip-path attribute referring to to a simple <clipPath> containing an ellipse. The rendered portion of the image is limited to those pixels that are within the ellipse. As with gradients and other SVG items containing references to things defined elsewhere in the document, the clipPath is given an id and then the thing to be clipped by it refers to that id within its clip-path attribute.

A simple <clipPath> applied to an <image> <clipPath id="CP"> <ellipse cx="330" cy="80" rx="70" ry="25"/> </clipPath> <image xlink:href='thesoul2.jpg' y="0" x="200" width="35%" height="40%" clip-path="url(#CP)"/>

We may insert more than one graphic element inside a clipPath, and the graphic element may itself be complex (in the sense that a fill-method="evenodd" assignment would render the region with more than one contiguous sub-region). If an element is complex in this way, then it must have its clip-method (rather than its fill-method) set to "evenodd." The example below shows a clipPath containing three shapes inside it: two simple ellipses and a complex path with two distinct subregions. A single rectangle has been placed "behind" the image, so that we may observe that the regions cropped away from the rendered image are indeed invisible.

<clipPath> containing three graphic elements and applied to an <image> <rect x="322" y="0" height="200" width="20" fill="url(#g)"/> <clipPath id="CP"> <ellipse cx="335" cy="25" rx="70" ry="25"/> <ellipse cx="335" cy="80" rx="90" ry="25"/> <path d="M 270 140 A 65 30 0 1 1 270 141 M 308 128 A 25 7 0 1 1 308 129" clip-rule="evenodd"/> </clipPath> <image xlink:href='thesoul2.jpg' y="0" x="200" width="35%" height="40%" clip-path="url(#CP)"/> This example may be see at http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath1.svg

Two <clipPath>s may be intersected. The following demonstrates a picture being clipped first to a star-shaped region "ST". The result, "I", is then reused (being reflected and translated) with a new clip-path applied — one that happens to coincide with a rectangle, "R", that passes beneath it and is reused to form the second clipping path, "C2" . The example is an interesting one since it illustrates some of the complex ways in which SVG objects can be combined with one another.

Repeated clippings of an <image>: first to a star, then to a rectangular subregion of the star. <clipPath id="ST" > <path d = "M 204 247 24 189 135 343 135 152 24 306 z"/> </clipPath> <image xlink:href='p76.jpg' y="140" x="-30" id="I" width="35%" height="40%" clip-path="url(#ST)"/> <rect id="R" x="0%" y="215" height="16%" width="100%" fill="#734" opacity=".4"/> <clipPath id="C2"> <use xlink:href="#R"/> </clipPath> <use xlink:href="#I" clip-path="url(#C2)" transform="translate(416,0) scale(-1,1)"/> A similar example can be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg

Above, we have taken the result "I" of a clipping operation and applied another clip to that. We might accomplish a similar result, following from the above code by applying the "ST" clipPath as a clipping path to another clipPath containing the rectangle "R" as shown in the following code.

<clipPath id="C3" clip-path="url(#ST)">

<use xlink:href="#R"/>

</clipPath> <image xlink:href='../p76.jpg' y="150" x="350" width="35%" height="40%" clip-path="url(#C3)"/>

It should also be noted that the major SVG browsers show some inconsistent behavior regarding clipPaths at the current point in time. While all browsers seem to agree on the handling of the earlier example involving two <image> tags above, the addition of additional complexity in the URL cited as viewed in different browsers is markedly different, with some, but not all of the differences being attributable to the presence of SMIL. Neither Firefox, Safari, nor Chrome seems to appreciate the application of a clip-path directly to a clipPath, though Opera and ASV+IE behave as one might expect on the basis of intuition alone.

Because of the expressive power of SVG, there are often multiple ways to accomplish the same end. As demonstrated below, we might clip an image to a shape using the clipPath, as we have investigated in this section, but we might also use the <mask>, a composite filter (covered in the next chapter), or simply overlay a rectangle with a hole in it (the least elegant of the approaches). All but the last approach actually remove unwanted parts of the picture as is illustrated by the rectangle which appears behind the first three images, but is interrupted by the overlaid region in the fourth.

Clipping to a shape using clipPath, mask, composite, and overlay. <clipPath id="CP"> <ellipse cx="50%" cy="65" rx="15%" ry="60"/> </clipPath> <image xlink:href='p78.jpg' y="0" x="30%" width="35%" height="160" clip-path="url(#CP)"/> <mask id="Ma"> <ellipse cx="55%" cy="190" rx="15%" ry="60" fill="white"/> </mask> <image xlink:href='thesoul2.jpg' y="110" x="30%" width="35%" height="160" mask="url(#Ma)"/> <ellipse style="filter:url(#B)" cx="50%" cy="315" rx="15%" ry="60"/> <filter id="B"> <feImage xlink:href='p74.jpg' y="240" height="160" width="90%"/> <feComposite operator="in" in2="SourceGraphic" /> </filter> <image xlink:href='p76.jpg' y="380" x="300" width="300" height="155"/> <path d="M 300 380 L 600 380 600 535 300 535 M 320 457 A 120 60 0 1 1 320 458" fill="white" fill-rule="evenodd"/>

The <mask>

As can be seen from the above illustration, the mask and the clipPath have much in common. The fundamental difference is that while the clipPath provides an all-or-none clipping function, the mask can provide partial occlusion of the underlying object based on color values provided within the mask.

In a sort of simplest case (see the figure "Clipping to a shape using clipPath, mask, composite, and overlay" above), a mask, just like a clipPath, provides a region that divides the object to be clipped into two parts: the visible (black or opaque) part and the invisible (white or transparent) part. A mask also allows, however, for this division to provide an alpha channel to an object based on color or transparency values of the mask. That is, suppose instead of merely clipping a bitmap or other graphic we wish to make parts of it invisible or partly visible, while we might see a gradual transition from invisible to visible in other parts.

To illustrate the difference between a clipPath and a Mask, consider the following example.

<linearGradient id="gradient1" >

<stop offset="0.0" stop-color="black"/>

<stop offset="1" stop-color="white"/>

</linearGradient>



<mask id="Ma">

<rect x="300" y="300" width="400" height="100"

fill="url(#gradient1)"/>

</mask>



<text x="220" y="365" font-family="impact"

font-size="52" mask="url(#Ma)" fill="black">

Some Masked Text: it outsprawls its mask

</text> This example may be seen at http://srufaculty.sru.edu/david.dailey/svg/newstuff/mask6.svg

A simple linear gradient is defined ranging from black to white as we move from left to right. The gradient is applied to a rectangle starting at (x,y)=(300,300) and ending at (x+w,y+h)=(700,400). The rectangle is not actually visible since it is part of a mask that has id="Ma". The mask is then applied to a text object, the bounds of which extend well beyond the rectangle of the mask, in both horizontal directions. Since black, at the left side of the mask, is equivalent (at least in the case of RGB images) to "opaque," the text is hidden at that side. As we move toward the right (which in this case coincides with white and hence "transparent") the text becomes more visible (since its mask is more transparent).

In the next example, we look a bit closer at the mask, this time using four different transparency levels (also known as alpha values) within the mask, applied through four separate rectangles.

<g id="RS"> <rect x="300" y="100" width="100" height="100" fill="rgb(25%,25%,25%)"/> <rect x="400" y="100" width="100" height="100" fill="rgb(50%,50%,50%)"/> <rect x="500" y="100" width="100" height="100" fill="rgb(75%,75%,75%)"/> <