Вы находитесь на странице: 1из 422

Preface

"With SVG, Web graphics move firmly from mere decoration to true graphical information. Scalable Vector Graphics are the key to providing rich, reusable visual content for the Web. At last, designers have the open graphics format they need to make professional graphics not only work visually on the Web, but perform as searchable, reusable Web content." - Tim Berners-Lee, W3C director and father of the World Wide Web. "Designers are reaching larger audiences with an increasing variety of Web-enabled devices from palmtops to desktops to printers. They need graphics which can be restyled for different purposes. But most of all, they need to be able to handle their graphics the same way as their text and business data, which nowadays are in XML. SVG is specifically designed to let them do that." - Chris Lilley, W3C Graphics Activity Lead.

Introduction
The first thing you need to know is the authors of Learn SVG are experts in the field of computer graphics (CAD/simulation background, Graphics Programming and Web Design). The next thing you need to know is Learn SVG is a tour de force through the world of SVG. Please do not worry, every concept covered is followed up by clear, intriguing examples that serve to instruct and inspire.

Scalable Vector Graphics (SVG) is a revolutionary new graphics format that is unleashing the true potential of graphical information on the Web. SVG is a language for describing twodimensional graphics in XML. SVG supports anti-aliased rendering, zooming, panning, filtereffects, pattern and gradient fills, clipping to paths, text, animations and interactivity and more! SVG is designed to use and to incorporate other W3C specifications and standards such as DOM, CSS, XSLT , SMIL. SVG gives developers, designers, and publishers the ability to create rich lightweight, interactive, extensible documents that are ideally suited for use on the Web. SVG allows for pixel-perfect positioning of SVG graphical objects, which include shapes, text as well as raster graphics such as PNG and JPEG images and supports color accuracy of over 16 million colors. SVG is revolutionary in that it can be fully customized on the client at runtime by means of style sheets and script. Users are able to customize colors, fonts, content and even the layout of graphical objects on the client-side. You can unleash the power of SVG by combining it with scripting. SVG uses the W3C DOM (Document Object Model) for scripting SVG documents. SVG has its own document object model that extends the DOM in a compatible way called the SVG DOM. By being able to use both of these object models, SVG is able to be scripted in a open and powerful way.

Learn SVG

Chapter 1 Introduction

This book has a special focus on scripting. The scripting content is complete for beginners, as it introduces EcmaScript and the DOM first and shows how to access and manipulate the internals of a SVG document via programming. Furthermore, the book focuses on the generation of highly interactive graphics and shows in detail how to deal with event handling. Learn SVG will also cover necessary insights into the essential theory of vector and matrix algebra to explain the guts of the efficient raw transformation matrices that can even be controlled by the client at runtime.

Aims and Objectives of the Book


About Learn SVG / Approach
The objective of this book is to enable readers who are brand spanking new to SVG to reach a semi-advanced level of SVG design and programming through a progression of "real-world" case studies, examples, and scenarios that programmers, Web developers and graphic designers will face. The reader we will move on to more advanced topics of adding style, gradients and filter effects, menu creation, animation, script-based interactivity, publishing, extensibility, and finally implementing cover some cutting-edge SVG Web applications. In the process, the reader will be transcended from a beginner to a semi-expert SVG developer. Throughout this book the presentation of both basic and complex concepts are accompanied by intriguing examples, real-world scenarios and brilliant user interface designs. By the end of this book the reader will be well equipped to ride the SVG wave and integrate SVG into XMLbased technologies that are at our doorstep.

The challenges of gracefully integrating both the graphic design and programming aspects of SVG are not insignificant. But with the help of some terrific editors and reviewers we have produced an excellent foundational text for your reading pleasure. The workbook-like format of this book lends itself ideally to Web designers and developers who want both a solid foundation in the main aspects of SVG and who are willing to get their hands dirty with the fertile soil that SVG has to offer. The full challenge of the book is not for the faint of heart but Learn SVG has made sure to thoroughly cover all the bases using many concrete examples. The purpose of Learn SVG is to inform and inspire readers by covering SVG programming and design techniques through in-depth examples. This book is for people who are relatively new to SVG and who want to start fiddling with the guts of SVG right away. This book will jump right in to real-world examples that can serve as both a workbook and a reference. The large pool of current programmers, Web developers, content publishers and graphic designers will find that this book gives them an invaluable edge in their respective and increasingly overlapping fields.

Learn SVG

Chapter 1 Introduction

Audience of this Book


Due to the fact that SVG is revolutionary, Learn SVG aims to educate a wide-ranging audience including: Web developers and Graphic designers who want to implement powerful Web applications and Services Content-management professionals who need to display visualizations of data GIS-people: the world of geographical information systems Creators and maintainers of (industrial) technical drawings such as Engineers and Architects The XML-community The Flash-community

This book is aimed to inspire many types of content-creators to love SVG. This book provides a solid foundation for getting started with SVG. We will cover the basics as clearly and concisely as possible. On the other hand, there is a lot to this new graphics format/language and so we have included "SVG Concepts", challenges, and advanced exercises at the end of each chapter that introduce more complex topics for the avid Web developer. If you are here for the full challenge then please fasten your safety belts and hang on tightly lest you be thrown to the wolves.

Conventions and Terminology


We use a number of different styles of text and layout in the book to help differentiate between the different kinds of information. Here are examples of the styles we use and an explanation of what they mean: Indentation Indentation improves readability. Following convention is used for: children elements elements spanning several lines Indentation of children elements is 2 space characters. Elements spanning several lines are broken so, that attributes are in line. Here is an example of both types of indentations:
<svg width="200" height="100"> <circle cx="10" cy="86" r="15"

Learn SVG

Chapter 1 Introduction

fill="red" stroke="black" /> <!-- code for the car goes here --> </svg>

Emphasizing of important code and terms When you first come across an important term it will be in bold type, then in normal type thereafter. We'll use a Courier to emphasize words and phrases that appear on the screen, and code. Code that is new, important or relevant to the current discussion will be presented like this:
<svg> <ellipse cx="50" cy="50" rx="10" ry="20" /> </svg>

Code blocks
<svg width="200" height="100"> <circle cx="10" cy="86" r="15" fill="red" stroke="black" /> <!-- code for the car goes here --> </svg>

Menu Commands Menu commands are written in the form: Menu > Sub-menu > Sub-menu Scripting The script language used throughout this book is EcmaScript, which the W3C accepts as an open scripting standard. The corresponding element is always :
<script type="text/ecmascript"> <![CDATA[ // script content goes here .. ]]> </script>

SVG Elements It is beneficial, to have a common skeleton for introducing a new SVG element or a family of new elements throughout the book. The format that will be used will be:

Learn SVG Introductory text Element syntax

Chapter 1 Introduction

Explaining element specific attributes. text or table Element example(s): picture and code

The Element Syntax always looks similar to this example


Syntax:
<marker id="name" refX="coordinate" refY="coordinate" markerWidth="length" markerHeight="length" markerUnits="strokeWidth | userSpaceOnUse" viewBox="min-x min-y width height" orient="auto | angle" style-attribute="style-attribute"> <!-- marker content here --> </marker>

What You Need To Use This Book


Basic understanding of HTML XML One of the following SVG Viewer ( See Appendix C)

Learn SVG

Chapter 1 Introduction

Chapter 1
"Make everything as simple as possible, but not simpler." - Albert Einstein (1879-1955)

Chapter Objectives
History of SVG SVG is XML Raster vs. Vector Graphics SVG Concepts Viewing SVG Creating SVG

Introduction
Learn SVG explores the world of Scalable Vector Graphics. SVG is a graphics format that has been developed as an open source industry standard graphics format and is maintained by the W3C. SVG describes graphics using XML grammar. SVG interrogates and conforms with Web standards such as DOM, XML Namespace, Xpath, Xlink and XPointer and many others that will addressed in this book. The key to SVG is in fact that each of these robust standards seamlessly works together with SVG. This allows SVG to be stylized, dynamic, animated, interactive, extensible and an all-around extraordinary graphics format. In SVG we find the culmination of the next generation of the Web. This is why SVG makes for a truly astounding and robust presentation layer for the Web. We have a lot to cover so lets start with some inspiration. You will need a SVG Viewer to view figure 1.1. If you do not have a SVG Viewer Please see Appendix C to help you pick one out.

Figure 1-1:

Inspirational SVG image

Learn SVG

Chapter 1 Introduction

How SVG Emerged


There has been a lot of excitement and generated by this graphics format as it has become a vital part of Web development. SVG is a creation of the World Wide Web Consortium (W3C), which is an openstandards international industry consortium that has been formed to develop open-source standards for the Web. SVG emerged through the work of a The World Wide Web Consortium working group that was formed back in 1998. The W3C SVG Working Group continues to improve the capabilities of SVG. W3C working groups are comprised of representatives from a variety of industries across the world. There are over twenty members of the SVG Working Group including some of the top industry leaders such as: Adobe Systems, Sun Microsystems, IBM, Corel, Macromedia, HewlettPackard, Microsoft, and AOL/Netscape. With the development of XML the opportunity arose to create an XML-based language to describe graphics. The W3C gave the SVG working group the goal of developing a XML graphic format that could produce top quality graphics. SVG does just that and a great deal more as we will be discovering throughout this book. In 1998, the W3C was presented with two proposals for new graphics formats. Both Precision Graphics Markup Language (PGML) and Vector Markup Language (VML) are described using an XML grammar. Adobe proposed PGML based on its experience with Postscript and PDF, PGML is in fact generated from PDF files. Support for Microsofts submission, VML, has been realized in Internet Explorer, but development stopped in the autumn of 1998. After much consideration the W3C decided to combine the best aspects of both of the PGML and VML languages into a new language called SVG. On August 2nd and again on November 2nd of 2000 the W3C upgraded SVG to Candidate Recommendation and urged developers to begin implementing SVG. One and half years after the first SVG Working Draft was published, Chris Lilley, the Activity leader and chair of the SVG Working Group, announced the release of the SVG 1.0 specification as a W3C Recommendation. The SVG 1.0 specification was finalized by the W3C on September 4, 2001. This means that SVG has been thoroughly tested and is an industry standard that is ready for full-scale implementation. The SVG Working Group is continuing to expand the capabilities of SVG in their work on SVG 1.1 ,SVG 2.0 specifications and the SVG Mobile , Tiny profiles. The SVG Working Group is continuing to expand the capabilities of SVG. In Jan of 2003 SVG 1.1 and SVG Mobile specifications were released. Work continues on the long anticipated SVG 1.2, SVG 2.0 and SVG Print specifications that will probably support highly desired features such as text-wrapping.

Learn SVG

Chapter 1 Introduction

This is the current SVG Roadmap.


Document SVG 1.0 SVG 1.1 SVG Mobile Profiles SVG 1.2 SVG Print Requirements SVG Print WD1 11 Nov 2002 [Jan 2003] [Mar 2003] [Feb 2003] WD2 [Jan 2003] LC [May 2003] Ends [July 2003] CR [August 2003] PR 11 Nov 2002 11 Nov 2002 [Dec 2003] REC 5 Sep 2001 14 Jan 2003 14 Jan 2003 [Jan 2004] -

Authoring Tool Guidelines Accessibility [Mar Techniques 2003]

Legend: WDn = n'th working draft; LC = last call for comments (i.e., last WD); Ends = deadline for LC comments; CR = Candidate Recommendation; PR = Proposed Recommendation; REC = W3C Recommendation. [Feb '02] = expected date.

SVG is XML
SVG is based on eXtensible Markup Language (XML) grammar, the standard markup for Web documents in the 21st century. Other XML-based applications that are in use or under development include XHTML, MathML, SMIL, X3D, XFORMS, and many others. Rapid adoption and application of these technologies has already occurred and offer a state-of-theart foundation for documents. As you can see, SVG is built with the future of the Web in mind. SVG being an application of XML benefits from all the advantages XML brings. SVG is textbased and open source web standard. If you are familiar with XML you will see that there really is nothing new about the structure of the SVG language. As you can see in figure 1-1, SVG is composed of content markedup within tags which are made up of elements and attributes. The following diagram examines components of the SVG language using XML grammar and syntax:

Learn SVG

Chapter 1 Introduction

Figure 1-2: SVG syntax and basic grammar

SVG is Efficient
SVG is a text based graphic format. This means that SVG files are just plain old text files. SVG graphics files are very small compared to other graphic file formats. The image in figure 1.1 ends up having a file size of around 2.3 KB. (Note that there is a reference to one external jpeg image that has been positioned over the letter "G" that is really making the file size huge.) If we use gzip to compress the SVG file then it ends up being less than 1 KB. This is tiny! You will find this to be especially astonishing when you discover that this image can be infinitely scaled without any loss in image quality, except for any referenced raster content. Also, because SVG conforms to the Document Object Model (DOM) and style sheets, all of the elements and attributes of figure 1.1 can be efficiently accessed and manipulated. If you wanted any of the objects in the graphic to move, you can just add some animation elements or script at almost no cost to size of the file.

SVG is Powerful
For the past ten or more years programmers have been thinking about how best to introduce two-dimensional vector graphics to end users. The benefits of using vector graphics include greater interaction and analysis with the user interface including such functionality as panning, zooming and best of all programmatic animation. One excellent aspect of SVG is that once downloaded to the client it can be reused on a page at different sizes or with different features and even different data. A host of technologies can work together to make SVG the ultimate graphics format and XML application. For example, ECMAScript, CSS, XSLT and XSL-FO can be applied to SVG on the client to provide truly dynamic, user-friendly and interactive Web documents. Also, since SVG conforms to the XML specification it is also extensible which means that SVG can be viewed inline with other XML-based languages / applications such as XHTML, SMIL, XFORMS and MathML. SVG has several key advantages over other graphics formats used on the Web. These include:

Learn SVG

Chapter 1 Introduction

10

Scalable SVG images do not degrade upon panning and zooming, which is ideal for many things such as portable devices, mapping, charting, printing at any size and technical diagrams. Plain text Developers and designers can edit SVG code using a wide variety of tools. Smaller file sizes Compression techniques and the effectiveness of SVG's vocabulary can make SVG files very small and ideal for use on the Web. Searchable - SVG content is text and therefore can be searched and indexed. Infinite color and font options - 16 million colors and support for embedded fonts which means what is seen on the screen will look exactly the same when printed Native image effects drop-shadows, blurs, and lighting effects can be applied when SVG is being rendered on the client side. The dynamic filter effects of SVG are a true breakthrough for graphics on the Web. Animation SVG includes built-in elements for declarative animation effects and can also be animated through the SVG DOM with script. Interaction Script can control animation and allow for advanced user-friendly interactivity. XML - Compatibility with XML, HTML4, XHTML as well as conformance to CSS, XSL-FO, and the DOM means that SVG is extensible, can be styled , scriptable, extensible, interactive and integrates easily with other XML languages.

SVG is Scalable (Vector Graphics)


Until recently Web developers only had the option of using these bitmap graphic formats to render images in browsers. The main bitmap graphic formats that are used on the Web today are: Graphics Interchange Format (GIF) Joint Photographic Experts Group (JPEG) Portable Network Graphics (PNG)

Bitmaps graphics belong to a class of computer graphics called raster graphics. Raster graphics are displayed by a method of filling in a matrix of pixels, which requires storing the information for every pixel of the graphic. Vector graphics such as SVG and SWF formats are different beasts altogether belonging to another class of graphics that are rendered using short line segments called vectors. Also, vector graphics contain geometric objects such as lines and curves.

Learn SVG

Chapter 1 Introduction

11

Although bitmap images do work very well in many situations, vector graphics open up a whole new world of possibilities in Web graphics. For example compare the following two screenshots of the same SVG image. This is the original view of this vector graphic.

Figure 1-3: Original size

Figure 1-4: Size after zooming in

Notice that we have not lost any quality. This is because the vector-based viewers are able to recalculate how the graphic should look based on the textual description of the circle shape that is found inside of the SVG graphic. This is a key advantage of SVG and raster graphic formats. Because vector graphics are defined programmatically they provide a more efficient means for rendering print and animation, as well as adding interaction (including panning and zooming) and analytical capability. One of the limitations of bitmap images is how they describe graphics. Bitmaps do not describe graphics as shape elements or objects but instead have to describe each and every pixel in the image. Bitmaps can make use of efficient compression techniques and can be streamed because its data is stored serially, however as you will see in these screenshots the scalability of vector graphics is a tremendous advantage over raster images.

Figure 1-5:

Original image

Figure 1-6:

Vector image at 300%

Figure 1-7:

Raster image at 300%

Learn SVG

Chapter 1 Introduction

12

The raster image becomes very pixilated when it is scaled while the vector image loses absolutely no image quality! SVG is a Vector graphic format. Now, you know why SVG is called Scalable Vector Graphics.

The Building Blocks of SVG


Scalable Vector Graphics (SVG) is a completely open standard XML language for describing two-dimensional graphics using a combination of three types of graphical objects: vector graphic shapes, images and text. Lets take a minute to explain in detail what that last sentence actually means.

SVG is Composed of Graphical Objects


SVG is made up of three types of graphical objects: shape, image and text objects.

Figure 1-8: Graphic Objects in SVG

Shapes in SVG The following image can be displayed using HTML via the <image> element, or it can be displayed using SVG via the <circle> element.

Figure 1-9: HTML document: <html> <head> <title>Pink Circle</title> </head> <body>

Circle in SVG

Learn SVG

Chapter 1 Introduction

13

<img src=circle01.gif /> </body> </html> SVG document:

<?xml version=1.0 ?>


<svg width="100" height="100"> <title>Pink Circle</title> <circle cx="50" cy="50" r="40" fill="pink" stroke="black"/> </svg>

So if both documents can produce the same looking circle then what is all this excitement surrounding the SVG graphic format? What are the kinds of benefits and drawbacks of using SVG rather than HTML? Those are great question that this book will reveal. SVG shapes objects include the following elements: <path>, <line>, <rect>, <circle>, <ellipse>, <polyline> and <polygon>. The <path> element is able to describe more complex shapes using Cubic and Bezier curves. We will cover Shapes in chapter 2 and the more complex <path> element in several chapters though out the book. Shapes are not always the most efficient method of rendering image content. The W3C SVG Working Group recognized this and provides two more graphic objects to help: Images and Text. How to inline and embed SVG images will be exported in many chapters. Images in SVG In SVG, raster images are actually graphical objects. This gives the developer or end-user the ability to, for example, apply client-side animation and filter effects on specific raster images as we saw in the figure 1.1. Notice that the raster image in the top right corner is semi-opaque! We will discover how this was accomplished in the next chapter. SVG Recommendation states that an SVG Viewer has to support two raster formats. The two formats are JPEG and PNG. The SVG Viewer can support more raster formats. Text in SVG After shapes and images, the third graphical object in SVG is text. As a graphical object, text can be programmatically controlled and manipulated through script just like shapes and images! SVG text is composed of font characters that technically are in turn comprised of glyphs. We will describe the difference between fonts and glyphs and many other interesting features of using text in SVG in greater detail in Chapter 5.

SVG in Practice

Learn SVG

Chapter 1 Introduction

14

SVG is already taking off as demonstrated in the computer industries widespread support of SVG in major product lines, third-party tools and Web applications. Please see Appendix C for a listing of Products, third-party tools and Web applications.

Viewing SVG
Before we start working with SVG lets make sure were all on the same page. A prerequisite for this book is that you have the resources in place to at least be able to view SVG. Please see Appendix C to help you quickly pick out a SVG Viewer.

Creating SVG
Hand-coding SVG So now that we know what SVG is and what SVG is made of lets start creating some SVG of our own. The quickest and easiest way to ease into understanding SVG is by hand-coding your first few SVG graphics. Hand-coding SVG graphics is actually not too difficult so take out our magic keyboard, open your favorite text editor and follow along as we journey into the land of Scalable Vector Graphics. This next example will be very short and simple black rectangle. One of SVG's greatest assets lies in its ease of use. SVG is quite simple and you can create SVG without the use of a graphical authoring environment. Our first example of SVG shows the basic structure of a complete SVG graphic/document. Line 1: Line 2: Line 3: Line 4:
<?xml version=1.0 ?> <svg> <rect x="100" y="50" width="100" height="100" /> </svg>

This code creates this shape:

figure 1-10: rectangle with default fill

Line 1: The XML Declaration and the XML version of this document. Line 2: Opens the SVG document Line 3: Creates an SVG shape using the <rect> element, specifies: a: top left corner of rectangle positioned at x and y attribute values b: specifies the width and height of the rectangle by setting the width and height attribute values.

Learn SVG Line 4: Closes the SVG document

Chapter 1 Introduction

15

Notice that the default fill color is black. We will cover styling in detail in Chapter 5.

Summary
Congratulations! You have just created an SVG-powered Web page. If you liked this exercise then just hold tight because we will continue to expand your SVG knowledge. If you found this exercise to be somewhat boring we will quickly be moving on to bigger and better things! Beauty is in the eye of the beholder. Up to this point we have quickly covered the main questions involved in creating, viewing and editing SVG without going into undue depth. In the next section we will continue to partake of the SVG feast by analyzing shapes, text, and images. As mentioned earlier SVG is ideally suited for use on the Web, so in this book we will be dealing with all aspects of using SVG on the Web. Also found in this book are a number of great SVG images with the accompanying source code that should be of great value to both designers and developers. In Chapter 1 we learned what SVG is and began to familiarize ourselves with the tools of SVG. We also quickly covered how to create and view SVG output. Hopefully you are having fun. Do always remember that it is a state of mind. And as Yoda says, Your focus determines your reality.

Chapter 2 Basic Shapes


"What you see is all you get." - Brian Kernighan4 "In theory, there is no difference between theory and practice. But, in practice, there is." - Jan L.A. van de Snepscheut "Form must follow function." - Le Corbusier

Chapter Objectives
The SVG Header The svg, desc and title Elements Presentation Attributes: Stroke and Fill Basic Shapes line, circle, rect, ellipse, polyline, polygon Basic Shape Reference The image Element

Overview
If you will recall from Chapter 1, SVG offers three types of graphical objects: shapes, images, text. In this chapter we will be exploring basic SVG document structure, basic presentation attributes and basic shapes, images and a little about text. We will cover all aspects of text processing in depth in Chapter 5. Mastery of these concepts will provide us with the building blocks for most everything that we will do with SVG.

The SVG Header


The code below demonstrates the structure of a complete SVG document. The document is composed of the XML declaration, the DOCTYPE declaration, and the SVG Document Fragment. This is the complete SVG header:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="350" height="300" xmlns="http://www.w3.org/2000/svg"> <!-- content goes here --> </svg>

The first line of the SVG header is the standard XML processing instruction that efficiently states this document conforms to the XML 1.0 specification, uses UTF-8 character encoding and depends on a Document Type Definition (DTD) external to the document to parse correctly. Where is this DTD located? The second line holds the secret to this information. In the second line, the DOCTYPE states where the DTD is located and the name of the document element it will be applied to. In this case, the DTD is applied to a document element named svg. The DTD provides the grammar and rules for the document.

Learn SVG

Chapter 2 Basic Shapes

Lets take a look at a sample that uses the complete SVG header and adds some SVG elements:

Figure 2-1.

Line and circle with style

<?xml version=1.0 encoding=UTF-8 standalone=no?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="350" height="300"> <title>SVG - Introduction</title> <desc> This graphic demonstrates many exciting features of SVG.</desc> <circle cx="50" cy="70" r="30" fill="grey" fill-opacity="0.4" stroke="darkslategrey" stroke-width="2"> <desc>Basic circle</desc> </circle> <line x1="72" y1="50" x2="110" y2="10" stroke="darkslategrey" stroke-width="2"/> </svg>

Now, lets take a closer look at the svg element and new SVG elements we added to the code.

The basics of the <svg> element


After the doctype declaration is the svg element. In our example, the svg element contains all other elements. This makes the svg element the document element of the document.
<?xml version=1.0 encoding=UTF-8 standalone=no?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="350" height="300"> <!-- content goes here --> </svg>

You may have noticed the attributes on the svg element. What do they do? The width and height attributes describe the width and height of the SVG graphic. The height and width attributes can also be used on some graphical objects such as rectangle elements.

Learn SVG

Chapter 2 Basic Shapes

Figure 2-2.

Rect with width and height attributes

<?xml version=1.0 encoding=UTF-8 standalone=no?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="350" height="300"> <rect x="40" y="20" width="140" height="70" stroke="black" fill="lightgrey" /> </svg>

There are many more properties that can be defined on the svg element. We will explore these properties in the next chapter and throughout the book. Now, lets look at the new SVG elements we added to the document. You will see 'title', 'desc', circle, line element. We will look at title and desc in this section and will cover circle and line later on in the chapter.

The basics of title and desc


Looking again at the code example you will see in bold title and desc elements:
<?xml version=1.0 encoding=UTF-8 standalone=no?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="350" height="300"> <title>SVG - Introduction</title> <desc> This graphic demonstrates many exciting features of SVG.</desc> <circle cx="50" cy="70" r="30" fill="grey" fill-opacity="0.4" stroke="darkslategrey" stroke-width="2"> <desc>Basic circle</desc> </circle> <line x1="72" y1="50" x2="110" y2="10" stroke="darkslategrey" stroke-width="2"/> </svg>

In SVG, all elements can have the title and desc elements as children. This allows every element can have a title and description. The content of title and desc will not be displayed to the screen.

Learn SVG

Chapter 2 Basic Shapes

An interesting note in the SVG recommendation leaves the implementation of these elements up to the implementers of the SVG processor. This means that some viewers may implement functionality for the title and desc attributes, some will not. For example, A SVG viewer may use the desc element for a tooltip and the title element that is the child of a svg documents element for the title of the web page. Note that title element in SVG behaves differently then title attribute of HTML. But do not worry, using the SVGs Document Object model and scripting we will show you how to create your own tooltips.

Note to reader
For the rest of the book we will leave out the complete SVG header to help us focus on the SVG elements and attributes and improve the readability of the code. That being said, we highly recommended that you always use the complete header in your own documents. So for readability each of the SVG code samples will take this form:
<?xml version="1.0"?> <svg width="350" height="300"> <!-- content goes here --> </svg>

Units of Measurement: Throughout the rest of the book no CSS units (pt, mm, px, etc.) will be used. This is due to the fact that the SVG working group is considering better alternatives to CSS units in future SVG versions. The SVG working group recommends avoiding these units today and so we will follow that recommendation. Instead we will not specify any unit type so that our SVG graphics will default to what is called user units. We will always refer to our coordinates as user units rather than any specific CSS unit of measurement.

Style Properties
Graphical objects can be much more useful when they have been stylised. In this section we will show how to apply a few of the most common style properties to shapes using presentation attributes. You can find a complete listing of all of SVGs presentation attributes in Appendix B. Styling with CSS vs. Presentation Attributes Style can be applied to SVG in a number of ways. Throughout this book we will be using presentation attributes rather than CSS to stylize our images. Presentation attribute have the syntax:
style = name of style

CSS style has this syntax:


style = name of style : value

Presentation attributes such as fill="red" are used exclusively in code examples because they are easier to read and understand than CSS styles such as style="fill:red". Styling with CSS will be covered in Appendix B.

Learn SVG

Chapter 2 Basic Shapes

Colors We can not talk about 'fill' and stroke property until we address how to specify a color. Color in SVG was adopted from the CSS specification which means that everything you learned about CSS color is the same for SVG! There are two main ways to define a color and they are through color keyword names or through the RGB color model. If you want to specify that a graphical object have its interior color be lightgray this is all you need to do.

Figure 2-3.

Rect with fill value

<svg width="350" height="300"> <rect x="50" y="30" width="200" height="100" fill=lightgray /> </svg>

Alternatively, colors can be specified using three- or six-digit hexadecimal RBG notation #rgb, rgb(000,000,000) or rgb(0%,0%,0%). For example each of these notations specifies a color value that is equal to the color white:
#FFF = #FFFFFF = rgb(255,255,255) = rgb(100%,100%,100%) In SVG syntax, the color white would look like this: <rect <rect <rect <rect x="50" x="50" x="50" x="50" y="30" y="30" y="30" y="30" width="200" width="200" width="200" width="200" height="100" height="100" height="100" height="100" fill=#fff /> fill=#ffffff /> fill=rgb(255,255,255) /> fill=rgb(100%,100%,100%) />

We have included a list of SVGs color keyword names and hexadecimal RBG notation in a color chart in Appendix A. The fill and stroke properties Lets take a look at how to use the stroke and fill presentation attributes. All of SVGs graphical objects have an outline and an interior space. The outline is called the stroke and the interior is called the fill. We can set an objects stroke and fill property values through presentation attributes. fill Properties When you use the fill property it will fill the interior of an graphic object with a color, gradient or pattern. We will cover gradient and pattern fully in future chapters. The fill attribute specifies the color of the graphic objects filled region. The fill property is used to fill graphical elements interior with the specified paint value. 5

Learn SVG

Chapter 2 Basic Shapes

Fill Property Reference Table The fill properties include: fill fill-opacity fill-rule Each of these properties is defined in greater detail here. Fill Properties: Property fill fill-opacity fill-rule Description A color value that defines the color of a shape or text interior. A number between 1.0 and 0 with 1.0 being opaque and 0 being transparent that defines the opacity of a shape or text interior. A value of nonzero or evenodd that is used to determine interior for intersecting lines.

fill-opacity This is syntax definition for the fill property. 'fill' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: <paint> black Shapes and textual content yes N/A visual yes

Each of these fill color attributes are demonstrated in figure 2-3.

Figure 2-4.

Fill property colors

<svg width="350" height="300"> <rect x="10" y="10" width="40" height="40" fill="cornflowerblue"/> <rect x="30" y="25" width="40" height="40" fill="#64DDDD"/>

Learn SVG

Chapter 2 Basic Shapes

<rect x="50" y="40" width="40" height="40" fill="rgb(100, 100, 237)"/> <rect x="70" y="55" width="40" height="40" fill="rgb(50%,50%,50%)"/> </svg>

fill-opacity Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: <opacity-value> | inherit 1 shapes and text content elements yes N/A visual yes

The fill-opacity property sets the amount of opacity the interior of a graphical object will have. The default opacity value is 1 (opaque) with 0 (transparent) being the lowest possible value for this property. In figure 2-4 we have set varying opacity values.

Figure 2-5.

Fill-opacity property

<svg width="200" height="200"> <rect x="5" y="5" width="50" height="50" fill="cornflowerblue" fill-opacity=0.7 /> <rect x="25" y="25" width="50" height="50" fill="#64DDDD" fill-opacity=0.5 /> <rect x="45" y="45" width="50" height="50" fill="rgb(100, 100, 237)" fill-opacity=0.3 /> <rect x="65" y="65" width="50" height="50" fill="rgb(50%,50%,50%)" fill-opacity=0.1 /> </svg>

fill-rule Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: nonzero | evenodd | inherit Nonzero shapes and text content elements Yes N/A Visual Yes 7

Learn SVG

Chapter 2 Basic Shapes

The fill-rule property determines the internal and external portions of a shape. Often this is straight-forward but this becomes more tricky with complex shapes. This next example comes straight from the SVG 1.2 Specification.

Figure 2-6.

Fill-rule property nonzero

<?xml version="1.0" standalone="no"?> <svg width="12cm" height="4cm" viewBox="0 0 1200 400" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <desc>Example fillrule-nonzero - demonstrates fill-rule:nonzero</desc> <rect x="1" y="1" width="1198" height="398" fill="none" stroke="blue" /> <defs> <path id="Triangle" d="M 16,0 L -8,9 v-18 z" fill="black" stroke="none" /> </defs> <g fill-rule="nonzero" fill="red" stroke="black" stroke-width="3" > <path d="M 250,75 L 323,301 131,161 369,161 177,301 z" /> <use xlink:href="#Triangle" transform="translate(306.21 249) rotate(72)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(175.16,193.2) rotate(216)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(314.26,161) rotate(0)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(221.16,268.8) rotate(144)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(233.21,126.98) rotate(288)" overflow="visible" /> <path d="M 600,81 A 107,107 0 0,1 600,295 A 107,107 0 0,1 600,81 z M 600,139 A 49,49 0 0,1 600,237 A 49,49 0 0,1 600,139 z" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(0) translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(120) translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(240) translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(60) translate(49,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(180) translate(49,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(600,188) rotate(300) translate(49,0) rotate(90)" overflow="visible" /> <path d="M 950,81 A 107,107 0 0,1 950,295 A 107,107 0 0,1 950,81 z M 950,139 A 49,49 0 0,0 950,237 A 49,49 0 0,0 950,139 z" /> <use xlink:href="#Triangle" transform="translate(950,188) rotate(0) translate(107,0) rotate(90)" overflow="visible" />

Learn SVG

Chapter 2 Basic Shapes


rotate(120) rotate(240) rotate(60) rotate(180) rotate(300)

<use xlink:href="#Triangle" transform="translate(950,188) translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) translate(49,0) rotate(-90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) translate(49,0) rotate(-90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) translate(49,0) rotate(-90)" overflow="visible" /> </g> </svg>

Stroke Properties When you use the stroke property it will stroke the outline of an graphic object with a color, gradient or pattern. We will cover gradient and pattern fully in future chapters. There are several stroke-related properties including: stroke stroke-width stroke-opacity stroke-linecap stroke-linejoin stroke-dasharray stroke-dashoffset stroke-miterlimit Each of these properties is defined in greater detail here. Stroke Properties: Property stroke Description A color value that defines the color of a shapes or text stroke. A number or percentage value that defines the width of a shapes stroke-width or text stroke. A number between 1.0 and 0 with 1.0 being opaque and 0 being stroke-opacity transparent that defines the opacity of a shapes or text stroke. A set of user coordinate numbers that define the repeating dash stroke-dasharray and gap length of a stroke. A value of butt (default), round or square that specifies the stroke-linecap stroke shape at the end of line segments. A value of miter (default), round or bevel that indicates the stroke stroke-linejoin shapes of the corners of basic shapes and paths. A number >= less than 1 that defines the limit on the ratio of the stroke-miterlimit miter length to the stroke-linewidth.

stroke and stroke-width Here are the syntax definitions for each of the stroke and stroke-width properties.

Learn SVG 'stroke' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: 'stroke-width' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

Chapter 2 Basic Shapes

10

<paint> (See Specifying paint) none shapes and text content elements yes N/A visual yes

<length> | inherit 1 shapes and text content elements yes Yes visual yes

In this example we have used presentation attributes to apply stroke color and stroke-width properties to the lines.

Figure 2-7.
<svg>

Stroke property

<!-- Horizontal Lines --> <line x1="0" y1="20" x2="100" y2="20" stroke="darkslategray"/> <line x1="25" y1="30" x2="125" y2="30" stroke="darkslategray" stroke-width="4"/> <line x1="50" y1="40" x2="150" y2="40" stroke="darkslategray" stroke-width="6"/> <line x1="75" y1="50" x2="175" y2="50" stroke="green" stroke-width="8"/> <line x1="100" y1="60" x2="200" y2="60" stroke="blue" stroke-width="10"/> <!-- Diagonal Lines --> <line x1="0" y1="20" x2="100" y2="60" stroke="black" stroke-width="1"/> <line x1="100" y1="20" x2="200" y2="60" stroke="black" stroke-width="1"/> </svg>

As you can see, the line element has a different stroke color and different stroke-width. Each of these properties is used to affect the outline appearance on the graphic object to which it is applied.

10

Learn SVG stroke-opacity Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

Chapter 2 Basic Shapes

11

<opacity-value> | inherit 1 shapes and text content elements yes N/A visual yes

The stroke is always centered on the outline of the graphic object. This means that half of the stroke is on the inside of the graphic object and the other half of the outline is on the outside of the graphic object. Lets look at the next example which makes use of the stroke-opacity property:

Figure 2-8.

Stroke-width property illustrated using stroke-opacity

<svg width="200" height="200"> <rect x="20" y="20" width="60" height="60" fill="#CCCCCC" stroke="blue" stroke-width="15" stroke-opacity="0.2"/> </svg>

As you can see in the example above, by using the stroke-width and stroke-opacity properties we can easily create some interesting effects. We have made what seem to be three different rectangles. When adding style to graphic object some interesting scenarios can develop. For example, what would happen if the stroke-width property value were greater than the interior space of the graphic object? Try it. As you might have guessed, the stroke can consume the interior space and completely paint over the shapes fill.

stroke-dasharray 'stroke-dasharray' Value: Initial: Applies to: none | <dasharray> | inherit none shapes and text content elements 11

Learn SVG Inherited: Percentages: Media: Animatable:

Chapter 2 Basic Shapes yes yes (see below) visual yes (non-additive)

12

Using just the stroke-dasharray we can create the following types of dot-dash patterns along the stroke of our shapes.

Figure 2-9.

Stroke-dasharray property (dot, dash, dashdot, etc.)

<svg width="350" height="300"> <line x1="40" y1="20" x2="200" y2="20" stroke-dasharray="1 10" fill="none" stroke="darkslategray" stroke-width="2" stroke-linecap="round" <line x1="40" y1="40" x2="200" y2="40" stroke-dasharray="10 10 10 10" fill="none" stroke="darkslategray" stroke-width="2" stroke-linecap="round" <line x1="40" y1="60" x2="200" y2="60" stroke-dasharray="10 10 1 10" fill="none" stroke="darkslategray" stroke-width="2" stroke-linecap="round" <line x1="40" y1="80" x2="200" y2="80" stroke-dasharray="1 10 10 10 1 10" fill="none" stroke="darkslategray" stroke-width="2" stroke-linecap="round" <line x1="40" y1="100" x2="200" y2="100" stroke-dasharray="1 10 10 10 10 10" fill="none" stroke="darkslategray" stroke-width="2" stroke-linecap="round" </svg>

/>

/>

/>

/>

/>

Note: When using lines in the Adobe SVG Viewer you will notice that you should always set the fill=none to prevent a thin line from being displayed along the length of the line.

stroke-dashoffset Value: Initial: Applies to: Inherited: Percentages: Media: <length> | inherit 0 shapes and text content elements yes see prose visual 12

Learn SVG Animatable: yes

Chapter 2 Basic Shapes

13

The stroke-dashoffset can be used to effectively move the start position of the strokedasharray. The stroke-dasharray property also allows the stroke to be segmented as shown in this example.

Figure 2-10.

Stroke-dasharray and stroke-dashoffset design

<svg width="300" height="300"> <rect x="10" y="10" width="70" height="70" fill="pink" stroke="blue" stroke-width="5" stroke-dasharray="35 35" stroke-dashoffset="-17.5"/> <line x1="90" y1="45" x2="215" y2="45" stroke-width="10" stroke="black" stroke-dasharray="2 13"/> <line x1="120" y1="80" x2="215" y2="45" stroke-width="2" stroke="black" stroke-dasharray="1 10 5 10"/> <line x1="120" y1="10" x2="215" y2="45" stroke-width="2" stroke="black" stroke-dasharray="1 10 5 10"/> </svg>

In the example above the stroke-dashes on the rectangle have been offset using the strokedashoffset property so that they are centered along the length of rectangles sides. Using the stroke-dasharray property on two line elements we can even create a grid like this.

Figure 2-11.

Grid using stroke-dasharray

<svg width="100" height="100"> <line x1="0" y1="50" x2="100" y2="50" stroke-width="100" stroke="black" stroke-dasharray="2 18" /> <line x1="50" y1="0" x2="50" y2="100" stroke-width="100" stroke="black" stroke-dasharray="2 18" /> </svg>

13

Learn SVG

Chapter 2 Basic Shapes

14

The stroke-dashoffset property is illustrated more clearly in this next example.

Figure 2-12.

Stroke-dashoffset property

<svg width="350" height="300"> <rect x="40" y="10" width="30" height="20" stroke="black" stroke-width="0.75" stroke-dasharray="10 10 10 10" stroke-dashoffset="0" fill="silver" fill-opacity="0.4" /> <rect x="90" y="10" width="30" height="20" stroke="black" stroke-width="0.75" stroke-dasharray="10 10 10 10" stroke-dashoffset="-10" fill="silver" fill-opacity="0.4" /> <rect x="140" y="10" width="40" height="20" stroke="black" stroke-width="0.75" stroke-dasharray="10 10 10 10" stroke-dashoffset="5" fill="silver" fill-opacity="0.4" /> <rect x="40" y="40" width="140" height="20" stroke="black" stroke-width="0.75" stroke-dasharray="6 3 2 3" stroke-dashoffset="20" fill="silver" fill-opacity="0.4"/> <rect x="40" y="70" width="140" height="20" rx="5" ry="5" stroke="darkslategray" stroke-width="2" stroke-dasharray="10 5 10 5" stroke-dashoffset="500" fill="silver" fill-opacity="0.4" /> <rect x="40" y="100" width="140" height="20" rx="40" ry="20" stroke="darkslategray" stroke-width="2" stroke-dasharray="10 5 10 5" stroke-dashoffset="7" fill="silver" fill-opacity="0.4" /> </svg>

Both the stroke-dasharray and the stroke-dashoffset properties are quite useful for designs and animations, as we will see later in this book. stroke-linecap Value: Initial: Applies to: Inherited: butt | round | square | inherit butt shapes and text content elements yes 14

Learn SVG Percentages: Media: Animatable:

Chapter 2 Basic Shapes N/A visual yes

15

The default stroke-linecap property value is butt specifies the shape to be used at the end of open path. Setting the stroke-linecap value to round creates a small semi-circle at the end of the line. The last possible value for the stroke-linecap property is square and this extends the stroke out from the end of the line a distance equal to the stroke-width property value.

Figure 2-13.

Stroke-linecap property

<svg> <!-- Line 1 --> <line x1="20" y1="20" x2="20" y2="120" fill="black" stroke="indigo" stroke-width="20" stroke-linecap="butt" /> <!-- Line 2 --> <line x1="60" y1="20" x2="60" y2="120" fill="black" stroke="indigo" stroke-width="20" stroke-linecap="round" /> <!-- Line 3 --> <line x1="100" y1="20" x2="100" y2="120" fill="black" stroke="indigo" stroke-width="20" stroke-linecap="square" /> <!-- Guide Lines --> <line x1="0" y1="20" x2="120" y2="20" fill="black" stroke="black" stroke-width="2"/> <line x1="0" y1="120" x2="120" y2="120" fill="black" stroke="black" stroke-width="2"/> </svg>

stroke-linejoin Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: miter | round | bevel | inherit Miter shapes and text content elements yes N/A visual yes 15

Learn SVG

Chapter 2 Basic Shapes

16

The default stroke-linejoin property value is miter which is just a normal boxed edge. SVG also offers a stroke-linejoin value of round and bevel as demonstrated in this example.

Figure 2-14.

Stroke-linejoin property

<svg width="250" height="200"> <rect x="10" y="10" width="50" height="50" fill="magenta" stroke="black" stroke-width="10" stroke-linejoin="round" /> <rect x="80" y="10" width="50" height="50" fill="maroon" stroke="black" stroke-width="15" stroke-linejoin="bevel" /> <rect x="150" y="10" width="50" height="50" fill="gray" stroke="black" stroke-width="10" stroke-linejoin="miter" /> </svg>

We will dig into style in greater depth in Chapter 5. For now lets move on to SVG Basic Shape elements.

Basic Shapes
Wherever we live on this planet our environments contain an infinite number of shapes. Some examples include natural things such as trees, fruits and clouds and also man-made things like symbols, clothes or computers. SVG allows us to easily model our world using six predefined intuitive shape elements. The basic shape elements are: rect circle ellipse line polyline polygon Each SVG shape has specific attributes that define the dimensions of the shape. For example, this image was created using two rect elements.

16

Learn SVG

Chapter 2 Basic Shapes

17

Figure 2-15.

Basic shapes

<svg width="300" height="300"> <rect x="80" y="10" width="40" height="40" fill="none" stroke="blue" /> <rect x="40" y="50" width="40" height="40" fill="none" stroke="red" /> </svg>

Let's cover each of the shape objects in detail.

Lines
The line element in SVG takes four geometric attributes: (x1, y1, x2, y2) These four geometric attributes define the lines elements start-point and end-point vertices. This is how a line appears in an SVG viewer.

Figure 2-16.

Line element diagram

<svg width="350" height="300"> <line x1="30" y1="80" x2="160" y2="20" stroke="darkslategray" stroke-width="2" stroke-linecap="round" /> </svg>

17

Learn SVG

Chapter 2 Basic Shapes

18

The first lines start-point begins 30 user units from the left and 80 user units from the top of the SVG document. The end-point is 160 user units from the left and 20 user units from the top. This is the syntax for the line element
<line id="name" x1="coordinate" y1="coordinate" x2="coordinate" y2="coordinate" style-attribute="style-value"/>

That being said, all of these attributes are actually optional for the line element.

Figure 2-17.

Special cases for the line element

<svg width="350" height="300"> <line x1="0" y1="0" x2="0" y2="0" stroke="darkslategray" stroke-width="2" stroke-linecap="round" /> <line x2="160" y2="20" stroke="darkslategray" stroke-width="2" stroke-linecap="round" /> </svg>

If either attribute pair is not specified then the values for those attributes are automatically rendered as if they were equal to zero. Likewise, as you can see in the example above, if the x1, y1 and x2, y2 value pairs are the same or if they are not specified then the line will not display. Line Element Designs Here are some useful techniques for creating fascinating designs with only one or two line elements.

18

Learn SVG

Chapter 2 Basic Shapes

19

Figure 2-18.

Amazing shapes with the line element

<svg width="800" height="600" viewBox="0 0 400 300"> <defs> <pattern id="gridPattern" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse"> <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.25"/> </pattern> </defs> <rect id="grid" width="350" height="211" stroke="gray" stroke-width="0.1" fill="url(#gridPattern)" /> <!-- grid --> <line x1="10" y1="30" x2="152" y2="30" stroke="darkslategray" stroke-width="40" stroke-dasharray="2 18" fill="none" /> <line x1="10" y1="70" x2="150" y2="70" stroke="darkslategray" stroke-width="20" stroke-opacity="0.5" stroke-dasharray="20 20" fill="none" /> <line x1="30" y1="110" x2="70" y2="110" stroke="darkslategray" stroke-width="40" stroke-linecap="round" fill="none" /> <line x1="110" y1="110" x2="150" y2="110" stroke="darkslategray" stroke-width="10" stroke-dasharray="0 20" stroke-linecap="round" fill="none" /> <line x1="130" y1="160" x2="130" y2="160" stroke="darkslategray" stroke-width="40" stroke-opacity="0.5" stroke-linecap="round" fill="none" />

19

Learn SVG

Chapter 2 Basic Shapes

20

<line x1="10" y1="160" x2="100" y2="160" stroke="darkslategray" stroke-width="40" stroke-dasharray="1 1 1 1 1 2 2 2 2 1 1 1 4 1 1 2 2 2 1 1 1 1 1 1 1 1 2 3 1 1 2 1 3 1 1 3 1 2 1 2 1 1" fill="none" /> <text x="75" y="200" font-size="8" text-anchor="middle">single lines</text> <line x1="180" y1="31" x2="322" y2="31" stroke="darkslategray" stroke-width="42" stroke-dasharray="2 18" fill="none" /> <line x1="251" y1="10" x2="251" y2="52" stroke="darkslategray" stroke-width="142" stroke-dasharray="2 18" fill="none" /> <line x1="180" y1="70" x2="320" y2="70" stroke="darkslategray" stroke-width="20" stroke-opacity="0.5" stroke-dasharray="20 20" fill="none" /> <line x1="180" y1="70" x2="320" y2="70" stroke="silver" stroke-width="20" stroke-opacity="0.5" stroke-dasharray="20 20" stroke-dashoffset="20" fill="none" /> <line x1="230" y1="130" x2="270" y2="130" stroke="darkslategray" stroke-width="40" stroke-opacity="0.7" stroke-linecap="round" fill="none" /> <line x1="250" y1="110" x2="250" y2="150" stroke="darkslategray" stroke-width="40" stroke-opacity="0.7" stroke-linecap="round" fill="none" /> <text x="250" y="200" font-size="8" text-anchor="middle">two lines each</text> </svg>

Circles The circle element takes three geometric attributes: cx, cy, and r) The cx and cy values specify the location of the middle of the circle while the r value specifies the radius of the circle. For example if you want to create a circle with a diameter of 80 user units then you need to set the value of the r attribute equal to 40 as in this example.

Figure 2-19.

Circle element diagram

20

Learn SVG

Chapter 2 Basic Shapes

21

<svg width="350" height="300"> <circle cx="100" cy="50" r="40" stroke="darkslategrey" stroke-width="2" fill="grey" fill-opacity="0.4"/> </svg>

This is the syntax for the circle element.


<circle id="name" cx="coordinate" cy="coordinate" r="length" style-attribute="style-value"/>

The r attribute radii parameter is required for rendering the circle element in SVG. If the cx and cy attributes are not specified then the circles center point is assumed to be (0, 0). However, if the r attribute is not specified or is set equal to zero then the circle will not appear in the image as shown in this example.

Figure 2-20.
<svg width="350" height="300">

Circle designs

<!-- Points --> <circle r="0" fill="black" stroke="black"/> <circle cx="10" cy="10" r="3" fill="black" stroke="black"/> <circle cx="30" cy="10" r="5" fill="black" stroke="red" stroke-width="2"/> <circle cx="50" cy="10" r="7" fill="black" stroke="red" stroke-width="2"/> <!-- Circles --> <circle cx="0" cy="50" r="20" fill="orange" stroke="black" stroke-width="3" /> <circle cx="70" cy="50" r="30" fill="grey" stroke="black" stroke-width="3" /> <circle cx="120" cy="50" r="40" fill="grey" fill-opacity="0.5" stroke="black" stroke-width="3"/> <circle cx="200" cy="50" r="50" fill="grey" fill-opacity="0.3" stroke="black" stroke-width="3"/> </svg>

The circle element can be used as the basis for buttons, wheels, gears, bubbles, people or even planets as well see later in this book. Circle Element Designs

21

Learn SVG

Chapter 2 Basic Shapes

22

Here are some useful techniques for creating fascinating designs using only one or two circle elements.

Figure 2-21.

Amazing shapes with the circle element

There is nothing up my sleeves. See the code for yourself!


<svg width="800" height="600" viewBox="0 0 400 300"> <defs> <pattern id="gridPattern" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse"> <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.25"/> </pattern> </defs> <rect id="grid" width="350" height="211" stroke="gray" stroke-width="0.1" fill="url(#gridPattern)" /> <circle cx="40" cy="40" r="20" stroke="darkslategray" stroke-width="20" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" /> <circle cx="120" cy="40" r="20" stroke="darkslategray" stroke-width="10" stroke-dasharray="1.75 8.72" fill="lightslategray" fill-opacity="0.5" /> <circle cx="40" cy="100" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="15.708 15.708" stroke-dashoffset="7.854" fill="lightslategray" fill-opacity="0.5"/> <circle cx="120" cy="100" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="47.124 15.708" stroke-dashoffset="7.854" fill="lightslategray" fill-opacity="0.5"/>

22

Learn SVG

Chapter 2 Basic Shapes

23

<circle cx="40" cy="160" r="20" stroke="darkslategray" stroke-width="2" stroke-dasharray="31.416 31.416" stroke-dashoffset="-15.708" fill="none" /> <circle cx="120" cy="160" r="20" stroke="darkslategray" stroke-width="8" stroke-dasharray="62.832 100" stroke-dashoffset="-41.888" fill="none" stroke-linecap="round" /> <text x="75" y="200" font-size="8" text-anchor="middle">single circle each</text> <circle cx="230" cy="40" r="20" stroke="darkslategray" stroke-width="20" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" /> <circle cx="230" cy="40" r="15" stroke="darkslategray" stroke-width="20" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" /> <circle cx="310" cy="40" r="20" stroke="darkslategray" stroke-width="10" stroke-dasharray="1.75 8.72" fill="lightslategray" fill-opacity="0.5" /> <circle cx="310" cy="40" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="0.875 14.833 0.875 100" fill="none" /> <circle cx="230" cy="100" r="20" stroke="darkslategray" stroke-width="2" fill="none" /> <circle cx="230" cy="100" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="0.524 2.094" fill="none" /> <circle cx="310" cy="100" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="15.708 15.708" stroke-dashoffset="7.854" fill="none" /> <circle cx="310" cy="100" r="10" stroke="lightslategray" stroke-width="20" stroke-dasharray="15.708 15.708" stroke-dashoffset="-7.854" fill="none" /> <circle cx="230" cy="160" r="10" stroke="darkslategray" stroke-width="20" stroke-dasharray="15.708 15.708" stroke-dashoffset="7.854" stroke-opacity="0.5" fill="lightslategray" /> <circle cx="230" cy="160" r="10" stroke="lightslategray" stroke-width="20" stroke-dasharray="15.708 15.708" stroke-dashoffset="-7.854" stroke-opacity="0.5" fill="none" /> <circle cx="310" cy="160" r="20" stroke="darkslategray" stroke-width="8" stroke-dasharray="6.981 13.962" stroke-dashoffset="3.491" fill="none" stroke-linecap="round" /> <circle cx="310" cy="160" r="10" stroke="lightslategray" stroke-width="20" stroke-dasharray="3.491 6.981" stroke-dashoffset="-3.491" fill="none" /> <text x="275" y="200" font-size="8" text-anchor="middle">two concentric circles each</text> </svg>

Rectangles

23

Learn SVG

Chapter 2 Basic Shapes

24

Rectangles take four geometric attributes: (x, y, width, height) The x (distance from the left) and y (distance from the top) attributes define the position of the top-left corner of the rectangle while the width and height attributes define the breadth and girth of this two dimensional object.

Figure 2-22.

Rectangle element diagram

<svg width="350" height="300"> <rect x="40" y="20" width="140" height="70" stroke="black" stroke-width="0.75" stroke-dasharray="6 3 2 3" fill="none" /> <rect x="40" y="20" width="140" height="70" rx="40" ry="20" stroke="darkslategray" stroke-width="2" fill="lightgray" fill-opacity="0.4" /> </svg>

This is the syntax of the rect element.


<rect id="name" x="coordinate" y="coordinate" width="length" height="length" style-attribute="style-value"/>

When no coordinates are specified the element's top left corner aligns with the image area's top left corner. The rx and ry geometric attributes are optional but they can be used define the distance that should be "rounded off" from each of the four corner edge's of the rectangle in the horizontal (rx) and vertical (ry) directions. For example take a look at this next SVG image.

24

Learn SVG

Chapter 2 Basic Shapes

25

Figure 2-23.
<svg width="500" height="300">

Rectangle element designs

<!-- Elliptical Rectangles --> <rect x="30" y="45" width="80" height="50" rx="50" ry="30" fill="lightgrey" stroke="black" stroke-width="1"/> <rect x="0" y="40" width="90" height="60" rx="40" ry="30" fill="white" stroke="none"/> <!-- Horizontal Rectangle --> <rect x="50" y="45" width="100" height="50" rx="10" fill="none" stroke="black" stroke-width="2"/> <!-- Verticle Rectangle --> <rect x="20" y="20" width="50" height="100" rx="10" ry="10" fill="peachpuff" stroke="forestgreen" stroke-width="2"/> </svg>

Also worth noting is that if only the rx attribute or if only the ry attribute if specified then the svg viewer will assume that both the rx and ry attribute value are the same. That is, if rx is set to 5 user units but ry is not specified then both rx and ry will be equal to 5 user units. This is demonstrated in the rectangle element that is horizontal in the example above.

25

Learn SVG

Chapter 2 Basic Shapes

26

Ellipses The ellipse element takes four geometric attributes: cx, cy, rx and ry.

Figure 2-24.

Ellipse element diagram

<svg width="350" height="300"> <ellipse cx="110" cy="55" rx="70" ry="35" stroke="darkslategray" stroke-width="2" fill="lightgray" fill-opacity="0.4" /> </svg>

As the example above clearly defines, the cx and cy values specify the center position of the ellipse while the rx and ry values specify the x-axis and y-axis radius of the ellipse element. Here is the syntax for the ellipse element.
<ellipse id="name" cx="coordinate" cy="coordinate" rx="length" rx="length" style-attribute="style-value"/>

If you want to create a circle with an x-axis diameter of 70 user units then you need to set the value of the rx attribute equal to 35 as in this next example.

Figure 2-25.
<svg width="350" height="300">

Ellipse element designs

26

Learn SVG

Chapter 2 Basic Shapes

27

<!-- Horizontal Ellipse --> <ellipse cx="70" cy="50" rx="50" ry="20" fill="yellow" stroke="black" stroke-width="4"/> <!-- Vertical Ellipses --> <ellipse cx="180" cy="90" rx="35" ry="60" fill="powderblue" stroke="black" stroke-width="4"/> <ellipse cx="180" cy="110" rx="35" ry="60" fill="powderblue" stroke="black" stroke-width="4"/> <ellipse cx="180" cy="100" rx="55" ry="60" fill="white" stroke="black"/> <!-- Circle Ellipse --> <ellipse cx="70" cy="80" rx="20" ry="20" fill="yellow" fill-opacity="0.4" stroke="black" stroke-width="4"/> <!-- Odd Ellipse --> <ellipse cx="70" cy="150" rx="25" ry="0" fill="yellow" stroke="black" stroke-width="4"/> </svg>

The rx and ry attributes radii attribute are both required for rendering the ellipse element in SVG. However, if either of these values is set equal to 0 then the ellipse and ends up looking like a line as shown here.

Figure 2-26.

Special cases for the ellipse element

<ellipse cx="110" cy="55" rx="70" ry="0" stroke="darkslategray" stroke-width="2" fill="lightgray" fill-opacity="0.4" />

As you can see the horizontal length has been set to zero so the ellipse ends up collapsing upon itself and therefore renders as if it were a line. Polygons and Polylines The polyline and polygon points attribute allows for multiple numbers of (x,y) coordinate pairs. Lets take a look at the example to see what this means.

Figure 2-27.

Polygon element diagram

<svg width="350" height="300"> <polygon fill="silver" stroke="black" stroke-width="2" points="50,100 50,80 120,50 150,20 200,80 200,100" />

27

Learn SVG
</svg>

Chapter 2 Basic Shapes

28

Note to reader
Make sure you specify an even number of coordinate values. That is, for every x that you specify be sure to define a corresponding y coordinate. Normally your SVG authoring environment will handle this for you. Polygons Polygons can be used to quickly create a wide variety of shapes as shown here.

Figure 2-28.

Polygon element designs

<svg width="350" height="250"> <!-- Triangle --> <polygon points="175,10 100,60 250,60" fill="darkblue"/> <!-- Plane --> <polygon points="73,34 90,50 80,85 40,50" fill="green" stroke-width="1"/> <!-- Trapezoid --> <polygon points="150,80 200,80 220,110, 130,110" fill="white" stroke="black" stroke-width="2"/> <!-- Octagon --> <polygon points="47,108 22,133 22,166 47,184 85,184 108,166 108,133 85,108" fill="darkred" stroke-width="1"/> <!-- ART --> <polygon points="150,120 200,120 130,180, 220,180" fill="pink" stroke="black" stroke-width="2"/> <polygon points="265,180 300,5 265,5 300,180" stroke="black" stroke-width="2" fill="lightgrey" /> </svg>

The syntax of the polygon element is pretty simple.


<polygon id="name" points="coordinates" style-attribute="style-value"/>

Polygon Element Designs Here are some useful techniques for creating fascinating designs with only one or two polygon elements. 28

Learn SVG

Chapter 2 Basic Shapes

29

Figure 2-29.

Amazing shapes with the polygon element

<svg width="800" height="600" viewBox="0 0 400 300"> <defs> <pattern id="gridPattern" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse"> <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.25"/> </pattern> </defs> <rect id="grid" width="300" height="211" stroke="gray" stroke-width="0.1" fill="url(#gridPattern)" /> <!-- grid --> <polygon points="20,50 60,50 40,15.36" stroke="darkslategray" stroke-width="15" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" stroke-linejoin="round" /> <polygon points="100,50 140,50 120,15.36" stroke="darkslategray" stroke-width="5" stroke-dasharray="20 20" stroke-dashoffset="10" fill="lightslategray" stroke-linejoin="round" /> <polygon points="20,110 60,110 40,75.36" stroke="darkslategray" stroke-width="15" stroke-dasharray="20 20" stroke-dashoffset="10" fill="none" stroke-linejoin="round" stroke-linecap="round" /> <polygon points="100,110 140,110 120,75.36" stroke="darkslategray" stroke-width="12" stroke-dasharray="20 20" stroke-dashoffset="-10" fill="none" stroke-linecap="round" /> <polygon points="20,170 60,170 40,135.36" stroke="darkslategray"

29

Learn SVG

Chapter 2 Basic Shapes

30

stroke-width="23" stroke-opacity="0.5" stroke-dasharray="20 20" stroke-dashoffset="-10" fill="none" stroke-linecap="round" /> <polygon points="100,170 140,170 120,135.36" stroke="darkslategray" stroke-width="15" stroke-dasharray="40 40 1 40" fill="lightslategray" stroke-linecap="round" /> <text x="75" y="200" font-size="8" text-anchor="middle">single triangle each</text> <polygon points="220,50 260,50 240,15.36" stroke="darkslategray" stroke-width="10" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" stroke-linejoin="round" /> <polygon points="220,26.9 260,26.9 240,61.54" stroke="darkslategray" stroke-width="10" stroke-opacity="0.5" fill="lightslategray" fill-opacity="0.5" stroke-linejoin="round" /> <polygon points="220,110 260,110 240,75.36" stroke="darkslategray" stroke-width="5" stroke-dasharray="20 20" stroke-dashoffset="10" fill="lightslategray" fill-opacity="0.5" stroke-linecap="round" stroke-linejoin="round" /> <polygon points="220,86.9 260,86.9 240,121.54" stroke="darkslategray" stroke-width="5" stroke-dasharray="20 20" stroke-dashoffset="10" fill="lightslategray" fill-opacity="0.5" stroke-linecap="round" stroke-linejoin="round" /> <polygon points="220,170 260,170 240,135.36" stroke="darkslategray" stroke-width="5" stroke-dasharray="0.1 17 6 17" stroke-dashoffset="0" fill="lightslategray" fill-opacity="0.5" stroke-linecap="round" stroke-linejoin="round" /> <polygon points="220,146.9 260,146.9 240,181.54" stroke="darkslategray" stroke-width="5" stroke-dasharray="0.1 17 6 17" stroke-dashoffset="0" fill="lightslategray" fill-opacity="0.5" stroke-linecap="round" stroke-linejoin="round" /> <text x="240" y="200" font-size="8" text-anchor="middle">two triangles each</text> </svg>

30

Learn SVG Polylines

Chapter 2 Basic Shapes

31

Take a look at the grammar used to describe the following polyline shape elements.

Figure 2-30.
<svg width="350" height="250">

Polyline element designs

<!-- Star Polyline --> <polyline points="50,10 60,30 80,40 60,50 50,70 40,50 20,40 40,30" fill="lightcyan" stroke="black" stroke-width="3"/> <!-- Line Polyline --> <polyline points="120,20 140,120 180,120 200,20" fill="cyan" fill-opacity="0.4" stroke="black" stroke-width="6" stroke-linecap="round" stroke-opacity="0.5" /> </svg>

Just like polygon, the polyline element use the points attribute to specify shape coordinates. Also, notice that if you follow the black stroke line it does not automatically close the shape as the polygon element automatically does. Polyline shapes are closed only when a line is specifically drawn back to the start point as shown in the 8-sided star above. The syntax of the polyline element is exactly the same as the polygon syntax.
<polyline id="name" points="coordinates" style-attribute="style-value"/>

What would happen if a polygon element contained just on set of point coordinates or just the same coordinate twice in a row? Well, surprisingly the polygon would not even be rendered as a dot in the image. Even with this simple example you can begin to see how inefficient it is to handcode the points element data. For example, imagine how many of the polyline points coordinates would be needed to render even a basic SVG chart or map. Indeed, SVG will rarely be hand coded. Many of SVG authoring environments and coding techniques are being developed which will generate most of the worlds SVG graphics. For the purpose of learning, it is not a bad idea to type in the samples. 31

Learn SVG

Chapter 2 Basic Shapes

32

Cool Shapes Challenge


Presentation attributes provide us with a tremendous amount of creativity, as you saw in the line, circle and polygon designs. The Challenge Try design a set of unique designs using only presentation attributes and three or less elements from any of SVGs basic shapes. Email your best designs to dev@learnsvg.com and we will post them on our website. You may even win the trendy Learn SVG T-Shirt! Basic Shape Elements Reference Here is a basic reference containing a list of each of the basic shape elements and their required and optional attributes. Shape Line Rectangle Circle Ellipse Polyline Polygon

Element
<line> <rect> <circle> <ellipse> <polyline> <polygon>

Required Attributes
(none) width, height R Rx, ry points points

Optional Attributes
x1, y1, x2, y2 x, y, rx, ry cx, cy cx, cy

Future Shapes? A few other shape elements such as arc (open, closed, pie slice), spiral, star and regular polygons are currently being considered for inclusion in the next version of SVG but we will not pontificate on them here. This is cool stuff. Its quite easy to describe each of these shapes, these shapes are scalable, and as we will soon found out they are all scriptable and animatable! Note: Shapes elements are merely paths that are made of straight lines and curves. SVG has a path element that is the most powerful shape element that can be used to render each of the other shapes and even the most complex paths. In actuality, shapes and paths are mathematically equivalent and the reason why the SVG Working Group included all six of the shape elements was in part for our ease of understanding and use. We will be covering the path element in greater detail in Chapter 4.

32

Learn SVG

Chapter 2 Basic Shapes

33

The image Element


Raster Image SVG is a unique type of graphic in that it can contain a variety of file formats. SVG documents can contain other SVG documents as well as JPEG and PNG raster graphics. PNG and JPEG images can be transformed, animated or even controlled dynamically and interactively through script. The image element attributes are: (x, y, width, height, xlink:href) x, y, width, height, and xlink:href. The x and y attributes define the coordinates of the top-left corner of the image. The width and height attributes define the scale of the image and the xlink:href attribute defines the path location of the raster image.

Figure 2-31.

Referenced raster image

<svg width="350" height="250"> <image xlink:href="3202948.jpg" x="340" y="0" width="140" height="160" opacity="0.5"/> </svg>

Compared to HTML In order to use images in HTML we use the img element with the src attribute. SVG is much the same. In order to reference images in SVG we use SVGs image element. Just like in HTML, in SVG the width and height attributes can be used to set the specific scale of JPEG and PNG images. The attribute we use to reference the specific path to the image file or information is xlink:href. The xlink: is referencing a namespace which we will be discussing in depth in Chapter 11. For now just think of the xlink:href as being the same as HTMLs src attribute. Supported Image Types SVGs ability to precisely position and rotate and transform images makes SVG ideally suited for displaying raster images. Currently, PNG and JPEG images are the only images that the SVG specification requires that SVG viewers support. Web developers will find that the JPEG and PNG raster graphic formats will remain important formats due to the fact that JPEG and PNG raster images excel at displaying certain

33

Learn SVG

Chapter 2 Basic Shapes

34

detailed graphics that would be inefficient for SVG to render mathematically. JPEG is still the crme-de-la-crme image format for photographic and other high-quality images.

Note to reader
Not all SVG viewers will necessarily support GIF images. This is not as terrible as it might sound. PNGs serve as an excellent replacement for GIFs in most regards (except for animated raster images) and can now be generated or exported from most all graphic design applications. As of this writing the SVG Viewer plug-in does support the GIF image format. Relative and Absolute Directory Paths In different environments there are advantages and disadvantages to using either method. Also be aware that not all browsers treat absolute and relative paths the same when using the SVG Viewer. Relative paths can be tricky to keep track of and maintain. If you ever notice missing graphics then the path that is specified in the image elements src attribute value is the first thing to check. I have created several folders under my Web sites root folder so my directory structure is a follows: \root \images \script \stylesheets \svg As you can see the folder structure organizes the style sheets, script, and various types of media that are used in our Web site. In order for the SVG file that is located in the \svg folder to be able to reference our logo image file that is in the \img folder we need to specify the following path in our image elements src attribute value: ../img/logo.jpg. Just as in HTML the two dots that precede the /img directory path are used to move up one level in our Web sites directory structure before moving down into the /img directory where our logo.jpg file is stored. <image xlink:href=../images/logo.jpg>

Dissecting an SVG Image


Design time! Its time to stimulate the other side of our cerebral mass. First, put on some of your favorite music and get ready to play. Now lets fire up our favorite SVG authoring environment and get started. Were going to dive into the more practical aspects of creating/authoring each of these shapes using SVG authoring environments. So, fire up those SVG authoring environments so we can begin to get down with the funkiness of SVG! Now were ready to take a look at the source code of the SVG image that we saw at the beginning of Chapter 1. Now that we have a feel for the structure of SVG and we also know how to view SVG graphics we are going to start exploring ways of designing SVG graphics. We are also going to get a first hand look at some SVG graphics that will better explain how SVG works. 34

Learn SVG

Chapter 2 Basic Shapes

35

Figure 2-32.

Illustration of SVG capabilities

Full SVG Code Here is the complete SVG code of the graphic.
<svg width="100%" height="100%"> <title>Scalable Vector Graphics - Introduction</title> <desc>This graphic demonstrates many exciting features of SVG.</desc> <defs> <circle id="Ball01" cx="100" cy="100" r="40" fill="url(#Grad01)"/> <text x="50%" y="80%" text-anchor="middle" writing-mode="lr">S V G</text> <pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern> <radialGradient id="Grad01" gradientUnits="userSpaceOnUse" cx="120" cy="60" fx="130" fy="50" r="100"> <stop offset="0%" stop-color="white"/> <stop offset="20%" stop-color="#cccccc"/> <stop offset="100%" stop-color="rgb(100,20,150)"/> </radialGradient> <marker id="Marker01" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="6" orient="auto"> <path d="M 0 0 L 15 5 L 0 10 z" /> </marker> </defs> <g letter-spacing="0.02em" enable-background="new"> <!--BACKGROUND--> <rect id="Background" fill="url(#Pat01)" stroke-width="0.5" stroke="#000000" x="0" y="0" width="100%" height="100%"> <desc>Background Pattern</desc>

35

Learn SVG

Chapter 2 Basic Shapes

36

</rect> <g id="watermark" fill="#000000" font-weight="bold" font-size=180" font-family="san-serif,Arial,Verdana" opacity="0.2"> <text x="50%" y="70%" text-anchor="middle" stroke="none" writing-mode="lr">S V G</text> </g> <!--SCALABLE--> <text x="30" y="180" stroke="none" writing-mode="lr">SCALABLE</text> <use xlink:href="#Ball01" x="0" y="0" transform="scale(0.1)"/> <use xlink:href="#Ball01" x="0" y="0" transform="scale(0.25)"/> <use xlink:href="#Ball01" x="0" y="0" transform="scale(0.5)"/> <use xlink:href="#Ball01" x="0" y="0" transform="scale(1)"/> <!--VECTOR--> <text x="205" y="180" stroke="none" writing-mode="lr">VECTOR</text> <line x1="165" y1="16" x2="165" y2="132" stroke="black" stroke-width="1.5" marker-end="url(#Marker01)"/> <line x1="165" y1="16" x2="272" y2="16" stroke="black" stroke-width="1.5" marker-end="url(#Marker01)"/> <!--GRAPHICS--> <text x="385" y="180" stroke="none" writing-mode="lr">GRAPHICS</text> <image xlink:href="3202948.jpg" x="340" y="0" width="140" height="160" opacity="0.5"/> </g> </svg>

Thats it! If you look through the SVG code you will quickly notice some recognizable terms such as circle, text, line, image, style, stroke, fill and opacity. Undoubtedly there are several other terms that are not as obvious such as pattern, gradient, marker, path, use, xlink:href, cx, cy, stop, patternUnits, and gradientUnits. All of these terms are thoroughly examined throughout this book through a host of brilliant examples, tutorials, scenarios and even advanced applications. As with life, the beauty is in the details so lets briefly look at some of the SVG code that produced the above SVG graphic. Lines used for vector arrows Lines are used to demonstrate the 2-dimensional vector aspect of SVG images.

Figure 2-33.

2-D vector arrows using markers

<!--VECTOR--> <line x1="165" y1="16" x2="165" y2="132" stroke="black" stroke-width="1.5"

36

Learn SVG

Chapter 2 Basic Shapes

37

marker-end="url(#Marker01)"/> <line x1="165" y1="16" x2="272" y2="16" stroke="black" stroke-width="1.5" marker-end="url(#Marker01)"/>

Notice the marker-end attribute. The marker-end attribute value url(#Marker01) references a marker element that is defined inside of the defs element. The defs element is used to contain graphical objects that are not intended to be displayed directly but rather are referenced by other elements in the graphic.
<marker id="Marker01" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="6" orient="auto"> <path d="M 0 0 L 15 5 L 0 10 z" /> </marker>

The marker element draws the same arrow at the end of each of line element. Rectangle used for the background pattern This rectangle defines the grid background of our image.
<!--BACKGROUND--> <rect id="Background" x="0" y="0" width="100%" height="100%" fill="url(#Pat01)" stroke-width="0.5" stroke="#000000" > <desc>Background Pattern</desc> </rect>

Notice that the fill property value of this rectangle element is a reference to something called url(#Pat01). This is actually a reference to a pattern element that is located inside of a defs elements.
<pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern>

We will be looking at more patterns in the next chapter. Circle used to show demonstration of scalability Here we use the use element to demonstrate the ability to scale a circle element.
<!--SCALABLE--> <use xlink:href="#Ball01" <use xlink:href="#Ball01" <use xlink:href="#Ball01" <use xlink:href="#Ball01" x="0" x="0" x="0" x="0" y="0" y="0" y="0" y="0" transform="scale(0.1)"/> transform="scale(0.25)"/> transform="scale(0.5)"/> transform="scale(1)"/>

Once again we are referencing the circle element that is located in our defs element. In this case however we are using the xlink:href attribute rather than the url() attribute.
<defs> <circle id="Ball01" cx="100" cy="100" r="40" fill="url(#Grad01)"/> </defs>

37

Learn SVG

Chapter 2 Basic Shapes

38

We will be looking at the powerful transform attribute in depth in Chapter 6. Text Element We also made use of the text element to display the text SCALABLE VECTOR GRAPHICS.
<!--SCALABLE--> <text x="30" y="180" stroke="none" writing-mode="lr">SCALABLE</text> <!--VECTOR--> <text x="205" y="180" stroke="none" writing-mode="lr">VECTOR</text> <!--GRAPHICS--> <text x="385" y="180" stroke="none" writing-mode="lr">GRAPHICS</text>

We will cover all aspects of text processing in depth in Chapter 5.

SVG Concepts: A Word from Our Sponsor XML


At this time we thought it would be appropriate to give some free sponsorship and thanks to our sponsors at eXtensible Markup Language (XML) since they provide the grammar that provides the syntax for powering the SVG that we use every day. XML is the markup-language grammar which is the basis for a whole new generation of markup-languages, such as custom XML "vocabularies", industry-namespaces, etc. which work hand-in-hand with other XML-namespaces including the styling-language XSL, the transformation-language XSLT, XML Linking Language (Xlink) and many other XML applications. Designers are able to output XML grammar from design authoring environments, developers can write programs to structure, manipulate, and manage the files, and publishers can easily modify the XML text documents and assign CSS or XSL style-sheets. This is a new system of technologies that is currently under development at the World Wide Web Consortium (W3C - www.w3.org) and that will take the Web and the worlds of publishing, writing, design, and knowledge-management to a new era. SVG fits nicely into the picture as an XML-language for describing interactive vectoranimations. We will discuss XML in greater detail throughout this book.

Summary

38

Learn SVG

Chapter 2 Basic Shapes

39

In this chapter we introduced several key concepts and terms including basic shape elements and supported raster image types. In the next chapter we will take an in-depth look at the structure of SVG documents. But, as is the case with all new entities that we encounter, in order to derive the greatest benefits it is necessity that we digest in portions, so feel free to lay back and rest on your laurels for a bit.

39

Chapter 3 : Document Structure


Benefits of Structured Documents When creating a graphical presentation with SVG we can, more often than not, utilize many different methods to achieve our aim. By this I dont simply mean the ability to achieve an identical presentation with different graphical elements, for example using the general <path> element to create a rectangle instead of the more specialized and comfortable <rect> element. Nor am I concerned with different styling options via <style> elements or presentation attributes. Essentially I am referring here to the deliberate use of SVGs structuring elements, which we will also designate as container elements. Lets start directly into this with an example. Suspend disbelief for a moment, escape the world of design and assume that you are a pallet rack manufacturer, in fact a pallet manufacturer with a penchant for graphical presentations of your products. Below is a pile of your produce.

Figure 3-1. The pallet rack Now, you might create the above vector graphics image by coding the following SVG document:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <rect x="50" y="20" width="12" height="300" stroke="black" fill="steelblue" /> <rect x="64" y="20" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="64" y="120" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="64" y="220" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="350" y="20" width="12" height="300" stroke="black" fill="steelblue" /> <rect x="364" y="20" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="364" y="120" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="364" y="220" width="284" height="10" stroke="black" fill="steelblue" /> <rect x="650" y="20" width="12" height="300" stroke="black" fill="steelblue" /> <rect x="30" y="320" width="654" height="10" stroke="none" fill="lightgray" />

Learn SVG

Chapter 3 Document Structure

<line x1="30" y1="320" x2="684" y2="320" stroke="black" /> </svg>

So, what do we have here? Well, a really simple document consisting almost exclusively of <rect> elements. It is compact and somehow elegant. Nevertheless, you are a rack manufacturer and used to thinking in terms of racks, upright posts, beams and pallets. With this in mind your document is not particularly verbose. In order to identify the beams in this document we have to look at those <rect> elements with a width attribute much bigger than their height attribute not particularly helpful! Despite the documents simple appearance and near-symmetrical pattern, it does not give us many clues to meaning, to what part of the code is doing what, and how it is controlled. Let us create, then, a document with an identical end-product, but which is richer in structure and organization. If youve not already done so I suggest you have a read through the
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="12" height="300" /> <rect id="beam" x="14" y="0" width="284" height="10" /> <g id="column"> <use xlink:href="#beam" x="0" y="0" /> <use xlink:href="#beam" x="0" y="100" /> <use xlink:href="#beam" x="0" y="200" /> <use xlink:href="#uprightPost" x="300" y="0" /> </g> <g id="rack"> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="300" y="0" /> <g id="ground"> <rect x="-20" y="300" width="662" height="10" stroke="none" fill="lightgray" /> <line x1="-20" y1="300" x2="642" y2="300" stroke="black" fill="none" /> </g> </g> </defs> <use xlink:href="#rack" x="50" y="20" fill="steelblue" stroke="black" /> </svg>

What a document! You might stare at it, wondering why I consider this second one, with nearly double the size of the first, an improvement after all, both render the same graphical output. Remember though, that we wanted a more meaningful document, and indeed the longer you look at the second documents code, the better we can understand its structure consisting of racks, upright posts and beams, it is somehow both self-referential and self-explanatory. I wont discuss the SVG key features used in detail here since we will do this in the rest of this chapter. Quick Change Just to demonstrate the increased functionality of our second piece of code, lets suppose we wanted to include the following adjustments: A rack with stronger beams A red rack A rack with one more column

Learn SVG

Chapter 3 Document Structure

Figure 3-2. Pallet Rack Adjustements

1. We create the first variant with a slight modification of the height attribute in a single line:
<rect id="beam" x="14" y="0" width="284" height="20" />

2. The second variant is generated by changing the colour in:


use xlink:href="#rack" x="50" y="20" < fill="red" stroke="black" />

3. Finally, we end up in the third variant by adding one single line of SVG code:
<g id="rack"> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="300" y="0" /> <use xlink:href="#column" x="600" y="0" />

4. Now try to generate these variants shown above with the first unstructured document. Awkward isnt it! So, as a generalization, Structure in documents is the way forward.
Another option

So, now that you are now deeply impressed by the potential power of structured documents, but still complaining about the increased file size, take a look at this third document. It results in the same graphical output as the previous two SVG documents.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <g id="rack" externalResourcesRequired="true"> <use xlink:href="RackParts.svg#xpointer(id('uprightPost'))" x="0" y="0" /> <use xlink:href="RackParts.svg# xpointer(id('column'))" x="0" y="0" /> <use xlink:href="RackParts.svg# xpointer(id('column'))" x="300" y="0" /> <g id="ground"> <rect x="-20" y="300" width="662" height="10" stroke="none" fill="lightgray" /> <line x1="-20" y1="300" x2="642" y2="300" stroke="black" fill="none" /> </g> </g> </defs> <use xlink:href="#rack" x="50" y="20" fill="steelblue" stroke="black" /> </svg>

Here again I dont want to explain the content in detail, but here are some useful characteristics of the document.

Learn SVG

Chapter 3 Document Structure

The files size is even smaller than that of the first unstructured document. We put the groups uprightPost, beam and column into an external file RackParts.svg. We simply reference the groups in that external file. Now you may be thinking Its a bluff. As we need the code in the external file, we didnt actually reduce the total code size. OK. Youre right, to an extent. But the benefit of evacuating SVG elements into external files comes with the magic of sharing code. As you (the pallet manufacturer remember) have to handle not only one rack image, but several hundred different ones, all those different SVG documents will refer to that one single file. That is real code reduction. Reusing Elements Lets have a closer look at how SVGs mighty define once, use everywhere principle works in detail. To do this in an illustrative manner, we will gradually evolve the rack example. We start with two upright posts and three beams.

Figure 3-3. Basic Element

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <!-- the upright posts --> <rect x="50" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <rect x="200" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <!-- the beams --> <rect id="beam" x="62" y="20" width="136" height="8" fill="steelblue" stroke="black" /> <rect id="beam" x="62" y="70" width="136" height="8" fill="steelblue" stroke="black" /> <rect id="beam" x="62" y="120" width="136" height="8" fill="steelblue" stroke="black" /> </svg>

Realizing that the three rectangles of the beams are identical except for their location, we decide to try out SVGs element reuse concept with them.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <!-- the upright posts --> <rect x="50" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <rect x="200" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <!-- the beams --> <rect id="beam" x="62" y="20" width="136" height="8" fill="steelblue" stroke="black" /> <use xlink:href="#beam" x="0" y="50" /> <use xlink:href="#beam" x="0" y="100" />

Learn SVG
</svg>

Chapter 3 Document Structure

It works, thanks to SVGs referencing element <use>. The first rectangle is simply cloned i.e. duplicated and positioned at the same location as the previous second and third rectangle. So we get an identical image as before. Now it is time to take a closer look at the <use> elements syntax: Syntax
<use xlink:href=uri x=coordinate y=coordinate width=length height=length style-attribute=style-attribute >

The xlink:href attribute references the target element via its id, so we need to provide id attributes for all elements we want to refer to by <use>. Bear in mind that the ids values must be unique across the document. Since the ids value must be an XML URI (uniform resource identifier), we can reference any element in any SVG document across the web. Most often you will access elements in your local document (local URI reference) via
xlink:href="#name"

but we can also reference elements in external resources (non-local URI reference) by an absolute URI as in
xlink:href="http://www.w3.org/TR/2001/REC-SVG-20010904/images/struct/Use01.svg/#xpointer(id('MyRect'))"

or by a relative URI as in
xlink:href="../svglib/Vehicels.svg#xpointer(id('Motorcycle'))"

Using the x and y attribute, we can position our duplicated element in the drawing, and methods of interpreting the attributes values will be discussed later in the chapter, where we examine coordinate systems and transformations. For now, simply add the x and y values to the coordinates of the referenced object to get the correct position. When you omit the x- and y-attribute as in
<use xlink:href="#beam" />

the x- and y-values are taken to be zero, so the <use> element is positioned exactly over its referenced original. One drawback of utilizing the <use> element is that we are unable to manipulate the original referenced elements attributes. While we may make adjustments to the instance we are dealing with, the original will remain the same. We can duplicate it and put it at a different place in the document, but thats it . As it is so important, here are the characteristics of the <use> element again. The <use> element creates a reference to another SVG element. We must assign an id attribute to those elements that might be reused by <use>. This id attribute is available for all SVG elements. The referenced SVG element can reside in the same file, or in another SVG file. This fact supports the evolving of application specific symbol libraries.

Learn SVG

Chapter 3 Document Structure

The <use> element cannot change any attributes of the referenced element. The application of the <use> element on a complex element a <path> element with lots of data can result in a notably reduced file size. Use All or Nothing Lets have a look at our rack example in more detail. Maybe we can improve it further.

Figure 3-4. A basic element


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <svg> <!-- the upright posts --> <rect x="50" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <rect x="200" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <!-- the beams --> <rect id="beam" x="62" y="20" width="136" height="8" fill="steelblue" stroke="black" /> <use xlink:href="#beam" x="0" y="50" /> <use xlink:href="#beam" x="0" y="100" /> </svg>

This is the SVG document from above. We didnt change anything so far, and still want to focus on the structure of the beams.
Spot the difference

Just looking at the image its impossible to tell which of the beams is the original and which are the clones. We have to look into the code to identify the upper beam as the original element. This may prompt the question
What is the importance of the original beam over the clones?

The answer is simply Nothing. The importance is to be found in our group structure only. Visually there is no difference whatsoever. However, it will of course behave differently, and need to be treated differently. Assume we want to raise the lower beam by 20 units. No problem, we change the y-attribute of the last <use> element.
<use xlink:href="#beam" x="0" y="90" />

Learn SVG

Chapter 3 Document Structure

Figure 3-5. Modified element This gives the result seen above. Now lets make a change to the original, the topmost beam. As we now want to lower the upper beam, well need to change the beams original <rect> element. But wait all of our <use> elements are dependent on the attributes of our original, a change here will affect all instances of our rectangle. Thus, we need to compensate for this in each <use> element.
<rect id="beam" x="62" y="30" width="136" height="8" fill="steelblue" stroke="black" /> <use xlink:href="#beam" x="0" y="40" /> <use xlink:href="#beam" x="0" y="80" />

Figure 3-6. Another modified element Fine, that works too. But with some more work, as we must modify all affiliated <use> elements. We were lucky we didnt have to accommodate several hundred beams! OK. So what did we just learn? The advantage, that the change of an elements attribute is transparent to all referencing <use> elements, became a disadvantage here. It would be best, if we didnt have the original element visible. So we would not have needed to change its position. What if we put the original graphical element into a <def> section?

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <!-- the upright posts --> <rect x="50" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <rect x="200" y="20" width="10" height="150" fill="steelblue" stroke="black" /> <defs> <!-- the beam --> <rect id="beam" width="136" height="8" fill="steelblue" stroke="black" />

Learn SVG

Chapter 3 Document Structure

</defs> <use xlink:href="#beam" x="62" y="30" /> <use xlink:href="#beam" x="62" y="70" /> <use xlink:href="#beam" x="62" y="110" /> </svg>

This markup results in exactly the same image the difference is that all visible rectangles are simply <use> elements of our original, which is now tucked safely away in a <defs>. This ensures that any
changes we make to individual instances will not affect other instances. If you want to reuse any SVG element, put this element into a <defs> section. This is an important point. As the SVG specification tells us For understandability and accessibility reasons, it is recommended that, whenever possible, referenced elements be defined inside of a 'defs.

Groups Now I want to introduce you to SVGs most important structural element the group element <g>.The group element is not a graphics element. That is, it produces no graphical output by itself. It is rather a container element like the <def> element meant for collecting different elements, mainly other graphics elements and graphics referencing elements, but also other container elements. Syntax
<g id=<name> style-attribute=style-attribute transform=transformation commands> <!-- groups content here --> </g>

The id attribute is the standard XML attribute for assigning a unique name to an element. It is heavily used with groups. The id attribute must be known to any other element that needs to reference the group. The behaviour of the styling attributes will be discussed later in this chapter. With that knowledge we now want to build a group column out of the three beams and the right upright post in order to reuse that group later.

Figure 3-7. Column group


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" fill="steelblue" stroke="black" /> <rect id="beam" width="136" height="8" fill="steelblue" stroke="black" /> </defs> <use xlink:href="#uprightPost" x="50" y="20" /> <g id="column"> <use xlink:href="#beam" x="62" y="20" />

Learn SVG

Chapter 3 Document Structure

<use xlink:href="#beam" x="62" y="70" /> <use xlink:href="#beam" x="62" y="120" /> <use xlink:href="#uprightPost" x="200" y="20" /> </g> </svg>

As expected, we dont see any sensational shift. Nevertheless, we will benefit from this structural improvement soon. A look at the SVG code shows nothing magical. To build a group, just enclose the graphic elements you want to collect within the group tags <g> .. </g>. There are several reasons why we may need to include a group. We need to create a meaningful object for reuse. We want to make your code more self-explaining and collect elements with a common logical context. We want the group elements to share particular presentation attributes. We intend to emulate layers and control their visibility. Using Groups The usefulness of the <g> element is largely increased by its companion the familiar <use> element. We apply <use> to drawing elements in the same way we use it for groups. So we are finally able to create a real world pallet rack.

Figure 3-8. More elements Here is the code:


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" fill="steelblue" stroke="black" /> <rect id="beam" width="136" height="8" fill="steelblue" stroke="black" /> <g id="column"> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> </defs> <use xlink:href="#uprightPost" x="50" y="20" /> <use xlink:href="#column" x="50" y="20" /> <use xlink:href="#column" x="200" y="20" /> <use xlink:href="#column" x="350" y="20" /> <use xlink:href="#column" x="500" y="20" /> </svg>

Learn SVG

Chapter 3 Document Structure

10

As we learned in the section about element reuse, we put the column group into a <defs> section. Now we have only five elements that create graphical output: One instance of uprightPost and three instances of column. Since it is so important, I need to tell you again:
Every group that will be instantiated more than once, should go into a <defs> section.

It is not uncommon to reuse groups in different SVG files. We still know how SVG supports the referencing of elements from other local files or even across the World Wide Web via the xlink:href="uri" attribute. We want to do this now with our rack example. So this results in two files:
RackParts.svg
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" fill="steelblue" stroke="black" /> <rect id="beam" width="136" height="8" fill="steelblue" stroke="black" /> <g id="column"> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> </defs> </svg>

and Rack.svg
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" externalResourcesRequired="true" xmlns="http://www.w3.org/2000/svg"> <use xlink:href="../parts/RackParts.svg#xpointer(id('uprightPost'))" x="50" y="20" /> <use xlink:href="../parts/RackParts.svg#xpointer(id('column'))" x="50" y="20" /> <use xlink:href="../parts/RackParts.svg#xpointer(id('column'))" x="200" y="20" /> <use xlink:href="../parts/RackParts.svg#xpointer(id('column'))" x="350" y="20" /> <use xlink:href="../parts/RackParts.svg#xpointer(id('column'))" x="500" y="20" /> </svg>

The file RACKPARTS.SVG is located in a subdirectory parts parallel to your current directory where RACK.SVG resides. We have just stepped over the point of no return. No longer will you be able to cope without groups in your SVG files. And since we are getting used to using them, lets now have a look at structuring our documents with a number of groups. Nested Groups Remember that I mentioned that a group, as a container element, can collect other SVG elements. Not only graphics elements, but also container elements in particular other groups. With that we have groups inside of groups or nested groups. You may be quite uncertain now, how to reference nested groups or why you should have nested groups at all. Before we discuss this further, let us explore the nesting of groups with our familiar rack example.

10

Learn SVG
Nesting our pallet groups

Chapter 3 Document Structure

11

The images in the brochure of your company always have a floor-segment drawn under the rack. To visualize this floor-segment we use a black line and a grey rectangle. Furthermore the beams are missing some details the fasteners. Ok, well start with the fasteners. 1. Shorten the beams a little and place two small rectangles at each end. 2. Put these three elements into a group named beam, so that the rest of the SVG document isnt affected if we modify this beam. 3. Well also define a new group rack out of the starting upright post and all columns. Well add the floor-segments line and rectangle too.

Figure 3-9. Rack with floor


4.

This leaves us with the following code


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" fill="steelblue" stroke="black" /> <g id="beam"> <rect x="0" width="3" height="16" fill="steelblue" stroke="black" /> <rect x="5" width="126" height="8" fill="steelblue" stroke="black" /> <rect x="133" width="3" height="16" fill="steelblue" stroke="black" /> </g> <g id="column"> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> <g id="rack"> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" /> <use xlink:href="#column" x="300" y="0" /> </g> </defs> <use xlink:href="#rack" x="50" y="20" /> <rect x="40" y="170" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="40" y1="170" x2="520" y2="170" stroke="black" /> </svg>

The image looks quite good. Though after having added the line and the rectangle to the document, it looks somewhat unstructured. The rectangle and the line belong logically together. So we feel, we should have a group floor.

11

Learn SVG

Chapter 3 Document Structure

12

5. Implement this group in the following manner


<use xlink:href="#rack" x="50" y="20" /> <g id="floor" /> <rect x="40" y="170" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="40" y1="170" x2="520" y2="170" stroke="black" /> </g>

Ok, that seems to be a bit more structured. Should we now leave the group floor where it is or would it be it better placed inside of the <defs> section? Well, we wont reference this group, so we do not necessarily need to add it to the <defs> section. But perhaps we should think more about where this floor segment belongs. The question we need to address is Does each rack need its own floor segment? You, the rack expert, spontaneously answer here: yes absolutely since it is very uncommon, that rack images share floor space. Fine, so the floor group can go into the rack group. Its really that simple! 6. Make the following adjustments to your code
<g id="rack"> <g id="floor" /> <rect x="-10" y="150" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="-10" y1="150" x2="470" y2="150" stroke="black" /> </g> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" /> <use xlink:href="#column" x="300" y="0" /> </g>

If youre wondering why I inserted the floor group at the beginning of the rack members, rather than appending it at the end, I must say here, its only a matter of personal coding style. It is no problem here (due to the fact, that no graphics elements overlap), to have the floor group appended at the existing group members alternatively. Please also note, that we needed to modify the lines and rectangles coordinates a little (we subtracted the coordinates of the last <use> element). This will become more transparent in Chapter 6, where we will talk about coordinate systems and transformations. After looking at the SVG code, you may question: Why didnt we define the beams group also inside of the columns group, as it is solely used there too? Good. I like your thinking. There seem to be no arguments against this remarkable observation. 7. So we update the column group accordingly.
<g id="column"> <defs> <g id="beam"> <rect x="0" width="3" height="16" fill="steelblue" stroke="black" /> <rect x="5" width="126" height="8" fill="steelblue" stroke="black" /> <rect x="133" width="3" height="16" fill="steelblue" stroke="black" /> </g> </defs> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g>

12

Learn SVG

Chapter 3 Document Structure

13

Here we could not simply transfer the beams group into the columns group. We had to create a local <defs> section first. Why? Well, we learned, that everything in a <defs> section will not get rendered, it is for referencing only. So what, if we reference the columns group without its internal <defs> section? Correct the internal beams group would become visible. As we also learned, to put everything into a <defs> section that will be referenced, we have to put it into a <defs> section local to the group. Confusing you may think. Why didnt we just leave the beam where it was? The answer is (as you should be getting used to by now) clean document structure.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" fill="steelblue" stroke="black" /> <g id="column"> <defs> <g id="beam"> <rect x="0" width="3" height="16" fill="steelblue" stroke="black" /> <rect x="5" width="126" height="8" fill="steelblue" stroke="black" /> <rect x="133" width="3" height="16" fill="steelblue" stroke="black" /> </g> </defs> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> <g id="rack"> <g id="ground"> <rect x="-10" y="150" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="-10" y1="150" x2="470" y2="150" stroke="black" /> </g> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" /> <use xlink:href="#column" x="300" y="0" /> </g> </defs> <use xlink:href="#rack" x="50" y="20" /> </svg>

Fantastic a place for everything and everything in its place. Group rules Here are some rules of thumb on proper group location: General purpose groups, that are to be instantiated from anywhere in the same or even from other documents, should be placed in an outermost <defs> section (public group). Groups, that are reused exclusively in one enclosing parent group, should be defined in that parent group (private group). So the parent group can be designed as complete as possible. Avoid references to an inner group from outside its parent group (public access to a private group). Never instantiate a group from inside that group (self-reference). The behaviour is undefined. Styling of Groups The SVG committee wisely designed the <g> element so that it passes its style to the enclosed elements. What we see then results from the CSS2 inheritance rules.
13

Learn SVG

Chapter 3 Document Structure

14

Lets illustrate this by example. 1. Enter the following markup into a fresh document. Two blue circles are contained in a group.

Figure 3-10. Two blue circles


<g> <circle cx="50" cy="50" r="20" fill="blue" /> <circle cx="100" cy="50" r="20" fill="blue" /> </g>

2. Now, we can make the fill colour a presentation attribute of the enclosing group.
<g fill="blue"> <circle cx="50" cy="50" r="20" /> <circle cx="100" cy="50" r="20" /> </g>

You see that the contained elements inherit their style from,the group. 3. So what happens, if one element has a colour defined and another hasnt? Lets see

Figure 3-11. Blue group and red circle


<g fill="blue"> <circle cx="50" cy="50" r="20" /> <circle cx="100" cy="50" r="20" fill="red" /> </g>

Fine, if an element wants to have a certain colour here red it simply defines that colour by a presentation attribute or via CSS styles. This colour will remain unaffected. Only those elements, that dont have a colour defined will inherit it from their enclosing group. So if we have a group of elements, that have a lot of style in common, it is always a good idea to define this style by the group. Moreover, if we have to deal with a lot of elements with common style, we should even consider enclosing these elements in a group just to share that style. 4. Just to be sure that this works also with nested groups, well expand our example a bit.

Figure 3-12. Green group and red circle


<g fill="green"> <g> <circle cx="50" cy="50" r="20" />

14

Learn SVG

Chapter 3 Document Structure

15

<circle cx="100" cy="50" r="20" fill="red" /> </g> <rect x="130" y="30" width="40" height="40" /> </g>

No surprise here. The inner group, as well as its contained elements inherit the colour from the outer group as expected. Please note, that for simplicity I use presentation attributes only here in this chapter. Using CSS styles instead, the above is also true. You should only know, that
When mixing presentation attributes and CSS style sheets, the style sheets have a higher priority over the presentation attributes. You can override the inheritance rules by the "!important" declaration.

Look at the CSS chapter of this book or read the CSS recommendation to learn more.
Back on the rack

8. Lets see if we can improve our rack document with what we just learned.

Figure 3-13. Our rack with floor


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="uprightPost" width="10" height="150" /> <g id="column"> <defs> <g id="beam"> <rect x="0" width="3" height="16" /> <rect x="5" width="126" height="8" /> <rect x="133" width="3" height="16" /> </g> </defs> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> <g id="rack" fill="steelblue" stroke="black" > <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" /> <use xlink:href="#column" x="300" y="0" /> <g id="ground"> <rect x="-10" y="150" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="-10" y1="150" x2="470" y2="150" stroke="black" /> </g> </g>

15

Learn SVG

Chapter 3 Document Structure

16

</defs> <use xlink:href="#rack" x="50" y="20" /> </svg>

Weve just omitted every occurrence of fill="steelblue" stroke="black" and given those attributes to the racks group instead. It works great and weve significantly reduced the size of our document. But what if one of your customers wants the middle column moccasin-coloured? An unusual request, but as a simple pallet supplier, ours is not to reason why!

Figure 3-14. Changing color of beams

This is achieved by adding an individual fill element to the particular rack.


<use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" fill="moccasin" /> <use xlink:href="#column" x="300" y="0" />

Obviously no problem there. But wait, this seems to be remarkable. We didnt tell the column group to get moccasin-coloured. We told one instance of the column group to get moccasin-coloured. So how does the <use> element influence the groups styling? Lets have a look, using our basic example.

Figure 3-15. Color in use element


<g fill="green"> <defs> <g id="inner"> <circle cx="50" cy="50" r="20" /> <circle cx="100" cy="50" r="20" fill="red" /> </g> </defs> <rect x="130" y="30" width="40" height="40" /> <use xlink:href="#inner" fill="moccasin" /> </g>

A group seems to be transparent for the styles of its instances, i.e. a group is passing presentation attributes from a referencing <use> element to its contained elements, as long as the group itself does not have that particular presentation attribute defined. In that case the group becomes opaque and blocks the style. Therefore the CSS inheritance rules also apply to group instances.

16

Learn SVG

Chapter 3 Document Structure

17

Lets see how this adds to our rapidly expanding structure knowledge. What do we know now? Group elements inherit the parent groups style. Group elements also inherit the parent groups instance style. If we want all instances of a group to have the same style, we implement the style in the group. If we want the instances of a group to have different styles, we implement the style in the groups instances, rather in the group itself. Symbols SVG provides us with another structuring element, the <symbol> element. It is another container element like its companions <g> and <defs>. In fact it is something in between the two. 1. The <symbol> element contains graphics elements and other container elements. Here it behaves like the <g> element. 2. The <symbol> elements content is never rendered. It must be instanced by an <use> element. With that it is more like the <defs> container element. 3. The <symbol> element always renders in a rectangular area. For this you will supply a referencing <use> element with additional width and height attributes. Syntax Lets look at symbols in their working environment
<symbol id=name viewbox=min-x min-y width height preserveAspectRatio="align [meetOrSlice]" style-attribute=style-attribute > <!-- symbolss content here --> </symbol>

and kick off a brand new example. Working with Symbols Lets have a look at some of the practical implications of using symbols. 1. Start by entering the following markup in your text editor
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <symbol id="icon" viewBox="0 0 100 100" preserveAspectRatio="none" stroke="blue" stroke-width="5" fill="blue"> <circle cx="50" cy="14" r="14" /> <path fill="none" d="M0,0 L50,40 50,60 0,100 M100,0 L50,40 M100,100 L50,60" /> </symbol> <rect x="50" y="50" width="100" height="100" fill="wheat" stroke="black" /> <use xlink:href="#icon" x="50" y="50" width="100" height="100" /> </svg>

This will hopefully give you the rather interesting graphic shown below.

17

Learn SVG

Chapter 3 Document Structure

18

Figure 3-16. A symbol

The symbol consists of a circle the head and a path element the arms, body and legs. We reuse the symbol by the <use> element, that defines a rectangular area 100 units wide and 100 units high. We also provide a true rectangle just to show the borders of this area. The viewBox attribute establishes a new coordinate system, into which the symbols graphic elements are drawn. We will discuss the viewBox attribute in more detail in Chapter 7. Just notice here that the viewBoxs rectangle exactly meets the uses rectangle here initially. 2. Now we want to play a bit with different sizes. So lets enlarge the uses rectangle a bit
<symbol id="icon" viewBox="0 0 100 100" preserveAspectRatio="none" <use xlink:href="#icon" x="50" y="50" width="150" height="100" />

Figure 3-17. Symbol in enlarged rectangle

As we see, the symbols content is scaled non-uniformly so that it fits into the uses rectangle. To change that behaviour, SVG provides us with a lot of other values for the preserveAspectRatio attribute. Lets meet one of them 3. Adjust the lines of markup we just worked with again to read
<symbol id="icon" viewBox="0 0 100 100" preserveAspectRatio="xMidyMid meet" <use xlink:href="#icon" x="50" y="50" width="150" height="100" />

18

Learn SVG

Chapter 3 Document Structure

19

Figure 3-18. "xMidyMid meet" preserveAspectRatio

Any value for the preserveAspectRatio attribute other than "none" will result in a uniform scale of the viewBoxs rectangle. The xMidyMid value instructs the SVG rendering engine to coincide with the midpoints of the viewBoxs and the uses rectangles. The second value meet results in a scaling so that the complete viewBox rectangle fits into the uses rectangle. 4. Now try the following markup
<symbol id="icon" viewBox="0 0 100 100" preserveAspectRatio="xMidyMid slice" <use xlink:href="#icon" x="50" y="50" width="150" height="100" />

Figure 3-19. "xMidyMid slice" preserveAspectRatio

A second value slice causes a scaling so that the viewBox rectangle completely fills out the uses rectangle. I wont cover the numerous variants of the preserveAspectRatio attributes values here. If you are interested, I suggest, that you look into the SVG specification. There you will find a complete explanation of all variants with an example.
All together now

I dont think that there is a great danger of you confusing the symbol element with the group element. Look at the symbol element more as a rectangular image element, where you can directly draw into. After that you are able to map that rectangle onto an other rectangle to make it visible. Personally I do not use the symbol element often. But we will benefit from knowing it, as both the <pattern> element and the <marker> element use the concepts weve just discussed here.

19

Learn SVG

Chapter 3 Document Structure

20

Finally, I recommend that whenever you define a symbol element, to put it into a <defs> section. This results in good SVG coding style as everything that is referenced should go into a <defs> section. Patterns Lets go back to our rack example. Perhaps our theoretical foreman has been complaining about the visual appearance of the upright posts. The real upright posts dont look like simple filled rectangles. They rather have equidistant holes along them. This is for saving material and weight. Hmm, the pattern element might be useful here. The spec reads:
A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted.

So lets try it out and have a quick look at the patterns syntax. Syntax Here is an example of pattern in effect.
<pattern id=name x=coordinate y=coordinate width=length height=length patternUnits=userSpaceOnUse style-attribute=style-attribute > <!-- patterns content here --> </pattern>

With the <pattern> element we have yet another container element. It is quite helpful to think of patterns as rectangular tiles. To help illustrate this, have a look at the next example.

Figure 3-20. Two rectangles filled with pattern


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="holes" x="0" y="0" width="50" height="50" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="50" height="50" stroke="black" fill="lightgray" /> <circle cx="25" cy="25" r="20" fill="blue" /> </pattern> </defs> <rect x="50" y="50" width="200" height="150" fill="url(#holes)" stroke="black" /> <rect x="275" y="50" width="200" height="150" fill="url(#holes)" stroke="black" /> </svg>

20

Learn SVG

Chapter 3 Document Structure

21

One pattern tile consists of a lightgray square with a size of 50 units and a centred blue circle. When we fill the 200 units wide and 150 units high rectangles with these pattern tiles, we are a bit surprised to achieve the above image. This behaviour is due to the fact, that the first tile starts in the origin of the documents coordinate system, which is in the upper left corner of SVG canvas. This results in seemingly fixed pattern tiles, that only shine through those shapes, that are using the tiles for filling. Just to test this, we move the rectangles a little to the right.

Figure 3-21. Moving Rectangles


<rect x="75" y="50" width="200" height="150" fill="url(#holes)" stroke="black" /> <rect x="300" y="50" width="200" height="150" fill="url(#holes)" stroke="black" />

As this is what we expected here, it is not always what we want. To have the coordinate systems used by the pattern fixed with object to fill, we can use the fact, that every group establish an own coordinate system. We will discuss this more detailed in Chapter 7. So all we have to do now, is to enclose one rectangle in a group and reuse that group twice.

Figure 3-22. "userSpaceOnUse"

for patternUnits

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="holes" width="50" height="50" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="50" height="50" stroke="black" fill="lightgray" /> <circle cx="25" cy="25" r="20" fill="blue" /> </pattern> <g id="rect"> <rect width="200" height="150" fill="url(#holes)" stroke="black" /> </g> </defs> <use xlink:href="#rect" x="50" y="50" /> <use xlink:href="#rect" x="275" y="50" />

21

Learn SVG
</svg>

Chapter 3 Document Structure

22

The patterns origin can then be moved by the values of the x- and y- attribute.
<pattern id="holes" width="50" height="50" patternUnits="userSpaceOnUse">

Now, that we know how patterns work, it should be easy, to add the holes in your upright posts.

Figure 3-23. Rack with holes on beams


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="holes" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" stroke="none" fill="steelblue" /> <circle cx="5" cy="5" r="2" fill="lightgray" /> </pattern> <g id="uprightPost"> <rect width="10" height="150" fill="url(#holes)" stroke="black" /> </g> <g id="column"> <defs> <g id="beam"> <rect x="0" width="3" height="16" /> <rect x="5" width="126" height="8" /> <rect x="133" width="3" height="16" /> </g> </defs> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> <g id="rack" fill="steelblue" stroke="black" > <g id="ground"> <rect x="-10" y="150" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="-10" y1="150" x2="470" y2="150" stroke="black" /> </g> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" /> <use xlink:href="#column" x="300" y="0" /> </g> </defs> <use xlink:href="#rack" x="50" y="20" /> </svg>

Markers Very delighted about the new look of the upright posts you say: And if we finally could add dimensions to the racks, SVG would be appropriate for our new brochure.

22

Learn SVG

Chapter 3 Document Structure

23

Ok, so lets look at markers. The SVG specification states:


A marker is a symbol which is attached to one or more vertices of path, line, polyline and polygon elements.

Sounds good. Here is the syntax for <marker> element. Syntax


<marker id=name refX=coordinate refY=coordinate markerWidth=length markerHeight=length markerUnits=strokeWidth | userSpaceOnUse viewBox=min-x min-y width height orient=auto | angle style-attribute=style-attribute > <!-- patterns content here --> </marker>

The <marker> element like its companion the pattern is a container element. Since we want to attach arrowheads to a line, we design the arrow offline first. For this we use a path element.

<path d="M0,0 L20,-4 20,4 z M0,-10 L0,10" stroke="black" />

In order to integrate this path in our new marker, we should illustrate some coordinates and lengths first.

Figure 3-24. Detailled arrow marker


<marker id="arrow" viewBox="0 -10 20 20" markerUnits="userSpaceOnUse" markerWidth="20" markerHeight="20" orient="auto"> <path d="M0,0 L20,-4 20,4 z M0,-10 L0,10" stroke="black" /> </marker>

As usual with SVG there are several ways to make things work. I will show you my preferred method here. Starting to make a marker, we first create a little sketch of it. We mark the origin of our locale marker coordinate system with (0,0). This is also the markers point, that will be placed onto the lines start- , mid- or endpoint. Then you designate the dimensions of the markers bounding box. Given these, you can then determine the coordinates of the bounding boxs upper left corner with respect to the markers coordinate system.

23

Learn SVG

Chapter 3 Document Structure

24

1. Fill the viewBox attribute with the coordinates of the bounding boxs upper left corner, its width and its height in exactly that order. 2. Give the markerWidth attribute the value of your bounding boxs width. 3. Give the markerHeight attribute the value of your bounding boxs height. 4. Create the <marker>s contained elements using coordinates with respect to the markers locale coordinate systems origin. Ok? Now that we know, how to create little markers, we should also be able to put them onto a path, line, polyline, etc.. To support markers, all those elements support the marker-start, marker-mid, and marker-end attributes. With the help of these attributes we can assign separate marker symbols to the start-point, the end-point and all mid-points. So lets now complete our dimension line with what we know.

Figure 3-25. Line with arrows at each side


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <marker id="startArrow" viewBox="0 -10 20 20" markerUnits="userSpaceOnUse" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M0,0 L20,-4 20,4 z M0,-10 L0,10" stroke="black" /> </marker> <marker id="endArrow" viewBox="-20 -10 20 20" markerUnits="strokeWidth" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M-20,-4 L0,0 -20,4 z M0,-10 L0,10" stroke="black" /> </marker> </defs> <line x1="50" y1="150" x2="500" y2="50" stroke="black" marker-start="url(#startArrow)" marker-end="url(#endArrow)" /> </svg>

Since the start- and end-arrow must have different directions, we had to define two different markers "startArrow" and "endArrow". Thanks to the orient="auto" attribute value the markers will align themselves to the lines direction. With this we can finally dimension the rack.

24

Learn SVG

Chapter 3 Document Structure

25

Figure 3-26. Rack and dimensions


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <svg> <defs> <marker id="startArrow" viewBox="0 -10 20 20" markerUnits="userSpaceOnUse" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M0,0 L20,-4 20,4 z M0,-10 L0,10" stroke="black" /> </marker> <marker id="endArrow" viewBox="-20 -10 20 20" markerUnits="strokeWidth" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M-20,-4 L0,0 -20,4 z M0,-10 L0,10" stroke="black" /> </marker> <!-- previous <defs> content goes here --> </defs> <use xlink:href="#rack" x="50" y="20" /> <g id="dimensions"> <line x1="50" y1="210" x2="512" y2="210" stroke="black" marker-start="url(#startArrow)" marker-end="url(#endArrow)" /> <text x="281" y="205" text-anchor="middle">462</text> <line x1="540" y1="20" x2="540" y2="170" stroke="black" marker-start="url(#startArrow)" marker-end="url(#endArrow)" /> <text x="545" y="95">150</text> </g> </svg>

In the case, where you want your markers to grow and shrink with the stroke-width of the line, you might use markerUnits="strokeWidth" instead. Visibility of Groups You may not always want to have all elements of an SVG document visible at every time. To change the visibility control of certain elements you have to make some changes to your document structure. The best way is to build so called layers. These layers contain elements that belong together logically. For this task the <group> element is the ideal instrument. The first step will be , to collect all elements that should become visible/invisible in one group. SVG or exactly CSS2 provides us with two presentation attributes display and visibility to control the visibility of elements. I recommend, to use the visibility attribute with a group, when you want to control the visibility of the contained elements.. With that we can override the visibility attribute for particular group members.

25

Learn SVG

Chapter 3 Document Structure

26

Read the Chapter 11.5 of the SVG recommendation, if you want to learn more about the differences between the display and visibility attributes. Now assume, we want to control the visibility of the racks dimensions. For this we have to 1. Add the visibility attribute to the group. 2. Ensure that no element in the dimensions group has its visibility attribute explicitly set.

Figure 3-27. Hide/show rack dimensions


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <marker id="startArrow" viewBox="0 -10 20 20" markerUnits="userSpaceOnUse" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M0,0 L20,-4 20,4 z M0,-10 L0,10" stroke="black" /> </marker> <marker id="endArrow" viewBox="-20 -10 20 20" markerUnits="strokeWidth" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> <path d="M-20,-4 L0,0 -20,4 z M0,-10 L0,10" stroke="black" /> </marker> <pattern id="holes" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" stroke="none" fill="steelblue" /> <circle cx="5" cy="5" r="2" fill="lightgray" /> </pattern> <g id="uprightPost"> <rect width="10" height="150" fill="url(#holes)" stroke="black" /> </g> <g id="column"> <defs> <g id="beam"> <rect x="0" width="3" height="16" /> <rect x="5" width="126" height="8" /> <rect x="133" width="3" height="16" /> </g> </defs> <use xlink:href="#beam" x="12" y="0" /> <use xlink:href="#beam" x="12" y="50" /> <use xlink:href="#beam" x="12" y="100" /> <use xlink:href="#uprightPost" x="150" y="0" /> </g> <g id="rack" fill="steelblue" stroke="black" > <g id="ground"> <rect x="-10" y="150" width="480" height="10" stroke="none" fill="lightgray" /> <line x1="-10" y1="150" x2="470" y2="150" stroke="black" /> </g> <use xlink:href="#uprightPost" x="0" y="0" /> <use xlink:href="#column" x="0" y="0" /> <use xlink:href="#column" x="150" y="0" />

26

Learn SVG

Chapter 3 Document Structure

27

<use xlink:href="#column" x="300" y="0" /> </g> </defs> <use xlink:href="#rack" x="50" y="20" /> <g id="dimensions" visibility="visible"> <line x1="50" y1="210" x2="512" y2="210" stroke="black" marker-start="url(#startArrow)" marker-end="url(#endArrow)" /> <text x="281" y="205" text-anchor="middle">462</text> <line x1="540" y1="20" x2="540" y2="170" stroke="black" marker-start="url(#startArrow)" marker-end="url(#endArrow)" /> <text x="545" y="95">150</text> </g> </svg>

With this complete rack document you now dont only have SVG based images for your print brochure, you also can extend it easily to a dynamic document for your e-commerce projects. The visitor of your rack product sites can magically make the dimensions appear with a simple button press. How we can accomplish this kind of interactivity, we will explore in more detail in the scripting chapter of this book.

27

Chapter 4 : Curves
When you are surfing the Web, it is not unlikely that you will come across some interesting SVG graphics. Since you find them interesting you will as you can always do with a web page inspect the graphics source code. Doing this, there will be a high probability, that you will find an SVG document dominated by <path> elements. This indicates most often, that the graphics was generated by a program, as opposed to hand-coded SVG. As with HTML pages, it is the normal way to use authoring software to create vector graphics. SVG content will also be quite often generated by serverside scripts or translated from semantically higherlevel XML documents via XSLT. SVG renderers know of the importance of <path> elements and will usually optimize the processing performance of paths. Given this, SVG export by programs will often rely on that perfomance advantage of paths and prefer those over basic shapes. Since we want to be able to do modifications or finetune these content by hand or simply want to understand it, we therefore need some insights into the <path> elements internals. That is what we want to explore in this chapter. So whats so special with paths? 1. The <path> element has a very compact data format. This is advantageous, since vector drawings can get very big in size and nevertheless should result in minimal download time. 2. The <path> element is a very general element. It allows us to draw lines, circles, rectangles, polylines and polygons as we discussed them in Chapter 2. You might ask, why not always use paths instead of the basic shapes. Well 3. The <path> element is very powerful but also quite complex. It is generally easier and more intuitive for us to use basic shapes where appropriate. On the other hand we can create Bezier curves with the path element or use subpaths to add holes to filled shapes. We cannot do this with basic shapes. I recommend to stick with basic shapes, as long as document size doesnt matter and as long as you find an equivalent basic element at all. For all other cases we get forearmed now by a closer look at how paths work.

Path concept
A path is described using the concept of a current point. In an analogy with drawing on paper, the current point can be thought of as the location of the pen.

This is, what the SVG specification tells us about the path concept. So we are not surprised, that SVG provides us with a command like syntax for path data, which reminds us somewhat of pen plotter software functions and the PostScript language. Yes, we really need to learn a special path syntax, because the wise W3C decided to put all information about the path geometry into a single attribute. As I told you, they did that in order to allow for minimal file size and efficient downloads. On the other side comes a drawback with this benefit. SVG parsers need not only to parse XML content, they also have to parse this special complex path data attribute via some kind of microparser. However, here is the <path> element syntax at first.

Learn SVG

Chapter 4 Curves

Syntax:
<path id=name d=path-data pathLength=length marker=uri marker-start=uri marker-mid=uri marker-end=uri transform=transformation fill-rule=nonzero | evenodd | inherit style-attribute=style-value />

The most important attribute is the d=path-data attribute. With this we can define the outline of the shape or curve. The pathLength attribute doesnt change the real length of the path. It merely helps us, to normalize the paths length to a value, with which we can process points on the path much simpler. With the help of that you can say: Whatever the exact length of the path is, I assume it has the length 100. And now I want to do something at the path locations 0, 25, 50, 75 and 100. This is a comfortable way of curve parameterization. The pathLength attribute is mainly used with placing text on a path and animation along a path.

Drawing a Path using Lines


Now we need to know how to define the paths outline. For this we have a closer look at the path data contained in the d (data) attributes value. 1) The path data consists of a serial of instructions or commands. 2) A command begins with a single uppercase or lowercase letter the command letter, followed by a certain number of numerical values the command parameters. 3) Command letters and parameters are separated by white space characters (space, tab, newline) and/or commas. 4) Every command relies on the current point, which represents the current position of an imaginary pen and contains the instruction to what new point and along what curve segment the pen shall be moved. 5) The pen can be moved with drawing a new path segment (pen down) or without drawing (pen up). The W3C SVG work groups motivation to use such an for human eyes odd - syntax was: Ease of processing by software. Minimal file size. Here is the syntax of the most frequently used path commands.

Syntax: moveto
M|m x, y x = x-coordinate of new point y = y-coordinate of new point

Syntax: lineto
L|l x, y x = x-coordinate of new point

Learn SVG

Chapter 4 Curves
y = y-coordinate of new point

Syntax: closepath
Z|z

So let us look now at an example. Figure 4-1 shows an U with a triangular roof above it. This should be drawn by a single path.

Figure 4-1. Path consisting of 6 lines Here is the corresponding <path> element.
<path stroke="blue" stroke-width="3" fill="none" d="M 40,40 L 40,80 L 100,80 L 100,40 M 40,30 L 70,10 L 100,30 Z" />

We want to illuminate the used path commands more closely.

Command M 40,40 L 40,80 L 100,80 L 100,40 M 40,30 L 70,10 L 100,30 Z

Instruction Move the pen to (40,40) and start a new sub-path Draw a line segment from the current point (40,40) vertically down to the new point(40,80) Draw a line segment from the current point(40,80) horizontally to the new point(100,80) Draw a line segment from the current point(100,80) vertically up to the new point(100,40) Move the pen to (40,30) and start a new sub-path Draw a line segment from the current point(40,30) to the new point(70,10) Draw a line segment from the current point(70,10) to the new point(100,30) Close the sub-path with a line segment from the current point(100,30) to the start point(40,30)

Table 4-1. Path Data Instructions and Commands

Learn SVG

Chapter 4 Curves

We created the path solely with those three path commands that we have learned so far: moveto, lineto and closepath. Please note the following striking things with the path in the example above: 1) Every path must start with a moveto command. 2) We used uppercase letters exclusively with the example above. That means we were using absolute coordinates, i.e coordinates with respect to the paths element coordinate system. We will introduce relative coordinates (lowercase letters) later. 3) We separated x- and y-coordinates by a comma and used the blank as delimiter elsewhere. This is only a convention used in this book and will be discussed more deeply later. We wrote the example in Figure 4-1 using a format with one line per path command. But we did this for better readability only. So we may write the path data attribute in one single line, even more I recommend this to you, since it is the usual way of coding. <path stroke="blue" stroke-width="3" fill="none" d="M 40,40 L 40,80 L 100,80 L 100,40 M 40,30 L 70,10 L 100,30 Z" /> Please remind that the path data concept was designed with minimal file size and efficient downloads in mind. So we should not be surprised, that the wise W3C provided another set of lineto commands for frequently used special classes of lines the horizontal and vertical lines.

Syntax: horizontal lineto


H|h x = x-coordinate of new point

Syntax: vertical lineto


V|v y = y-coordinate of new point

With the horizontal lineto command the y-coordinate of the new point need not be specified it is simply reused from the current point. Likewise we dont need to specify the x-coordinate with the vertical lineto command. Given this we can rewrite our example from Figure 4-1 and yield a significant more compact path data.
<path stroke="blue" stroke-width="3" fill="none" d="M 40,40 V 80 H 100 V 40 M 40,30 L 70,10 L 100,30 Z" />

Now that we know a lot about the <path> element, we are quite keen to do something useful with it. Fine, so lets design a car. As lines are the only segment types we know so far we will base our first car design on lines then.

Learn SVG

Chapter 4 Curves

Figure 4-2. Linear Car Since we want to evolve our car into some more challenging designs, we need its complete code here.
<?xml version="1.0" ?> <svg width="600" height="400" viewBox="0 0 300 200"> <defs> <circle id="crvpnt" r="2" stroke="black" fill="lightgray" /> <circle id="wheel" r="10" stroke="black" stroke-width="5" fill="lightgray" /> </defs> <path fill="silver" stroke="black" stroke-width="2" d="M 50,100 L 55,75 L 90,70 L 95,50 L 160,50 L 170,100 Z" /> <use xlink:href="#crvpnt" x="50" y="100" /> <use xlink:href="#crvpnt" x="55" y="75" /> <use xlink:href="#crvpnt" x="90" y="70" /> <use xlink:href="#crvpnt" x="95" y="50" /> <use xlink:href="#crvpnt" x="160" y="50" /> <use xlink:href="#crvpnt" x="170" y="100" /> <use xlink:href="#wheel" x="80" y="100" /> <use xlink:href="#wheel" x="145" y="100" /> <text x="20" y="140" font-size="7"> d="M 50,100 L 55,75 L 90,70 L 95,50 L 160,50 L 170,100 Z" </text> </svg>

Drawing Arcs
You might be wondering, why an elliptical and/or circular arc is no basic SVG element. Indeed this was a heavily discussed topic in the SVG community. And to make it short: The SVG WG signalized, there is a good chance, that we will have something like an <arc> element with the next version. Meanwhile we must help ourself with the mighty but complex <path> element. For this we introduce here the absolute elliptical arc A and the relative elliptical arc a command.

Syntax: elliptical arc


A|a rx, ry, phi, fA, fS, x, y rx = x-axis radius .. positive number ry = y-axis radius .. positive number

Learn SVG

Chapter 4 Curves
x-axis-rotation = angle fA = large-arc-flag .. 0, 1 fS = sweep-flag .. 0, 1 x = x-coordinate of new point y = y-coordinate of new point

Figure 4-3. Elliptical Arc Path Segment Figure 4-3 illustrates the arc segments data. The arc is part of an ellipse that starts in the current point and ends in the new point with the coordinates x and y, which are the arc segments last two values. Now we position a coordinate axis into the center point of the ellipse so, that the x-axis and the y-axis are pointing towards the biggest and the smallest (semi-major and semi-minor) radius. With this we have exactly the first two arc segment values rx and ry. Since there is no restriction, which of these two values is greater than the other, we call these values x-radius and y-radius instead of semi-major and semi-minor axis radius. The arc segments third value x-axis-rotation specifies the angle in degrees between the paths reference coordinate systems x-axis and the ellipses locale coordinate system. The effect, when setting this value to a non-zero value is identically with a rotate- and translatetransformation so, that the ellipse passes through the current point and new point again (Figure 4-4).

Figure 4-4. Rotated Elliptical Arc Path Segment There are cases, where the ellipses measurements specified by rx and ry are too small to fit between the path points. Then the radii are scaled up so, that the ellipse will fit and the ratio

Learn SVG

Chapter 4 Curves

of rx and ry remains constant. Figure 4-4 shows an ellipse, that fits with a x-axis-rotation of zero but doesnt fit any more with a non-zero angle.

Figure 4-5. Rotated and Auto-scaled Elliptical Arc Path Segment

The ellipses in Figure 4-3 to 4-5 were drawn all with a solid and a dotted segment. What, if we want to choose the dotted arc as our path segment. For this SVG provides us with the fourth segment value large-arc-flag and the fifth value sweep-flag. In fact we can draw not only one ellipse with predefined semi-major and semi-minor radii through two given points, we rather have two of them, provided that the radii are large enough. Figure 4-6 is showing these.

Figure 4-6. Four possible elliptical arcs With this we now have the choice of four elliptical arc segments. Two small ones and two large ones, two with positive angular orientation (clockwise) and two with negative orientation. And with that we also know now, what the large-arc-flag means (fl = 0 : small, fl = 1 : large). The sweep-flag controls the angular orientation analogically via fs = 0 : positive and fs = 1 : negative. I want to mention also, that for the special case with the end point coordinates (x,y) equal to the current points coordinates the arc will not get rendered. Since this behaviour is not much intuitive with the large-arc-flag set to 1, this might be changed with SVG 2.0. Lets practice what we learned about the elliptical arc and create a simple spiral.

Learn SVG

Chapter 4 Curves

Figure 4-7. Spiral composed from elliptical arcs


<svg width="600" height="400" viewBox="0 0 400 300"> <path stroke="darkslategray" stroke-width="6" fill="none" stroke-linecap="round" d="M50,100 A100,50 0 0 1 250,100 A80,40 0 0 1 90,100 A60,30 0 0 1 210,100 A40,20 0 0 1 130,100 A20,10 0 0 1 170,100" /> </svg>

Now we have to manufacture a car prototype with the help of these nice arcs.

Figure 4-8. Elliptical Car You will rarely use the elliptical arc with SVG handcoding. For this we usually have the support of high sophisticated graphical authoring tools. But there is a very important special case of the elliptical arc that is of high practical use. Lets now have a closer look at the circular arc.

Circular Arc
A circular arc is simply a special case of the elliptical arc. Since circular arcs are quite frequently used in technical drawings, I want to show you a comfortable way to hand-code these arcs using the path element

Learn SVG

Chapter 4 Curves

Figure 4-9. Four possible circular arcs

Syntax:
A|a r, r, 0, fA, fS, x, y r = radius .. positive number r = radius .. positive number 0 = x-axis-rotation angle .. always 0 fA = large-arc-flag .. 0, 1 fS = sweep-flag .. 0, 1 x = x-coordinate of end point y = y-coordinate of end point

Needless to say that you dont have two radii with the circular arc. So the first two values of arc command are always identical the arcs radius. Also you do not need to rotate a circle as you might want to do with the ellipse. Consequently we can always set the third value to zero. As with the elliptical arc we also have four possible circular arcs shown in Figure 4-9.

Figure 4-10. Circular Arc using Center Parameterization Consistent to its current point policy for defining paths, SVG is using the so called endpoint parameterization for describing arcs. That simply means that a circular arc as well as its elliptical brother is defined by its endpoints plus some more additional values. For single arcs this technique is not very convenient. Using the center parameterization here is often more intuitive. Consider a fictitious element

Learn SVG

Chapter 4 Curves

10

<circularArc cx=x0 cy=y0 r=radius start=angle sweep=angle />

describing a circular arc by its center point, radius, start- and sweep-angle as in figure 4-x. As we much likely will have an arc element in SVG 2.0 we should be not surprised, if it were similar to our <circularArc> element. What we need now is a simple way to emulate the circular arc via the <path> element, i.e. to use the <circularArc>s attributes without intensive conversion calculations with the path element. Here is one possible solution:
<!-- single arc --> <path transform=translate(x0,y0) rotate(start-angle) scale(radius) d=M 1,0 A 1,1 0 fA fS cos(sweep-angle) sin(sweep-angle) stroke-width=width/radius />

As it is not possible to find a way completely without any calculations, yet we have one with only minimal math. These are the conversion steps: 1. use the center coordinates as the arguments of the paths translate transform. 2. the start-angle in degrees goes into the rotate transform. 3. the radius is reused as the scale transforms value. 4. the large-arc-flag fA is 0 if the sweep-angle is in the interval 180 < sweep-angle < 180, otherwise 1. 5. the sweep-flag fS is 0 if the sweep-angle is positive, otherwise 1. 6. the last two values are calculated by the cosine and sine of the sweep-angle in that order. 7. Since the stroke-width is influenced by the scale transform, we have to compensate this effect by dividing the stroke-width value by radius. We can not only create single arcs with this trick, but also arc sections and pies.
<!-- arc section --> <path transform=translate(x0,y0) rotate(start-angle) scale(radius) d=M 1,0 A 1,1 0 fA fS cos(sweep-angle) sin(sweep-angle) Z stroke-width=width/radius /> <!-- pie section --> <path transform=translate(x0,y0) rotate(start-angle) scale(radius) d=M 0,0 L 1,0 A 1,1 0 fA fS cos(sweep-angle) sin(sweep-angle) Z stroke-width=width/radius />

Here is an example:

Learn SVG

Chapter 4 Curves Figure 4-11. Circular Arcs

11

<svg> <path transform="translate(50,50) rotate(-15) scale(40)" d="M1,0 A1,1 0 0 0 0,-1" stroke-width="0.08" stroke="blue" fill="none" stroke-linecap="round" /> <path transform="translate(50,100) rotate(-30) scale(40)" d="M1,0 A1,1 0 1 1 -0.707 -0.707" stroke-width="0.08" stroke="red" fill="none" stroke-linecap="round" /> <path transform="translate(150,50) rotate(-45) scale(40)" d="M1,0 A1,1 0 0 0 0,-1 Z" stroke="blue" stroke-width="0.08" fill="silver" fill-opacity="0.5" /> <path transform="translate(150,100) rotate(-22.5) scale(40)" d="M1,0 A1,1 0 1 1 -0.707 -0.707 Z" stroke="red" stroke-width="0.08" fill="silver" fill-opacity="0.5" /> <path transform="translate(250,50) rotate(-60) scale(40)" d="M0,0 L1,0 A1,1 0 0 0 0,-1 Z" stroke="blue" stroke-width="0.08" fill="silver" fill-opacity="0.5" /> <path transform="translate(250,100) rotate(-15) scale(40)" d="M0,0 L1,0 A1,1 0 1 1 -0.707 -0.707 Z" stroke="red" stroke-width="0.08" fill="silver" fill-opacity="0.5" /> </svg>

I dont want to finish this chapter about circular arcs without having designed a car from those also.

Figure 4-12. Circular Car

Splines
The term spline comes from drafting, where a spline is a flexible strip guided by points on a paper, used to draw a smooth curve through those points. Today we associate this term with a convenient mathematical method for drawing curves or surfaces in two or three dimensional space.

Approximating vs. Interpolating Splines

Learn SVG

Chapter 4 Curves

12

Any spline is based upon a set of control points. The lines connecting these control points in order are called the control polygon (characteristic polygon) or control graph. The various methods of spline drawing can be divided into interpolating splines, where the curve is forced to pass through all control points, and approximating splines, where the curve not necessarily needs to do so. The SVG work group decided for version 1.0 to confine to a special but very common type of approximating splines the Bzier splines. But we can expect to get general splines with SVG language version 2.0.

Bzier Splines
The mechanical engineer Pierre Bzier was working for the Renault car company. By 1960 he had to solve the problem of describing a best fit curve that would be easy to use and exact enough to meet the tolerance demands of manufacturing the car body. He accomplished this with the help of cubic polynomials. Bzier curves, in their two-dimensional form, are now the basis of almost all common graphics programs (such as Adobe Illustrator and Corel Draw), following their adoption as the standard curve of the PostScript language. Most outline fonts, including TrueType are stored as Bzier curves. In order to create a Bzier spline we need at least 3 points. To be exact, it is also possible to create a spline from two points but this is merely a simple line. Theoretically splines can be defined for an arbitrary number of control points. In the field of interactive computer graphics quadratic Bzier splines (three control points) and cubic Bzier splines (four control points) interspersed with the time. Since curves usually have more than three points, these curves are then composed by sequential quadratic or cubic Bzier spline patches or segments. We will use the term polybzier for a curve with sequential Bzier spline segments. This concept of a polybezier comes with the high desirable benefit, that a change of any control point in one spline segment does not influence the other segments curves.

Quadratic Bzier Spline

Figure 4-13. Quadratic Bzier Spline Segment To better understand the concept of the quadratic Bzier spline segment, we start with a simple line from point P1 to P2 and add a third point C12 not on this line forming a triangle. The Bzier curve passes through the control points P1 and P2, but will only approximate the control point C12. Here the imagination is of some help, that C12 acts with a certain

Learn SVG

Chapter 4 Curves

13

gravitational force onto the originally straight line and deforms it elastically into a smooth curve. I want to show you an illustrative geometric approach to create a quadratic Bzier spline segment. We start again with the triangle P1,C12,P2.

Figure 4-14. Quadratic Bzier Spline Creation We mark a point A1 at 30% along the line from P1 to C12. Then we find another point A2 at 30% along the line from C12 to P2. Connecting these points with a new line we set again a point B at 30% along this line from A1 to A2. This point B is now a point on our quadratic Bzier spline segment. If we repeat this geometric construction from 0% to 100% using steps with a width of 10%, we yield an image according the second triangle. All the new lines are tangents to the curve we call them the convex hull - and all new points B are points on our spline, a simple parabola. Here are its characteristics: When starting in P1 the curve is heading straight for C12. When arriving in P2 it is coming from the direction of C12. The whole curve is contained inside the triangle P1,C12,P2. If the points P1,C12,P2 are collinear (placed on a line), the resulting curve is also a line. The curve cannot intersect itself. Now that we understood, how the quadratic Bzier spline works, we still need to know, how SVG is helping us to create it via the <path> element. For this we introduce here the absolute and relative quadratic Bzier curveto Q and q command.

Syntax:
Q|q x1, y1, x, y x1 = x-coordinate of the approximating control point y1 = x-coordinate of the approximating control point x = x-coordinate of new curve point y = y-coordinate of new curve point

The Q command specifier is followed by two pairs of x-/y-coordinates. The first one determines the control point and the second one is the end point of the Bzier segment. Lets apply this path command to generate a smooth curved vase.

Learn SVG

Chapter 4 Curves

14

Figure 4-15. Vase using quadratic Bzier Segments


<path stroke="sienna" stroke-width="2" fill="none" d="M 80,180 Q 50,120 80,60 Q 90, 40 80,20 Q 100, 20 120,20 Q 110, 40 120,60 Q 150,120 120,180 Z" />

We start the outline of the vase at its lower left corner (80,180) with an absolute moveto M command. Then we add a quadratic bzier curveto Q segment with the control point (50,120) ending in (80,60). From here we continue with another Q command approximating the control point in (90,40) to the point (80,20). Please note, that we wanted to preserve the smoothness of the curve, when going over from the first spline segment (body?) to the second one (neck?). To accomplish this we need to have the tangent at the first splines endpoint equal to the second splines startpoint. And for this a curve points preceding control point, the curve point itself and the succeeding control point must be on the same line (collinear) with the curve point between the control points.

Learn SVG

Chapter 4 Curves

15

Figure 4-16. Tangents with equal, opposite and different direction Since a smooth junction between two spline segments is a very common demand, SVG provides us with a special simplifying smooth quadratic bzier curveto T command.

Syntax:
T|t x, y x = x-coordinate of new curve point y = y-coordinate of new curve point

Figure 4-17. Automatically generated control points The T command specifier is simply followed by a pair of x/y-coordinates setting the end point of the Bzier segment. The ommitted control point is automatically created from the previous control point by reflection relative to the paths current point.

Learn SVG

Chapter 4 Curves

16

Lets now apply the quadratic Bzier spline to our car.

Figure 4-18. Quadratic Car

Cubic Bzier Spline

Figure 4-19. Cubic Bzier Spline Segment The cubic Bzier spline segment comes with one additional control point compared to its little quadratic sister. With this extra burden we have to specify one more point even if we use a graphics editor comes the benefit of a more versatile curve. The Bzier curve starts in point P1 heading straight for C1. But it is only approximating C1 with a direction towards C2 and after having approximated C2 it is finally arriving in P2 coming from the direction of C2. Here again the imagination helps, that C1 and C2 are acting with a certain gravitational force onto the originally straight line P1,P2 deforming it into a smooth curve. Analogical to the quadratic Bzier spline we want to have an illustrative geometric approach to create a cubic Bzier spline. Here we start now with a quadrangle P1,C1,C2,P2.

Learn SVG

Chapter 4 Curves

17

Figure 4-20. Cubic Bzier Spline Creation We start again marking a point A1 at 30% along the line P1,C1. We repeat this for the lines C1,C2 and C2,P2 and yield the new points A12 and A2. We draw now two new lines A1,A12 and A12,A2. We set again a point at 30% along each of these lines resulting in another two points D1 and D2. Performing the same procedure for these points, i.e. connecting them and creating a new point at 30% along this last line we finally yield the Bzier spline point B. The second quadrangle in Figure 4-20 only contains the points constructed at 10%,20%,,90% according to the above steps and the appropriate last lines, which are tangents to the curve. The cubic Bzier spline segment is finally outlined in the third quadrangle and has some interesting characteristics: When starting in P1 the curve is heading straight for C1. When arriving in P2 it is coming from the direction of C2. The whole curve is contained inside the P1,C1,C2,P2 quadrangle (convex hull). If the points P1,C1,C2,P2 are collinear, the resulting curve is also a line. The curve can intersect itself. The curve can change its sign of curvature.

Hmm, the last point seems to need some more explanation. So what does it mean that the spline can change the sign of curvature? Lets look at the letter C, it is either drawn clockwise or counterclockwise. According to this we can say: Its curvature is either positive or negative. This is how the quadratic Bzier spline behaves. In contrast to that the letter S has one part of it drawn clockwise and the other drawn counterclockwise we say: the curvature changed its sign from positive to negative or otherwise. That is one of the competitive strength of the cubic spline over her quadratic sister. Since the behaviour of the cubic Bzier spline segment is quite clear to us now, lets look at the cubic Bzier curveto command C.

Syntax:
C|c x1, y1, x2, y2, x, y x1 = x-coordinate of the first approximating control point y1 = x-coordinate of the first approximating control point x2 = x-coordinate of the second approximating control point y2 = x-coordinate of the second approximating control point x = x-coordinate of new curve point y = y-coordinate of new curve point

Learn SVG

Chapter 4 Curves

18

The C command is followed by three pairs of x-/y-coordinates. The first and second pair specify the control points C1 and C2 (Figure 4-20) and the last pair are the coordinates of the segments end point P1. The start point P1 is as always the current point.

Figure 4-21. Different Cubic Bzier Spline Segments Figure 4-21 shows different combinations of control points. Please note, if the control points are symmetric to any axis then so is the curve itself. We can also coincide control points to achieve special effects. The cubic spline segment can be closed, intersect itself or degenerate to a line. The next step is to concatenate several segments for a polybezier curve.

Learn SVG

Chapter 4 Curves

19

Figure 4-22. Cubic Polybzier Splines Analogical to the quadratic Bzier T command we are allowed to omit the first control point with the cubic Bzier S command. Here too the ommitted control point is automatically created from the last control point of the previous cubic Bzier segment by reflection relative to the paths current point. The previous command specifier must be C or S to work smoothly. Here is the shamrock of Figure 4-23 as an example.

Figure 4-23. Usage of cubic Bzier shorthand command


<svg> <path stroke="green" stroke-width="2" fill="none" d="M100,100 C100, 10 190,100 100,100 S 100,190 100,100 S 10,100 100,100 S 100,190 100,100 Z" /> </svg>

Learn SVG

Chapter 4 Curves

20

Lets finally apply the cubic Bzier spline to our car.

Figure 4-24. Cubic Car

Relative Path Commands


Now that you are introduced to all types of path segments, you may also have noticed that every upper case path command letter, say A, in addition has a lower case pendant a. Upto here we only used upper case commands for consistency. The notational difference is quite important and designates the location of the reference coordinate system within which we define path point coordinates. Upper case command letters use absolute coordinates with respect to the path elements coordinate system. Lower case command letters use a relative coordinate system with its origin always located in the paths current point and the same orientation as the elements coordinate system.

Figure 4-25. Relative Path Commands We will refer to these commands with absolute and relative commands respectively. The path in Figure 4-25 is defined twice. On the left we used absolute commands, on the right we descibed the same contour using relative commands this time.

Learn SVG

Chapter 4 Curves

21

All coordinates on the left are defined with respect to the origin of the elements coordinate system on the grids upper left corner. This is what we are used to by now. The segments of the right path are solely described with lower case command letters, i.e via relative commands. We start here with a relative moveto m. Since the paths current point isnt explicitly set by a previous segment, it initially coincides with the element coordinate systems origin (0,0), located here in the middle of the grids upper edge. With this starting situation there is in fact no difference to the absolute moveto command M. But hereafter we have moved the current point to (40,80) and simultanously established here a temporary coordinate system for the subsequent command. With respect to this coordinate system we then move the current point by a relative lineto command to the point (0,-20). Again we also moved the temporary path coordinate system vertically to this point (40,60) absolute. In Figure 4-x we can see all subsequent locations of the current path coordinate system always coinciding with the current point. There are some important and remarkable things to notice with relative commands: 1. Relative Commands affect solely point coordinates. 2. Angles, radii and flags are the same with absolute and relative commands. 3. Control points used by the quadratic and cubic curveto commands dont move the paths current point and equally the temporary coordinate system. So the control points as well as the end point of a curveto command must be defined with respect to the same coordinate systems origin located in the current point (see example in Figure 4-x). 4. There is no observable difference between the relative and absolute closepath command z and Z, since it has no point coordinates. Obviously both exist just for consistency reason. 5. Relative commands usually result in more compact path data than absolute commands.
Be watchful, if you use the relative lineto command. The lowercase L can be easily mistaken for the number 1. The SVG WG may provide aliases for path command identifiers that are potentially confusing in the next SVG version.

Path Shortcuts
Now that we are quite used to the curve describing path data notation, we still remember that the choice for this from XML view - eccentric format was solely driven by the effort for compact path data. Due to the importance of this criterion we are not surprised that there are some more ways SVG attempts to minimize the size of path data. The numerical values are separated from each other and from the command letter by the single characters comma, blank and newline. These separators also referred to as whitespace characters may be eliminated under certain conditions: 1. We can condense two or more whitespaces in order to a single whitespace character.
d=M 10, 0, L 10, -20 L -10, 40Z d=M 10,0 L 10,-20 L -10,40 Z

2. We can eliminate any whitespace before or after a command letter.


d=M 10,0 L 10,-20 L -10,40 Z d=M10,0L10,-20L-10,40Z

Learn SVG

Chapter 4 Curves

22

3. Any whitespace before a negative numbers minus sign may be omitted.


d=M10,0L10,-20L-10,40Z d=M10,0L10-20L-10,40Z

4. We may eliminate the command letters of subsequent path segments that are of the same type - except of the first of course.
d=M10,0L10-20L-10,40Z d=M10,0L10-20-10,40Z

5. There is an important exception to the previous rule. Multiple pairs of coordinates following an M,m command are interpreted as values of following L,l commands, since the moveto can have assigned only one point to it.
d=M10,0L10-20-10,40Z d=M10,0 10-20-10,40Z

6. For horizontal and vertical lines SVG offers the horizontal lineto H,h and vertical lineto V,v commands. With these commands we can potentially compress our path further.
d=M10,0L10-20-10,40Z d=M10,0V-20L-10,40Z

Please remember also for generating short path data that relative path commands usually result in more compact code than absolute commands. Closing Paths Sometimes we have to close a path with an arc or spline segment. As we learned, we cannot use the closepath command Z here, since it is simply drawing a straight line back to the beginning of the sub-path. So we must close the path with that particular arc or spline segment. But even if you close the path explicitly, I strongly recommend to always use an additional Z command nevertheless. Only that way you ensure to have the sub-paths start and end point joined regularly.

Figure 4-26. Explicit closing path

Filling a Path
Filling a path consisting of lines is not so much different from filling a <polygon> or <polyline> element. A non-closed path is automatically closed for filling by the SVG renderer with the help of an invisible closepath segment (Figure 4-27).

Learn SVG

Chapter 4 Curves

23

Figure 4-27. Filling closed and non-closed pathes Since paths can intersect themselfes or can have subpaths, that may overlap or contain each other completely, SVG provides certain rules to deal with these filling cases. The basis of these rules is the so called scanline rendering, which works as follows: In order to test any point (pixel) on the canvas being inside of the path, we draw a ray from that point to infinity in any direction. Now we examine the locations where the ray crosses the path segments. Based on this rendering algorithm SVG 1.0 defines the presentation attribute fill-rule that can have one of three possible values, evenodd, nonzero and inherit. With the next SVG version 2.0 another rule needs to be implemented, the winding-count rule.

Figure 4-28. Principle of Scanline Rendering nonzero: When the ray crosses a segment of a clockwise oriented subpath we add +1 to the count of crossings. When the ray crosses a segment of a counterclockwise oriented subpath we subtract 1. If the total result of crossings is zero, the point is outside, in the case of nonzero the point lies inside. evenodd: We simply add +1 whenever the ray crosses a path segment regardless of the paths angular direction. Is the result of crossings an even number, the point is outside. With the result of an odd number, the point must be inside. winding-count: The first step is identical to the nonzero fill rule. When the ray crosses a segment of a clockwise oriented subpath we add +1 to the count of crossings. When the ray crosses a segment of a counterclockwise oriented subpath we subtract 1. If the result of crossings is zero, the point is outside and wont get filled. If the amount

Learn SVG

Chapter 4 Curves

24

of the resulting number is 1, the point is drawn with the fill coulour. In the case of a resulting number of greater than 1, the point will be filled multiple times. We get a visual effect with this fill rule only in combination with transparency, i.e. a fill-opacity of less than 1.0.

Figure 4-29. Application of different fill-rule values A notable characteristic of these fill rules is the ability to create holes in seemingly solid objects. Lets apply this effect to our car now and cut a window in it. Then looking through that window we want to see another object, which is partially hidden by the car. With that we can achieve a special clipping effect.

Figure 4-30. Clipping Cars Here is the SVG code to Figure 4-30.
<svg width="600" height="400" viewBox="0 0 300 200"> <defs> <g id="car"> <path fill="silver" stroke="black" stroke-width="2" stroke-linejoin="round" d="M 50,100 Q 40,75 90,70 Q 95,60 95,50 Q 180,40 170,100 Z

Learn SVG

Chapter 4 Curves

25

M 160,70 Q 145,50 100,55 Q 100,60 95,70 Z" /> <circle cx="80" cy="100" r="10" stroke="black" stroke-width="5" fill="lightgray" /> <circle cx="145" cy="100" r="10" stroke="black" stroke-width="5" fill="lightgray" /> </g> </defs> <use xlink:href="#car" transform="translate(100,95) scale(0.95) translate(-50,-100)"/> <use xlink:href="#car" /> </svg>

Markers on a Path
We discussed the marker element intensively in Chapter 3, where we finally created arrow heads for our dimension line. We want to revisit these markers now, since there are some special interesting aspects of markers in combination with paths. First of all, we can place markers only at distinct path points the paths verticies. In order to do this, we may use at least three different types of markers with a path. One marker on the paths start vertex using the marker-start attribute, another marker on the paths end vertex with the marker-end attribute and yet another marker on all paths middle verticies by the marker-mid attribute. For the common case where we want a single marker on all path verticies inclusive start and end vertex, we may use the marker attribute as a shortcut. The specification doesnt define the exact behaviour for treating start and end vertex with closed paths. That means, it is dependent on the implementation if there are two markers on the start vertex or only one, even if we close the path explicitely with a closepath segment.

Figure 4-31. Path with Markers Please note, that marker-start and marker-end only apply to the paths very first and last vertex and not to start and end verticies of sub-paths. Moreover SVG allows us to adjust the markers orientation. To accomplish this we may specify a fixed angular value with the markers orient attribute. This results in all markers being rotated by the same amount (see orient=30 in Figure 4-31). But frequently we want

Learn SVG

Chapter 4 Curves

26

to have the markers aligned tangential to the curve. We only need to specify orient=auto then. With this we achieve an automatic orientation so, that the x-coordinate of the markers coordinate system coincides with the path vertex tangent. However there might be a conflict with the incoming segments end tangent being not equal to the following segments outgoing start tangent. SVG deals with that cases by simply calculating the average tangent from those two tangents and then align the markers x-axis to this new tangent. Here is the SVG code for the last (lower right) path from Figure 4-31.
<svg width="800" height="400" viewBox="0 0 400 200"> <defs> <marker id="vertex" viewBox="-5 -5 10 10" markerWidth="10" markerHeight="10" markerUnits="strokeWidth" orient="auto"> <path stroke="black" d="M0,-2.5 0,-5 M0,2.5 0,5" /> <circle r="2.5" stroke="black" fill="none"/> </marker> </defs> <path marker-start="url(#scaleVertex)" marker-mid="url(#scaleVertex) d="M10,60 L10,30 L20,20 Q40,0 60,20 T100,20 L110,30 L110,60 Z" stroke-width="1.5" stroke="blue" fill="lightgray" stroke-linecap="round" /> </svg>

With this path we used an intelligent marker, which is able to adjust its own size to the paths stroke width. We discussed this feature in Chapter 3 already. All we have to do for achieving this effect is using the markerUnits=strokeWidth attribute. Maybe you find it somewhat inconvenient that we cannot affect the marker locations. There is a good chance with SVG 2.0 to gain a greater flexibility in positioning markers on a path. Meanwhile we need to achieve this effect with the help of a little script. Lets assume we want to walk jovially along a path and whenever a certain time has passed we drop a marker. When we finally arrive, the path has been marked equidistantly.

Figure 4-32. Path with equidistant Markers Here is the SVG document.
<svg width="800" height="400" viewBox="0 0 400 200" onload="SetMarkers(evt)"> <defs> <g id="vertex"> <path stroke="black" d="M0-2.5 0-5 M0,2.5, 0,5" /> <circle r="2.5" stroke="black" fill="none"/> </g> </defs> <path id="contour" d="M10,60 L10,30 L20,20 Q40,0 60,20 T100,20 L110,30 L110,60 Z"

Learn SVG

Chapter 4 Curves

27

stroke="blue" fill="lightgray" stroke-linecap="round" /> <script><![CDATA[ function SetMarkers(evt) { var path = evt.target.ownerDocument.getElementById("contour"), pathLength = path.getTotalLength(), point = null, use = null, n = 15; for (var i=0; i<n; i++) { point = path.getPointAtLength(i/n*pathLength); use = evt.target.ownerDocument.createElement("use"); use.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#vertex"); use.setAttribute("x", point.x); use.setAttribute("y", point.y); evt.target.ownerDocument.documentElement.appendChild(use); } } ]]></script> </svg>

Dont panic, if you are new to scripting. We will talk about this powerful stuff later in chapter 11. Here is a brief description of the steps. 1) We change the marker element to a group element. 2) We tell the SVG renderer to call a script function when the document has loaded completely. 3) We walk in a loop along the path and ask for equidistant path point coordinates at 0/15, 1/15, 2/15, .., 14/15 of the paths total length. 4) We create and set a use element of the vertex group at each of those path points. We get an excellent scripting support from SVGs DOM (s. Chapter 11). Unfortunately we dont get tangent information at the path points, so there is no easy way to have the use elements tangentially aligned to the path at current. Markers only Needless to say, that we are able to use the <path> element for displaying the markers only. We achive this by simply setting its stroke and fill presentation attributes to none. Sometimes it may be sufficient when we have simple dots as markers. For this special but very common demand I want to show you a trick with the path element where we even dont need the marker element. For this we Set the paths stroke-width attribute to the necessary size of the dots Set the stroke-linecap attribute to round for the dots. Place zero-length line segments at the desired locations by simply using pairs of moveto/closepath commands.

Learn SVG

Chapter 4 Curves

28

Figure 4-33. Path resulting in Dots This way we can have round path markers without the path of course - in a very compact manner.

Path Command Reference


Commands & Parameters M,m L,l H,h V,v x, y x, y x y Instruction Move from current point to new point (x, y). Draw line from current point to new point (x, y). Draw line from current point to new point (x, current-point-y). Draw a line from current point to new point (current-point-x, y). Draw an elliptical arc from current point to new point (x, y). The arc belongs to an ellipse with the radii rx and ry and a rotation with respect to the positive x-axis of x-axis-roation (in deg). If large-arc-flag is 0 (zero), the small arc (less than 180 deg) is drawn, a value of 1 results in the large arc (greater than 180 deg) being drawn. If the sweep-flag is 0 the arc is drawn in negative angular direction (counterclockwise), if its value is 1 the
positive angular direction (clockwise) is selected.

A,a

rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y

Q,q

x1, y1 x, y

T,t

x, y x1, y1 x2, y2 x, y

C,c

S,s

x2, y2 x, y

Draw a quadratic Bzier spline segment from the current point to new point (x,y) while approximating the control point (x1,y1). Draw a smooth quadratic Bzier spline segment from the current point to new point (x,y). The previous segment must be of type (smooth) quadratic Bzier spline also and thats control point is reused then via reflection relative to the current point. Draw a cubic Bzier spline segment from the current point to new point (x,y) while approximating the control points (x1,y1) and (x2,y2) in that order. Draw a smooth cubic Bzier spline segment from the current point to new point (x,y). The previous segment must be of type (smooth) cubic Bzier spline also and thats second control point is reused then via reflection relative to the current point as the segments first control point. The second control must be explicitely specified.
Table 4-2. Path commands

Chapter 5 Text Processing "When ideas fail, words come in very handy." - Goethe (1749-1832) "Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein (1879-1955)

Chapter Objectives
The <text> and <tspan> Elements Text Wrapping and Text Selection Text Presentation Properties Text Layout Properties Using Fonts, Glyphs and SVG Fonts Referencing Text with the <tref> Element Text on a Path with the <textPath> Element Internationalization Whitespace Handling

Overview
SVGs text capabilities allow us to add titles, labels, button text and even whole paragraphs to our SVG images. Working with text can be challenging but after completing this chapter you will have solid grasp of the main aspects of text processing in SVG. Also, an array of tips and tricks will be revealed that deal with text in SVG from both design and programming perspectives. There are many issues that are specific to positioning and styling SVGs text element that we will be discovering and putting into practice in this chapter. We will also cover text-on-apath, referencing internal and external text content, fonts, line wrapping, text selection and even anticipated changes in the SVG 2.0 specification.

The <text> and <tspan> Elements


The text and tspan' elements are the primary elements used for rendering text in SVG. Using the <text> Element Text elements in SVG take an x and y attribute that specifies the start position of our text content. Here is the classic Hello world example redesigned for SVG.

Learn SVG

Chapter 5 Text Processing

Figure 5-1.

Hello world demonstrating text positioning

<svg width="350" height="300"> <text x="30" y="20" fill="black" font-size="10"> Hello world. </text> <text x="30" y="50" fill="black" font-size="10"> I&apos;m a Scalable Vector Graphic! </text> </svg>

The Hello world example above uses the familiar x and y attributes for positioning the text elements textual content inside the SVG images coordinate system. The dx and dy attributes can be used to offset the text content by a specified length. The dx and dy attributes are optional. Lets take a closer look at the text element syntax. Element Syntax
<text id="name" x="coordinate+" y="coordinate+" dx="lengths+" dy="lengths+" rotate="numbers+" textLength="length" lengthAdjust"spacing|spacingAndGlyphs" transform="transform properties" style-attribute="style-attribute"> <!-- tspan text content here --> </text>

This simple diagram helps to demonstrate some of the text layout properties and terminology.

Learn SVG

Chapter 5 Text Processing


Figure 5-2. Text layout and terminology

<?xml version="1.0"?> <svg width="350" height="300"> <text x="30" y="70" dx="30" font-size="50">Alpha</text> </svg>

In the diagram the x attribute equals 30 and the y attribute equals 70. Then the dx attribute moves the entire word over 30 units so that the word ends up being rendered at the (60,70) position in our SVG image coordinate system. As you can see in the above diagram, if the x or y attribute values are set equal to 0 then the text will render at the 0,0 coordinate of your SVG image. This means that you will probably not be able to see anything because your text will be above the viewing area. If the x or y attribute is not used in a text element then the Adobe SVG Viewer will assume that these values are equal to zero. The Batik viewer however will not render the text element at all. Using the <tspan> Element The tspan element is a lot like the text element except for a few key differences. First, the example makes use of a <text> element that contains a <tspan> element. The tspan element must be contained within a text element. As we shown in this example, multiple values can be used to position individual characters within the elements textual content.

Figure 5-3.

List of values defining vertical position

<svg width="350" height="300"> <text x="20" y="30" fill="black"> Don't <tspan dx="0" dy="-2 4 -4 4 -4" stroke="black">WORRY</tspan> be <tspan dx="0" dy="-4 4 4 -4 -4" fill="purple">HAPPY</tspan> ! </text> </svg>

There are several things to examine in this example. While the tspan elements positioning properties, dx and dy, can offset the tspan contents relative the normal flow of the text. Notice that the dy attribute contains a list of numbers that are used to position individual characters in the words WORRY and HAPPY.

Learn SVG

Chapter 5 Text Processing

Lets take a closer look at the syntax of the tspan element. Element Syntax
<tspan id="name" x="coordinate+" y="coordinate+" dx="lengths+" dy="lengths+" rotate="numbers+" textLength="length" style-attribute="style-attribute"> <!-- tspan text content here --> </tspan>

The syntax for the tspan element is pretty much like the syntax for the text element. The + character at the end of the value data type name means that this property value can be a list of lengths, coordinates or numbers. Text Wrapping and Text Selection Currently the text element does not automatically wrap your text in the major SVG viewers. Therefore if your text extends past the edge of the SVG image viewbox then it might not be displayed. The SVG 1.2 and SVG 2.0 specifications will probably support text wrapping. For now if you want to display multiple lines of text then you will have to vertically position your strings of text using two or more tspan or text elements. The user can select the textual content of text elements but the text element only allows one line to be selected at a time. The tspan element however can be used to allow the user to select multiple lines of text at once. The textual content of multiple tspan elements within one text element can all be selected at one time.

Figure 5-4.

Positioning multiple lines of text

<?xml version="1.0"?> <svg width="350" height="300">

<text x="10" y="30" fill="black" font-size="10"> <tspan>They might not need me - yet they might -</tspan> <tspan x="10" dy="20">I'll let me Heart be just in sight -</tspan> <tspan x="10" dy="20">A smile so small as mine might be </tspan> <tspan x="10" dy="20">Precisely their necessity -</tspan> </text>

Learn SVG
</svg>

Chapter 5 Text Processing

Since the entirety of the poem in Figure 5-4 is contained within a single text element your users will be able to select and copy all of the lines of the text at once. By the way, the poem used in Figure 5-4 is by the great Emily Dickinson. Alternatively, you can use JavaScript to provide some degree of text wrapping as we detail on our website, FundamentalSVG.com.

Text Presentation Properties


SVG provides an enormous amount of options for controlling the display of your text. Presentation properties such as fill, stroke as well as decoration properties such as underline, bold, italic, subscript and superscript are at your disposal and are easy to use. Fill and Stroke Properties The fill and stroke properties for text are a lot like the fill and stroke properties for shapes.

Figure 5-5. Presentation properties


<svg width="350" height="300"> <text x="30" y="20" font-size="19"> Default </text> <text x="30" y="40" fill="orchid" font-size="19"> Fill </text> <text x="30" y="60" fill="orchid" stroke="black" font-size="19"> Stroke and Fill </text> <text x="30" y="80" fill="orchid" stroke="black" stroke-width="1.5" font-size="19"> Wide Stroke and Fill </text> <text x="30" y="100" fill="none" stroke="black" font-size="19"> Stroke Outline

Learn SVG
</text> </svg>

Chapter 5 Text Processing

We encourage you to tweak and play with these properties yourself. Notice how easy it is to create unique designs with your text. These are just a few of the many standard CSS and SVG specific properties and can be used to stylize <text> elements. As you will soon realize we can do much more with text in SVG. The key attributes are font-weight, font-style and text-decoration. The font-weight and fontstyle properties were borrowed directly from the fonts sections of the CSS specification, http://www.w3.org/TR/REC-CSS2/fonts.html. 'font-weight' Value: normal | bold | bolder | lighter | 100 | 200 | 300| 400 | 500 | 600 | 700 | 800 | 900 | inherit Initial: Normal Applies to: text content elements Inherited: Yes Percentages: N/A Media: Visual Animatable: Yes 'font-style' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

normal | italic | oblique | inherit normal text content elements yes N/A visual yes

'text-decoration' Value: none | [ underline || overline || line-through || blink ] | inherit Initial: none Applies to: text content elements Inherited: no (see prose) Percentages: N/A Media: visual Animatable: yes As stated in the definition above the SVG the text-decoration property supports the values underline, overline, line-through and blink. Making your text bold, underlined or italic in SVG is accomplished through some of the same properties that you would use to do these decorations in HTML. However, SVG allows us to use presentation attributes as this example demonstrates. Figure 5-6 demonstrates some textspecific style properties.

Learn SVG

Chapter 5 Text Processing

Figure 5-6.

Text decoration attributes

<svg width="350" height="300"> <text x="30" y="20" font-size="12"> Default </text> <text x="30" y="40" font-weight="bold" font-size="12"> Bold </text> <text x="120" y="40" font-style="italic" font-size="12"> Italic </text> <text x="30" y="60" text-decoration="underline" font-size="12"> Underline </text> <text x="120" y="60" text-decoration="overline" font-size="12"> Overline </text> </svg>

As you can see, adding style properties to text easy as cake. 'text-rendering' The text-rendering property can dramatically affect legibility as the next example demonstrates.

Figure 5-7.

Text rendering attributes

<svg width="600" height="200" viewBox="0 220 600 200"> <text text-rendering="auto" x="300" y="250" style="font-size:25;textanchor:middle">text-rendering</text>

Learn SVG

Chapter 5 Text Processing

<g transform="translate(0,-70)"> <text text-rendering="auto" x="300" y="350" style="font-size:15;textanchor:middle">filled</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;textanchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="fontsize:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="fontsize:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="fontsize:20;text-anchor:middle">geometricPrecision</text> </g> <g transform="translate(0,10)" stroke="black"> <text text-rendering="auto" x="300" y="350" style="font-size:15;textanchor:middle">stroked and filled</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;textanchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="fontsize:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="fontsize:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="fontsize:20;text-anchor:middle">geometricPrecision</text> </g> <g transform="translate(0,-30)" stroke="black" fill="none"> <text text-rendering="auto" x="300" y="350" style="font-size:15;textanchor:middle">stoked</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;textanchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="fontsize:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="fontsize:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="fontsize:20;text-anchor:middle">geometricPrecision</text> </g> </svg>

So far so good, lets keep going while were on a roll.

Text Layout and Alignment Properties


There are a number of specific style properties that provide us with a means of positioning and styling every aspect of textual content in our SVG images. text-anchor and baseline-shift The text-anchor property can be used to left, center or right align text with respect to the initial text position. The text-anchor property is useful for aligning both text and tspan textual content. The default value for this property is start. Setting the text-anchor value equal to middle will center the text chunk on the current text position that is specified by the text or tspan x and y property values.

Learn SVG

Chapter 5 Text Processing

Figure 5-8.

Text alignment using text-anchor

<svg width="350" height="300"> <text x="70" y="30" font-size="15"> start </text> <text x="70" y="50" text-anchor="middle" font-size="15"> middle </text> <text x="70" y="70" text-anchor="end" font-size="15"> end </text> </svg>

In this example the text-anchor attribute is used to center align all of the textual content along a vertical axis located at the position specified by the text elements x attribute. This helps to center all of the textual content that is contained in the text element. In the next example everything will be anchored at the midpoint of the texts length. This makes positioning a lot easier because we will only have to tweak and maintain the one coordinate that specifies the midpoint of the textual content.

Figure 5-9.

Advertisement using text-anchor

Learn SVG

Chapter 5 Text Processing

10

<svg width="350" height="300"> <!-- Circle --> <circle cx="120" cy="120" r="100" fill="darkred" stroke="black" stroke-width="3" /> <!-- Advertisement Text --> <text x="120" y="60" fill="white" font-family="Verdana" text-anchor="middle"> <tspan font-size="28">ALL</tspan> <tspan font-size="28" x="120" dy="35">Men's Pants</tspan> <tspan font-size="45" x="120" dy="55"> <tspan font-size="30" baseline-shift="super">1</tspan> <tspan font-size="30">/</tspan> <tspan font-size="30" baseline-shift="sub">2</tspan> Off! </tspan> <tspan font-size="15" x="120" dy="45">(today only)</tspan> </text> </svg>

The baseline-shift property has been used to position the text. Most fonts contain information about where to position subscripts and superscripts along the text baseline in regard to normal character data for the font. In this example the character 1 has a baselineshift value of super that means that this character should be treated as a superscript. Likewise, the 2 character is positioned as a subscript. Also notice that the x attribute in some of the tspan elements effectively resets the absolute start position for the tspan textual content. The dy attribute affects the relative y start coordinate for the textual content of the tspan element. We will discuss the font-related attributes a little later in this chapter. letter-spacing, word-spacing and kerning The default value for the letter-spacing and word-spacing properties is normal. By specifying a positive or negative length value in the letter-spacing and word-spacing properties you are adding or subtracting the amount of space between letters and words respectively.

Learn SVG

Chapter 5 Text Processing

11

Figure 5-10.

Spacing and kerning examples

<svg width="350" height="300"> <text x="10" y="20" fill="black" font-family="" word-spacing="normal">Word spacing is normal.</text> <text x="10" y="40" fill="black" font-family="" word-spacing="5">Word spacing is 5.</text> <text x="10" y="60" fill="black" font-family="Lucida Handwriting" letter-spacing="normal">Letter spacing is normal.</text> <text x="10" y="80" fill="black" font-family="Lucida Handwriting" letter-spacing="3">Letter spacing is 3.</text> <text x="10" y="100" fill="black" font-family="Georgia" kerning="auto">Kerning is auto.</text> <text x="10" y="120" fill="black" font-family="Georgia" kerning="0">Kerning is 0.</text> <text x="10" y="140" fill="black" font-family="Georgia" kerning="3">Kerning is 3.</text> </svg>

Here are the definitions for these properties.

'letter-spacing' Value: normal | <length> | inherit Initial: normal Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yes 'word-spacing' Value: normal | <length> | inherit Initial: normal

Learn SVG Applies to: Inherited: Percentages: Media: Animatable:

Chapter 5 Text Processing text content elements yes N/A visual yes

12

SVG provides the kerning property in order to allow you to alter the spacing between letters for specific fonts. The same letter in 10 different fonts might have 10 different widths. The width spacing for certain pairs of letters is defined in a fonts kern-pair table. The default value for the kerning attribute is auto that means that the text will make use of the fonts kern-pair table. Specifying a value of 0 effectively turns auto-kerning off. Specifying a positive or negative kerning value tells the SVG viewer to ignore the kern-pair table and instead evenly space the letters by the numbers specified in kerning value. 'kerning' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: auto | <length> | inherit auto text content elements yes N/A visual yes

By specifying a kern value you are in effect turning auto-kerning off for the font and telling the font to only use the value that you specify for the spacing of each letter of your text. TextLength and LengthAdjust In this example the phrase "The average person thinks he isn't." by Father Larry Lorenzoni is used to demonstrate the workings of the textLength and lengthAdjust properties. You can use these two properties on the text element to tweak your text to precisely fit your needs.

Figure 5-11.

textLength and lengthAdjust attributes

I used the Batik viewer to demonstrate these two properties because version 3 of the Adobe SVG Viewer did not yet support the textLength and lengthAdjust properties.
<svg width="350" height="300">

Learn SVG

Chapter 5 Text Processing

13

<text x="10" y="30" fill="black" font-size="7" textLength="150" lengthAdjust="spacing">The average person thinks he isn&apos;t.</text> <text x="10" y="40" fill="black" font-size="7" textLength="150" lengthAdjust="spacingAndGlyphs">The average person thinks he isn&apos;t.</text> <text x="10" y="70" fill="black" font-size="7" textLength="180" lengthAdjust="spacing">The average person thinks he isn&apos;t.</text> <text x="10" y="80" fill="black" font-size="7" textLength="180" lengthAdjust="spacingAndGlyphs">The average person thinks he isn&apos;t.</text> </svg>

textLength specifies the length value that the string of text must fill. The lengthAdjust property value can be either spacing or spacingAndGlyphs. As you can see by setting the value to spacingAndGlyphs both the spaces between characters and words and the glyphs or letters are stretched to meet the length requirement that is specified by the textLength property. Note that the lengthAdjust property can only be used on the text element and not on the tspan element. Rotate The rotate property can be used to position individual text characters or whole strings of text. Using a comma- or space-separated list of number value in the rotate attribute we are able to rotate individual characters within the text element as shown in figure 5-12.

Figure 5-12.

Rotate text

<svg width="350" height="300"> <text x="40" y="30" fill="black" font-size="20" rotate="-30">Rotate word</text> <text x="40" y="60" fill="black" font-size="20" rotate="-40 -35 -30 -20 -10">Rotate letters</text> <text x="40" y="90" fill="black" font-size="20" rotate="0 0 0 0 0 0 0 -20 -15 0 15 20"> <tspan>Rotate tspan</tspan> </text> </svg>

Learn SVG

Chapter 5 Text Processing

14

This image was produced by Batik. The Adobe SVG Viewer does not support rotating entire strings of text with just one number. In figure 5-10 notice that if two numbers are specified then only the first two characters will be rotated. Also notice that if fewer numbers are specified than the numbers of letters in the text string then the extra letters are not rotated. The transform property can be used to rotate text but well be discussing transformations in depth in the next chapter. writing-mode The writing-mode attribute is used to set the direction or inline-progression-direction of text content.

Figure 5-13.

Text layout writing-mode attribute

<svg width="800" height="600" viewBox="0 0 400 300"> <text x="30" y="20" fill="silver" stroke="darkslategrey" stroke-width=".7" opacity="1" font-weight="bold" font-size="15" writing-mode="lr-tb">left-to-right</text> <text x="120" y="60" fill="silver" stroke="darkslategrey" stroke-width=".7" opacity="1" font-weight="bold" font-size="15" writing-mode="rl-tb">right-to-left</text> <text x="185" y="2" fill="silver" stroke="darkslategrey" stroke-width="3" opacity="0.6" font-weight="bold" font-size="33" writing-mode="tb-rl">S V G</text> </svg>

This attribute can be ideal for positioning text for backgrounds, watermarks and other design elements. This is the writing-mode property syntax. 'writing-mode' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: lr-tb | rl-tb | tb-rl | lr | rl | tb | inherit lr-tb 'text' elements yes N/A visual no

Learn SVG

Chapter 5 Text Processing

15

The values lr, rl and tb are merely shortcuts for specifying the values lr-tb, rl-tb and tb-rl respectively. glyph-orientation The glyph-orientation properties allow you to rotate the angle of your text along the horizontal and vertical axis. If you text is running top-to-bottom you could set the glyphorientation-vertical property value to zero. This will rotate every character in your text string so that each letter is aligned with the vertical axis. Here are the definitions for these properties. 'glyph-orientation-vertical' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: auto | <angle> | inherit auto text content elements yes N/A visual no

'glyph-orientation-horizontal' Value: <angle> | inherit Initial: 0deg Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: no Direction and Unicode-bidi properties Languages such as Han, Arabic, Hebrew, Kanji and Chinese can be written in directions other than left to right including right to left and top to bottom. If you need the characters in your text string to actually reverse positions then you will need to use the direction and bi-directionality (bidi) properties. This is the definition for these properties. 'direction' Value: Initial: Applies to: Inherited: Percentages: ltr | rtl | inherit ltr text content elements yes N/A

Learn SVG Media: visual Animatable: no 'unicode-bidi' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

Chapter 5 Text Processing

16

normal | embed | bidi-override | inherit normal text content elements No N/A Visual No

We have assembled several examples of these two properties on our website www.fundamentalsvg.com

Inheritance
Inheritance is an extremely useful feature of SVG and more generally many XML-based languages. In fact inheritance of style properties in SVG works just like the inheritance rules in HTML as us demonstrated in this example.

Figure 5-14.

Inheritance demonstrated with stroke value

<svg width="350" height="300"> <text x="30" y="20" stroke="none" fill="black" font-size="15"> Global stroke and fill <tspan x="40" dy="20" stroke="black" fill="none">Local stroke and fill</tspan> <tspan x="40" dy="20">Inherited stroke and fill</tspan> </text> </svg>

Notice that the fill property on the text element is overridden by the local fill property on the <tspan> element. By adding the attribute stroke=none" to the group the entire group inherits the stroke=none property value. If however, one of the contained elements have a stroke=2 for example then this local attribute will override the inherited stroke attribute value and the contained element will render a stroke as demonstrated in this SVG image. If any of these attributes are declared on children elements then the local attribute will override any attribute that is specified on parent or ancestor elements.

Learn SVG

Chapter 5 Text Processing

17

This is also true for the rotate property. Remember that the 'text' elements x, y, dx, dy and rotate attributes can take a list of values. The x, y, dx, dy and rotate attributes on 'text' and 'tspan' elements apply to any contained character content, not just character content within immediate children.

Text on a Path
The textPath element allows us to reference a path element. All textual content within the textPath element can then be positioned along the outline of the path. This feature gives us an amazing amount of control over text positioning in SVG. For example, Figure 5-15 demonstrates how easy it is to position text along a variety of paths using the powerful textPath element.

Figure 5-15.

Text along a Path

<svg width="800" height="600" viewBox="0 0 400 300"> <!-- Paths <path id="textPath01" d="M10 50 L80 30" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath02" d="M130 30 L200 50" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath03" d="M279 11 L304.981 56 L253.019 56 z" transform="matrix(1.19319 0 0 1 -53.9002 4.77396e-015)" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath04" d="M9 86 L79 86 L79 135" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath05" d="M130 85 L200 85 M130 110 L200 110 M130 135 L200 135" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath06"

Learn SVG

Chapter 5 Text Processing

18

d="M282.057 146 C288.599 135.355 316 118.885 316 101.844 C316 72.3472 87.46 79.366 281.796 91.016 C275.78 79.0081 248 74.2157 248 101.844 C248 119.3 276.338 135.443 282.057 146 z" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath07" d="M5.5 177 C52.5 143 24.5 176 76.5 176" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath08" d="M128 176 C164 219 199 176 199 176" fill="none" stroke="black" stroke-width="0.5"/> <path id="textPath09" d="M278.7 188.8 C277.789 188.8 277.05 188.8 277.05 188.8 C277.05 190.623 277.789 192.1 278.7 192.1 C281.434 192.1 283.65 190.623 283.65 188.8 C283.65 185.155 281.434 182.2 278.7 182.2 C273.232 182.2 268.8 185.155 268.8 188.8 C268.8 196.09 273.232 202 278.7 202 C287.813 202 295.2 196.09 295.2 188.8 C295.2 177.865 287.813 169 278.7 169" transform="matrix(2.57576 0 0 -1 -444.364 371.014)" fill="none" stroke="black" stroke-width="0.5"/> <!-- Text <text x="50px" y="80px" visibility="visible" fill="darkslategrey" font-size="12" stroke="none"> <textPath xlink:href="#textPath01">Going up, madam?</textPath> <textPath xlink:href="#textPath02">Going down, sir?</textPath> <textPath xlink:href="#textPath03">S c a l a b l e &#160;&#160;&#160; V e c t o r &#160;&#160; G r a p h i c s</textPath> <textPath xlink:href="#textPath04">H o r i z o n t a l V e r t i c l e</textPath> <textPath xlink:href="#textPath05" font-size="9" fill="black">This text spans multiple lines. Word-wrapping needs more intelligence.</textPath> <textPath xlink:href="#textPath06">Now you know that I will love you forever and ever!</textPath> <textPath xlink:href="#textPath07">Life. Ups and downs.</textPath> <textPath xlink:href="#textPath08">Joy &gt; Sadness &gt; Joy</textPath> <textPath xlink:href="#textPath09">Here we go loop-de-lu. Here we go loop-de-li.</textPath> </text> </svg>

Remember that SVG uses XML grammar; this ability to reference content in other XML elements is a part of the extensibility aspect of XML. Using xlink:href attribute we are able to position our text along the path whose id=textPath01. This path is located inside of our defs element at the beginning of our SVG document. The path element with the id equal to textPath05 uses the moveTo command to create a path that creates three lines. The textPath element is then able to display three distinct lines of text along the textPath05 path. This example displays the path with the text. If you want to only display the text enclose your path elements with a defs element. Remember that all content within a defs element will never be directly displayed. Recall from Chapter 3 that in SVG the path commands stand for relative coordinate values if they are lower-case and are absolute coordinates if they are capitalized. In the following graphic each point specifies a coordinate that is absolute and is therefore positioned with respect to the origin (0,0) of the entire graphical image.

Learn SVG

Chapter 5 Text Processing

19

Figure 5-16.

Example of text following a path

<svg width="350" height="300"> <defs> <path id="textPath01" d="M90 80 L160 80 L160 160"/> <path id="textPath03" d="M133 44 C88.8176 44 53 79.5937 53 123.5 C53 167.406 88.8176 203 133 203 C177.182 203 213 167.406 213 123.5 C213 79.5937 177.182 44 133 44 z"/> <g id="people"> <rect x="222" y="9" width="30" height="30" stroke="black" stroke-width="5" fill="none"/> <rect x="213" y="42" width="48" height="51" stroke="black" stroke-width="5" fill="none"/> <rect x="217" y="93" width="13" height="25" stroke="black" stroke-width="5" fill="none"/> <rect x="243" y="93" width="13" height="25" stroke="black" stroke-width="5" fill="none"/> </g> </defs> <use x="0" y="0" xlink:href="#textPath03" fill="none" stroke="blue" stroke-width="3"/> <text font-size="15" letter-spacing="3"> <textPath xlink:href="#textPath01"> Square people </textPath> </text> <text font-size="15" baseline-shift="-15" letter-spacing="3" word-spacing="5" text-anchor="start" fill="black"> <textPath xlink:href="#textPath03" startOffset="26%"> in a world that&apos;s round. </textPath> </text> <g transform="translate(58 95) scale(0.25 0.25)"> <g transform="translate(-45 25)"> <use x="0" y="0" xlink:href="#people"/> </g> <g transform="translate(10 -15)"> <use x="0" y="0" xlink:href="#people"/> </g> <g transform="translate(60 25)"> <use x="0" y="0" xlink:href="#people"/>

Learn SVG
</g> </g> </svg>

Chapter 5 Text Processing

20

First of all, this phrase is from the song Heartbreak Town by the Dixie Chicks whose songs have a way of making my eyes watery. Second, one of the interesting features that you may notice in the above example is the use of the xlink:href attribute in the textPath element. The text Square people is contained within the textPath element that references the path called textPath01. startOffset The startOffset attribute is a length value that can be used on the textPath element to position the textual content along the referenced path. A positive startOffset will move the text further along the path while a negative startOffset value will pull the text in the opposite direction along the path. If using a percentage to specify the length then 0% would equal the start of the path and 100% would equal the end of the path. In the above example we set the startOffset value equal to 26% for the text in a world thats round. This moves the text around the circular path whose id equals textPath03 so that the text phrase wraps around the bottom of the round world. Finally, you will notice that the use element is used to render the textPath03 path in our SVG image. Notice that if the length of the text exceeds the length of the path that the text is cut off in mid sentence. This can be prevented using script to set the textLength property value equal to the path.length value.

Fonts and Font Properties


This is an interesting topic because there are so many options and possibilities. This section could even be in its own book if we delved into some of the fascinating typography issues that concern the power and flexibility of SVG. Unfortunately we can only spend a brief amount of time on the concepts of glyphs, characters, font tables, system fonts, SVG Fonts and referencing and embedding fonts. First lets cover a few basic font properties like font-size and font-family. font-size We have used the font-size property many times already in examples in this book. This example shows how different font sizes look in SVG.

Learn SVG

Chapter 5 Text Processing

21

Figure 5-17.

Various font sizes

<svg width="350" height="300"> <text x="20" y="28" fill="black">default size</text> <text x="20" y="80" fill="black" font-size="50" stroke="0">font-size="50"</text> <text x="20" y="110" fill="black" font-size="35" stroke="0">font-size="35"</text> <text x="20" y="135" fill="black" stroke="0" font-size="25">font-size="25"</text> <text x="20" y="160" fill="black" stroke="0" font-size="20">font-size="20"</text> <text x="20" y="180" fill="black" stroke="0" font-size="16">font-size="16"</text> <text x="20" y="200" fill="black" stroke="0" font-size="14">font-size="14"</text> <text x="20" y="220" fill="black" stroke="0" font-size="11">font-size="11"</text> <text x="20" y="240" fill="black" stroke="0" font-size="8">font-size="8"</text> <text x="20" y="260" fill="black" stroke="0" font-size="5">font-size="5"</text> <text x="20" y="280" fill="black" font-size="1">font-size="1"</text> <text x="150" y="200" fill="black" stroke="0" font-size="2em">font-size="2em"</text> <text x="150" y="230" fill="black" stroke="0" font-size="24px">font-size="24px"</text> <text x="150" y="260" fill="black" stroke="0" font-size="1.5pc">font-size="1.5pc"</text> </svg>

The font-size property value can be inherited from parent elements. If you are going to use a unit of measure to specify your font-size then I recommend using em rather than px. This is the font-size property definition. 'font-size'

Learn SVG Value:

Chapter 5 Text Processing

22

<absolute-size> | <relative-size> | <length> | <percentage> | inherit Initial: medium Applies to: text content elements Inherited: yes, the computed value is inherited Percentages: refer to parent element's font size Media: visual Animatable: yes Glyphs and Fonts There are some key differences between fonts, letters and glyphs. For most people this is a new concept that is worth exploring. Marks that make up letters are technically called glyphs. Glyphs can be defines as any mark that conveys meaning whether by itself or in sequence with other glyphs. Therefore glyphs are not always letters since many letters are comprised of more than on glyph. Also, different fonts have different glyphs for the same letter. PostScript and TrueType are vector-based font formats. The fonts called Verdana and Arial were created by the Monotype company have become very popular on the Web. The dot in a lowercase i is a glyph and is used in conjunction with a short vertical line to comprise one letter. The letter can then be included in a group of other letters to comprise a font. font-family This example demonstrates how to use different font families in SVG.

Figure 5-18.

Common font families

<svg width="350" height="300"> <text x="20" y="20" fill="darkslategrey">default size</text> <text x="20" y="40" fill="darkslategrey" font-family="Arial" stroke="0">font-family="Arial"</text> <text x="20" y="60" fill="darkslategrey"

Learn SVG

Chapter 5 Text Processing

23

font-family="Verdana" stroke="0">font-family="Verdana"</text> <text x="20" y="80" fill="darkslategrey" font-family="Courier" stroke="0">font-family="Courier"</text> <text x="20" y="100" fill="darkslategrey" font-family="Times New Roman" stroke="0">font-family="Times New Roman"</text> <text x="20" y="120" fill="darkslategrey" font-family="Comic Sans MS" stroke="0">font-family="Comic Sans MS"</text> </svg>

This is the definition for the font-family property. 'font-family' Value: [[ <family-name> |<generic-family> ],]* [<family-name> | <generic-family>] | inherit Initial: depends on user agent Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yes

System Fonts Using system fonts just means that you are relying on the client to have the specified font installed on their system. There really are very few fonts that can generally be assumed to be on most peoples systems but some common fonts include: san-serif, Arial, Times New Roman, Helvetica, Verdana, and Tahoma. Font Tables A font is not actually considered a font unless it also comes with information that defines how to present its characters. This accompanying information is commonly known as a font table and can be used to display fonts uniquely on different medium. SVG Fonts If you want to use a more custom font that is not commonly found on other computers or platforms then SVG gives us the option of sending along the actual font in our graphic. Fonts that are embedded in SVG are not surprisingly called SVG Fonts. There is a font converter called SVGFont by Steady State ( http://www.steadystate.co.uk/svg/ ) that can convert your fonts into font data that can be used in your SVG images. SVGFont has also been incorporated into the Batik SVG Toolkit. Another great option for creating SVG Fonts is Illustrator 9 and 10 that is capable of automatically to embedding the fonts into your SVG images.

Learn SVG

Chapter 5 Text Processing

24

Embedded SVG Fonts When we generate inline fonts from a program such as Illustrator 10 the glyph data and font table information is base64 encoded and saved into a <style> element as like this:
<style type="text/css"> <![CDATA[ .st0{font-family:'Verdana';} @font-face{font-family:'Verdana';src:url("data:;base64,(encoded data))} ]]> </style>

This encoded SVG Font can then be referenced using CSS like this:
<text> <tspan class="st0">Am I speaking with Verdana?</tspan> </text>

External Fonts Referenced CEF Fonts


<style type="text/css"> <![CDATA[ .st0{font-family:'Verdana';} @font-face{font-family:'Verdana';src:url(79BA9154.cef)} ]]> </style>

In the above example the CEF file would need to be located in the same directory as the SVG file and then used in your SVG just like the previous example:
<text> <tspan class="st0">Am I speaking with Verdana?</tspan> </text>

We will discuss how to use CSS in detail in Appendix B.

Referencing Internal and External Text


This may come as a surprise but text content does not need to be contained within your SVG image. The tref element allows us to reference internal or external text content. There are many advantages in referencing text content using the <tref> element rather than copying text multiple times within your SVG images. For one, any changes to the text content will only have to occur once and the changes will automatically be updated in every place that the text is used. Second, referencing text can significantly decrease the size of the SVG image since the information is used more efficiently. Referenced Text

Learn SVG

Chapter 5 Text Processing

25

Like paths, textual content can also be referenced using the xlink:href attribute as shown in the following example.

Figure 5-19.

The tref element

<svg width="350" height="300"> <defs> <text id="UseMe" x="20" y="30">I <tspan font-style="italic" font-weight="bolder">am</tspan> being used! </text> </defs> <text x="20" y="30" font-size="10">I am <tspan font-style="italic" font-weight="bolder">not</tspan> being used. </text> <text x="20" y="60" font-size="10" fill="orange"> <tref xlink:href="#UseMe" fill="darkslategrey" /> </text> </svg>

This allows us to easily reuse text content. Also remember that local properties override inherited properties. In this case the text is darkslategrey because the on the actual <tref> elements fill value is defined to be darkslategrey which overrides the text elements orange fill value. We will continue to cover style concepts progressively throughout the book and Appendix B covers both CSS and XSL styling in detail.

Internationalization
SVG has some great features that support internationalization of your SVG images including full support for Unicode character encoding and support for multiple languages via the switch element. Character encoding Unicode is an ISO standard that supports a wide-range of languages through character codes. You are probably already familiar with some common character encodings such as HMTLs &#160; that represents a space character. This is a Unicode character code. The goal of Unicode is to provide character encodings for every character of every known written language. The Unicode standard already defines sets of characters that represent characters from hundreds of languages from across our planet.

Learn SVG

Chapter 5 Text Processing

26

SVG provides full support for Unicode as well as other character encoding methods. For your convenience we have provided a reference table of Unicode characters from the HTML specification in Appendix E. switch The switch element provides a means of allowing the users systems settings to determine the language of the SVG images text content. This example demonstrates how to include support for multiple languages using the switch element and the systemLanguage attribute.

Figure 5-20.

Demonstration of the switch element

<svg width="350" height="300"> <! Text bubble --> <path transform="translate(-150 -80)" d="M314.669 164.186 C320.812 160.386 324 153.585 324 148.857 L324 117.286 C324 108.844 313.907 102 301.457 102 L204.543 102 C192.093 102 182 108.844 182 117.286 L182 148.857 C182 157.299 192.093 164.143 204.543 164.143 L285.024 164.143 L276.175 188 z" fill="white" stroke="black" stroke-width="3"/> <switch> <! OS system language set to German. --> <text systemLanguage="de" x="40" y="50" fill="black" font-size="12" font-family="Verdana"> <tspan dy="-5">Die Liebe geht</tspan> <tspan x="40" dy="20">durch den Magen.</tspan> </text> <! OS system language set to English. --> <text systemLanguage="en" x="40" y="50" fill="black" font-size="12" font-family="Verdana"> <tspan dy="-5">Love comes</tspan> <tspan x="40" dy="20">through the stomach.</tspan> </text> <! OS system language set to French. --> <text systemLanguage="fr" x="40" y="50" fill="black" font-size="12" font-family="Verdana"> <tspan dy="-5">L'amour va</tspan> <tspan x="40" dy="20">par l'estomac.</tspan> </text>

Learn SVG

Chapter 5 Text Processing

27

<! OS system language set to Spanish. --> <text systemLanguage="es" x="40" y="50" fill="black" font-size="12" font-family="Verdana"> <tspan dy="-5">El amor viene a</tspan> <tspan x="40" dy="20">traves del estomago.</tspan> </text> </switch> </svg>

When the users system language is set to German then the SVG images will render the first screenshot and if the users system language is English then the content of the second screenshot will be displayed. This shows the true power of SVG in how it can produce a variety of graphics on the clients-side based on the users system and preference settings. More information on support for internationalization on the Web can be found at these websites. RFC document: http://www.ietf.org/rfc/rfc3066.txt System language country codes: http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/index.html

Whitespace Handling
Whitespace is defined as any blanks, tabs and newline characters within a text elements character data. The property that we can use to affect how whitespace characters are dealt with in SVG is actually borrowed from the XML 1.0 specification and is therefore called xml:space. There are two possible values for the xml:space property: default and preserve. This is how these values are defined in the SVG specification.

default (the initial/default value for xml:space) - When xml:space="default", the SVG user agent will do the following using a copy of the original character data content. First, it will remove all newline characters. Then it will convert all tab characters into space characters. Then, it will strip off all leading and trailing space characters. Then, all contiguous space characters will be consolidated. preserve - When xml:space="preserve", the SVG user agent will do the following using a copy of the original character data content. It will convert all newline and tab characters into space characters. Then, it will draw all space characters, including leading, trailing and multiple contiguous space characters. Thus, when drawn with xml:space="preserve", the string "a b" (three spaces between "a" and "b") will produce a larger separation between "a" and "b" than "a b" (one space between "a" and "b").

This is simply stating that if the xml:space property value is set to default then SVG viewers should do the following: - Remove newline characters - Convert tabs characters to space characters - Remove leading and trailing space characters - Replace multiple space characters into single space characters

Learn SVG

Chapter 5 Text Processing

28

However, if the xml:space property value is set to preserve then SVG viewers will merely replace all newline and tab characters with spaces characters. This will all you to leave larger gaps between characters if you so desire. Adding blocks of text As stated earlier in this Chapter, working with blocks of text in SVG can be overly tedious due to the fact that neither textboxes nor any other means of implementing automatic word wrapping has been defined in the SVG specification. XHTML on the other hand is suited fairly well for structuring large blocks of text, therefore, whenever possible use XHTML for rendering blocks of text. This can be accomplished through mixed namespaces and is currently partially supported by the X-Smiles browser, the Mozilla browser or with the SVG Viewer in IE 5.5/6.0 using a binary behavior. Well go into this in greater depth in Chapter 11.

Summary
Now that we have covered many key SVG basics like shapes, document structure, curves, and text we will move on to even more interesting topics like gradients, filters, animation and scripting. Then well be able to do more useful things including the following: Testing SVG Viewer Installation on Clients Machines Preloading SVGs Using Server-Side ActiveX to Graph Real-Time Data Rollovers Button Creation Menu Design and Interactivity

Review of Key Strengths Lets review some of SVGs strengths that we have addressed thus far: Precise positioning Scalability (do not degrade upon panning and zooming which is ideal for portable devices, Web site navigation, charting, and mapping) Plain text (which allows developers and designers to edit SVG code using a simple text editor) Smaller file sizes (decreased download times due to the effectiveness of SVG's vocabulary) Infinite color and font options (16 million colors and support for embedded fonts which means what is seen on the screen will look exactly the same when printed)

In the coming chapters we will be addressing these strengths: - Native image effects (drop-shadows, blurs, and lighting effects can be applied when SVG is being rendered on the client side) - Animation (SVG includes built-in elements for declarative animation effects) - Scripting (large SVGs can be generated using tiny scripts and SMIL animation)

Learn SVG -

Chapter 5 Text Processing

29

Interactivity Sound (integration of user-controlled sounds) Namespaces (compatibility with XML, XLink, SMIL, as well as conformance to CSS, XSL, and the DOM this means that SVG is extensible, styleable, scriptable, and integrates easily) Several authoring environments, converters and utilities are already available for creating SVG content.

Chapter 6 : Coordinate Systems and Transformations Coordinate system, cant live without it
In the course of the previous chapters we used coordinates intensively. What exactly do we know about them? The SVG document provides us with a default coordinate system the initial User Coordinate System.

Figure 6-1. User coordinate System

With this user coordinate system comes along a plane 2D-space. This canvas is theoretically infinite in both dimensions. To specify a point on the canvas, we also need to have a unit measure affiliated to each coordinate axis. SVG provides us with initial User Units. Initially one user unit is equal to the size of one pixel. We know, that a pixel (picture element) is the smallest visible point of a raster graphics device. Consequently, the coordinates, and so the position and size of graphic elements, are device and resolution dependent. The canvas is infinite, however your computer screen is finite in both dimensions. So the SVG specification furthermore defines a finite rectangular region. Now rendering occurs only to that window the so-called Viewport..

Figure 6-2. ViewPort <svg width=200 height=100>

Learn SVG

Chapter 6 Coordinate system and Transformations

You can define the width and the height of the initial viewport by the SVG root element <svg> via its width and height attributes. The grid in the above picture has a line spacing of 10 user units. The viewports upper left corner coincides with the initial user coordinate systems origin. The positive x-axis is pointing towards the right, the positive y-axis is pointing downward. Now with that all defined, we can exactly predict, where a circle is drawn, when cx and cy is specified. Please note, that the coordinate systems origin is not for ever fixed to the upper left corner. A simple zoom or pan operation can move it to somewhere else. The mathematicians and CAD users among you will feel that coordinate axis alignment somewhat unusual, since they are accustomed to a Cartesian coordinate system, with the y-axis up. Though we need to get used to this coordinate system with the y-axis down, since it is common in the field of computer graphics. Again, the <svg> root element automatically defines a viewport with dimensions specified by its width and height attributes.

Figure 6-3. Some objects in viewport <svg width=200 height=100> <circle cx="10" cy="86" r="15" fill="red" stroke="black" /> <!-- code for the car goes here --> </svg>

All graphical elements, that are partly outside of the viewports window are clipped, i.e. only those parts of the elements inside of the viewport are rendered. Elements, that are completely outside are simply invisible.

Multiple Viewports
Now, as we are familiarized with the root elements viewport characteristic, we are not astonished to learn, that SVG allows the definition of multiple viewports. As any other element every additional viewport also has to be defined as a descendant element of the root element.

Learn SVG

Chapter 6 Coordinate system and Transformations

Figure 6-4. Circles in different viewports <svg width=200 height=100> <circle cx="10" cy="86" r="15" fill="red" stroke="black"/> <svg x="125" y="15" width="50" height="70"> <circle cx="10" cy="60" r="15" fill="blue" stroke="black"/> </svg> </svg>

In the above example a second viewport is defined inside the documents viewport. Its upper left corner is located at (125,25) and it is 50 units wide and 70 units high, expressed in coordinates and units of its parents the root elements viewport. The positioning of a viewport via x- and y-attribute is supported for all <svg> elements except the outermost <svg> element. This new viewport establishes its own new coordinate system with the origin again in the upper left corner and initial user units by default. So all its elements are using that coordinate system. This viewport is also clipping all graphics elements, that are not completely inside its window. But you can suppress this behaviour by setting the presentation attribute to overflow=visible. The above drawing shows, that both viewports use the same length units. So two circles with identical radius are rendered to the same size. What, if we want another scale? To achieve this, we can use <svg>s viewBox attribute.

Figure 6-5. Two others viewports <svg width=200 height=100> <circle cx="10" cy="86" r="15" fill="red" stroke="black" /> <svg x="135" y="15" width="50" height="70" viewBox="0 0 100 140"> <circle cx="10" cy="60" r="15" fill="blue" stroke="black" /> </svg> </svg>

Learn SVG

Chapter 6 Coordinate system and Transformations

The viewBox attributes value consists of four numbers xmin, ymin, width, height. With these you can specify a rectangular user space that will be mapped to the bounds of the affiliated viewport. Syntax:
viewBox=xmin, ymin, width, height minimal x-coordinate corresponding xmin ymin minimal y-coordinate corresponding width width of the viewport height height of the viewport

to the viewports upper left corner to the viewports upper left corner

Locale Coordinate System


When we discussed the <g> and <use> elements in a previous chapter, we didnt pay extra attention to the choice of the coordinate system. Now we need to recover that. We refer again to the rack example from chapter 3 and start defining a pallet consisting of four rectangles.

Figure 6-6. A pallet for the rack

This part should be provided for the purpose of multiple reuse. So we design it as a group in the documents <defs> section. Now, when we need to define the pallets <rect> elements, we wonder what coordinate values to choose. Since the objects dimensions are predefined, we have not much choice. We can arbitrarily define at least one points coordinates, the others result more or less uniquely from the dimensions given. So we define the pallets upper left corner to have the coordinates (0,0). By having fixed this, we implicitly refer to a coordinate system with its origin at (0,0).

Figure 6-7. Showing viewport for pallet <g id="pallet" stroke="black" fill="tan" > <defs> <rect id="block" width="16" height="12" /> </defs> <rect x="0" y="0" width="132" height="3" /> <use xlink:href="#block" x="0" y="3" /> <use xlink:href="#block" x="58" y="3" /> <use xlink:href="#block" x="116" y="3" /> </g>

We chose to give the upper board a thickness of 3 and the blocks a width of 16 and a height of 12. With this all other coordinates could be calculated. As the pallet is made out of wood, tan seems to be an appropriate colour for the rectangles.

Learn SVG

Chapter 6 Coordinate system and Transformations

You might ask now: Where did I define a coordinate system in this code?. Indeed we didnt, at least not explicitly. But as I mentioned above, we do refer to a implicit coordinate systems origin, when we write x="58" and y="3". Now that we finished our pallets definition, we can imagine the coordinate system to be rigidly coupled to the pallet. With this in mind, we will use the term local coordinate system of the group. Corresponding to that term we will also refer to a reference coordinate system. The reference coordinate system is defined by the innermost container element (usually the parent group) or the innermost viewport. Now we need some criteria to qualify the arbitrary choice of our local coordinate system as advantageous or disadvantageous. For this we want a scene, in which we can insert some instances of the pallet.

Figure 6-8. Rack for pallets

We decide to use a rack similar to that we defined in the previous chapter ??. With regard to the red reference coordinate system there are three positions defined. These positions are the destined midpoint of each load. Since your boss has told you, to store three empty pallets at those locations, you start immediately with the lower left one, as it is the most easiest to handle.
<use xlink:href="#pallet" x="71" y="300" />

Figure 6-9. Put pallet in place

Ok, it would have been nice if it were so easy. Simply using the destination point coordinates causes our pallet sinking into the floor. But that might be no problem. We just have to calculate a little.
x_pallet = 71 width_of_pallet/2 y_pallet = 300 height_of_pallet

This should work now.

Learn SVG

Chapter 6 Coordinate system and Transformations

<use xlink:href="#pallet" x="5" y="285" />

Figure 6-10. It's better

Fine, but you do not appear very happy, as there are a lot of different sized pallets in this storage and you are in no mood to always calculate a lot. A way out of this could be to change the pallets specifications, so that its local origin lies in the lower midpoint. Sounds good, so you upgrade your pallet.
<g id="pallet" stroke="black" fill="tan" > <defs> <rect id="block" width="16" height="12" /> </defs> <rect x="-66" y="-15" width="132" height="3" /> <use xlink:href="#block" x="-66" y="-12" /> <use xlink:href="#block" x="-8" y="-12" /> <use xlink:href="#block" x="50" y="-12" /> </g>

With this the positioning of any pallet without calculation work should be possible.
<use xlink:href="#pallet" x="71" y="300" />

Figure 6-11. Better viewport for pallet

With the help of this illustrative example we realize, that the local origin is of great importance for handling group instances. We can imagine it as a grip point, with which we clutch the pallet and move it to the location we want it to be. It is now easy to place the other pallets as well provided that you are tall enough to reach the height. As you do not like to store empty pallets, you even put some load onto it.
<use xlink:href="#pallet" x="71" y="300" /> <use xlink:href="#pallet" x="371" y="0" /> <use xlink:href="#pallet" x="513" y="200" />

Learn SVG

Chapter 6 Coordinate system and Transformations

Figure 6-12. Some pallets in rack Select the local origin of a group deliberately. Comparing it with a grip point, with which to handle the group instances, might be of help.

Here is the complete code of the racks final document.


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="postBore" height="20" patternUnits="userSpaceOnUse"> <rect width="12" height="20" stroke="none" fill="steelblue" /> <circle cx="6" cy="10" r="2" stroke="none" fill="lightgray" /> </pattern> <g id="pallet" stroke="black" stroke-width="0.2" fill="tan" > <defs> <rect id="block" width="16" height="12" /> </defs> <rect x="-66" y="-15" width="132" height="3" /> <use xlink:href="#block" x="-66" y="-12" /> <use xlink:href="#block" x="-8" y="-12" /> <use xlink:href="#block" x="50" y="-12" /> </g> <g id="load"> <use xlink:href="#pallet" /> <rect x="-66" y="-85" width="132" height="70" stroke="black" stroke-width="1" /> </g> <g id="uprightPost" stroke="black" stroke-width="0.2" > <rect width="12" height="300" fill="url(#postBore)" /> </g> <g id="beam" stroke="black" stroke-width="0.2" fill="steelblue" > <rect x="3" y="0" width="278" height="10" /> <rect x="0" y="0" width="3" height="20" /> <rect x="281" y="0" width="3" height="20" /> </g> <g id="column"> <use xlink:href="#uprightPost" /> <use xlink:href="#beam" x="14" y="0" /> <use xlink:href="#beam" x="14" y="100" /> <use xlink:href="#beam" x="14" y="200" /> </g> <g id="rack"> <use xlink:href="#column" x="0" y="0" />

Learn SVG

Chapter 6 Coordinate system and Transformations

<use xlink:href="#column" x="300" y="0" /> <use xlink:href="#uprightPost" x="600" y="0" /> <line x1="-50" y1="301" x2="650" y2="301" stroke="black" fill="none" /> <rect x="-50" y="302" width="700" height="8" stroke="none" fill="lightgray" /> </g> </defs> <g transform="translate(100,150)" > <use xlink:href="#rack" x="-14" y="0" /> <use xlink:href="#load" x="71" y="300" fill="tomato" /> <use xlink:href="#load" x="371" y="0" fill="tomato" /> <use xlink:href="#load" x="513" y="200" fill="tomato" /> </g> </svg>

Elementary Transformations
We have learned now how to displace <use> elements by their x and y attributes and how to design the corresponding groups in order to do that quite comfortable. But a simple element displacement from one location to another cant be the end of the road. What if we want to rotate, mirror or change the size of an element? For this task the SVG specification gives us a very common powerful feature the transform attribute. That transform attribute can be applied to most graphics elements, i.e. elements, that cause graphics to be drawn onto the canvas. It can be applied as well to the <g> element. Here is the transform attributes syntax:
transform = "translate(tx [ ty]) rotate(angle [cx cy]) scale(sx [sy]) skewX(angle) skewY(angle)"

We will discuss the individual components of the transform attribute separately now. I prefer to illustrate the transformations with a more complex element, i.e. an <use> element referring to a group. But we do bear in mind that the transform attribute is applicable to the other graphics elements too. We will use the binding screw here for the subsequent examples. Assume that we defined the screws geometry regarding its red local coordinate system.

Figure 6-13. The screw and its coordinate system

Here is the code for our screw


<defs> <linearGradient id="zylinderShade" x2="0%" y2="50%" spreadMethod="reflect"> <stop offset="0%" stop-color="darkslategray"/> <stop offset="100%" stop-color="white"/> </linearGradient>

Learn SVG

Chapter 6 Coordinate system and Transformations

<g id="screw" stroke="black" stroke-linejoin="round" > <path fill="url(#zylinderShade)" d="M100,64 96,60 96,140 100,136 z M68,64 72,60 72,140 68,136 z M96,60 72,60 72,140 96,140 z" /> <path fill="url(#zylinderShade)" d="M100,84 220,84 220,116 100,116 z M220,84 220,116 224,112 224,88 220,84 z" /> <path stroke-width="0.4" fill="none" stroke-linecap="round" stroke-dasharray="24 12 4 12" d="M60,100 232,100" /> <path stroke-width="0.4" fill="none" stroke-linecap="round" d="M100,88 224,88 M100,112 224,112" /> </g> </defs>

If we simply instantiate the screws group via


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

the screws local coordinate system will coincide with the blue reference coordinate system. With this starting situation we will analyse now the effects of the individual components of the transform attribute. With that model it might become somewhat clearer, that we rather transform the coordinate system including the affiliated 2D-space with the screw here accidentally in it than simple graphics elements. Translate The translation is an elementary displacement transformation. Syntax:
translate(tx, ty) x-coordinate tx ty y-coordinate

of displacement of displacement

Here we apply the translate transformation to the screw groups instance, exactly to the local origin of this group.
<use xlink:href="#screw" transform="translate(100,130)" />

Learn SVG

Chapter 6 Coordinate system and Transformations

10

Figure 6-14. x and y attributes in use element

Easy, isnt it? So you might ask now what the difference of the translate transformation to the use of the x- and y- attributes is. Obviously seems
<use xlink:href="#screw" transform="translate(100,130)" />

to be identical to
<use xlink:href="#screw" x="100" y="130" />

Yes, you are right. So why do we need something complex like transforms? We will understand that later, when we had a look at the other elementary transforms and need to combine them. So please be patient and simply accept the necessity of the translate transformation for now. But we should also understand the effect of a combination of the x- and y- attributes and the translate transformation.
<use xlink:href="#screw" transform="translate(100,130)" x="130" y="-160" />

Learn SVG

Chapter 6 Coordinate system and Transformations

11

Figure 6-15. Translate the use element

The effect we have now, is that the screw is translated first to the coordinates (100,130) and subsequently displaced by (130,-160) to the end location (230,-30). To yield the end position of the elements local coordinate system formally we can simply add the coordinates as in Xlocal = tx + x ylocal = ty + y In this formulas we can exchange the addends without harm, i.e. Xlocal =x + tx ylocal =y + ty will give us the same result. But this means we can also exchange the coordinate values to
<use xlink:href="#screw" transform="translate(130,-160)" x="100" y="130" />

Learn SVG

Chapter 6 Coordinate system and Transformations

12

Figure 6-16. Put the screw at (230,-30)

As you see we yield the expected end position of (230,-30) here too. So we are not surprised to hear that the following elements produce identical output.
<use <use <use <use xlink:href="#screw" xlink:href="#screw" xlink:href="#screw" xlink:href="#screw" transform="translate(130,-160) translate(100,130)" /> transform="translate(100,130) translate(130,-160)" /> transform="translate(230,-30)" /> x="230" y="-30" />

It is quite simple but also somewhat confusing to use both the x- and y- attributes and the translate transformation. So it is best to avoid this generally, but there may be situations to use this effect deliberately as a benefit. Although the sequence of these both displacements is of no importance here, the SVG specification states:
The transform attribute is applied to an element before processing any other coordinate or length values supplied for that element.

With that we have a predefined sequence of perform the translate transformation. apply the x- and y- attributes. This was also taken into account with the examples above. Rotate The rotate transformation is used to rotate an element by a certain angle. Syntax:
rotate(angle [, cx, cy])

Learn SVG
angle cx cy

Chapter 6 Coordinate system and Transformations rotation angle in degrees, can be positive and negative x-center of rotation, optional y- center of rotation, optional

13

We apply that rotate transformation to our screw in its simplest form.


<use xlink:href="#screw" transform="rotate(25)" />

Figure 6-17. Rotate the screw

This results in a rotation around the blue origin yes it is the origin of the reference coordinate system the screw is rotated about, as well see later. The angles value 25 is given in degrees. The rotation occurs clockwise since we have a positive angles value. The mathematicians among you may cry out loud, because this is the mathematical negative direction. They are right when referring to a Cartesian coordinate system with the y-axis up. Since we have a coordinate system with its y-axis down, the positive rotation angle is directed clockwise. Now we want to explore the effect of using the other two parameters of the rotate transform. We write
<use xlink:href="#screw" transform="rotate(25, 100,100)" />

Learn SVG

Chapter 6 Coordinate system and Transformations

14

Figure 6-18. Rotate with center at (100,100)

With this we forced the screw to be rotated about the point (100,100) marked with the little blue pin. The coordinates of this pivot are in the reference coordinate system with the blue axes. So we learned about the rotate transformation: the rotation occurs about the reference systems origin by default if an additional pivot point (cx,cy) is given in reference systems coordinates, the rotation occurs about that point. the rotation angles value has to be provided in degrees. the rotation angle can be positive or negative. A positive value results in a clockwise rotation. With the rotate transformation the pivot coordinates only remain unchanged. This is also the transformation centre. a rotation angle of zero results in the identity transformation, i.e. the transformation, that leaves the element unaffected. The inverse rotation transformation to rotate(angle) is rotate(-angle),i.e. these transformations applied subsequently to an element leaves the element unaffected (identity transformation). Scale The scale transformation is used to change the size of an element. Syntax:
scale(sx [,sy]) x-scale factor sx sy y-scale factor,

optional

If we omit the y-scale factor, its value will be set equal to the value of the x-scale factor.
<use xlink:href="#screw" transform="scale(2)" />

As a result we now have a screw twice as large as the original. But it is not only enlarged, it has also changed its position. Instead of wondering about this effect any longer let us look at the screws local

Learn SVG

Chapter 6 Coordinate system and Transformations

15

coordinate system. We see now that the underlying grid as well as the coordinate axes are scaled also by a factor of 2. And with the recognition of the fact, that obviously every local coordinates value has been doubled we do understand now that the scaled screw also must seem to be translated. It isnt, it is simply scaled with respect to the origin the blue one.

Figure 6-19. Scale(2) the screw

Of course we can also reduce the size of our screw with


<use xlink:href="#screw" transform="scale(0.5)" />

For this we simply have to use values less than one. Here we also multiply every coordinate with the scale factor, so that those get smaller values.If we make the scale value smaller and smaller the screw will vanish into thin air, exactly into the worlds origin. Finally a scale factor of zero will reduce the screw to a single, dimensionless point. Thus preventing it from being rendered.

Figure 6-20. Scale(0.5) the screw

Until now we used only one scale factor. With this we speak about an uniform scaling, as we remember, that sy is set to the value of sx when omitted. What if we use two different scale factors now? We should consequently call this a non-uniform scaling.
<use xlink:href="#screw" transform="scale(1,0.5)" />

Learn SVG

Chapter 6 Coordinate system and Transformations

16

Figure 6-21. Scale(1,0.5) the screw

With this we reduced the screws dimensions in y-direction only. We can vary this of course with
<use xlink:href="#screw" transform="scale(0.5,1)" />

Figure 6-22. Scale(0.5,1) the screw

by shrinking the screw in x-direction only. As we understood this so far, you may ask what about negative values. No problem with this.
<use xlink:href="#screw" transform="scale(-1,1)" />

Figure 6-23. Scale(1,-1) the screw

Learn SVG

Chapter 6 Coordinate system and Transformations

17

With that we mirrored our screw at the y-axis. Or to explain it geometrically, we changed the sign of every x-coordinate by multiplying it by 1, so that we now have negative x-values for the screw. Of course we can also mirror about the x-axis by simply using
<use xlink:href="#screw" transform="scale(1,-1)" />

With the special case of


<use xlink:href="#screw" transform="scale(-1,-1)" />

we yield a reflection about the origin by a series of two consecutive mirroring transformations at the xaxis and the y-axis. This is identical to the result of a rotation about the origin by 180.
<use xlink:href="#screw" transform="rotate(180)" />

So we learned about the scale transformation: an element is scaled uniformly using the scale transformation with one single argument or two arguments with equal values. a scale factor greater than 1 will enlarge the element. a scale factor with a magnitude of less than 1 will reduce the size of the element. a scale factor of zero will prevent the element from being displayed. an element is scaled non-uniformly using the scale transformation with two different argument values. a scale factor sx = -1 results in mirroring at the y-axis. a scale factor sy = -1 results in mirroring at the x-axis. a scale transformation does usually not preserve lengths. a uniform scale transformation preserves angles, while a non-uniform doesnt. the centre of the scale transformation is exclusively the reference coordinate systems origin. Scale factors sx = 1 and sy = 1 results in the identity transformation. The inverse scale transformation to scale(sx,sy) is the transformation scale(1/sx,1/sy), i.e. scaling with inverse scaling factors. Skewing The skewing transformation frequently called shearing consists of two elementary transformations skewX and skewY. Syntax:
skewX(angle]) angle angular displacement of y-axis skewY(angle]) angle angular displacement of x-axis

We want to look at the skewY transformation first.


<use xlink:href="#screw" transform="skewY(25)" />

Learn SVG

Chapter 6 Coordinate system and Transformations

18

Figure 6-24. SkewY(25) the screw

We can interpret the skewY transformation as a rotation of the x-axis towards the positive y-axis, while leaving the y-axis direction as it is. It is also obvious now, that a skewing angle of 90 and greater is not allowed. The results for doing so are not defined. A negative angle results in a rotation in the opposite direction. Here also the angle must be greater than 90. The only line of the plane that remains unaffected by that transformation is the x-axis. The skewX transformation behaves similar with regard to the y-axis.

Figure 6-25. SkewX(25) the screw

Here we can understand the skewX transformation as a rotation of the y-axis towards the positive x-axis, while leaving the x-axis intact. But beware. The association of a rotation with the skewX and skewY transformation is somewhat misleading, since the resulting effect is a true shearing or skewing. As you can easily see above the skewX transformation results in a displacement of the x-coordinates only, not y-coordinates. the skewY transformation displaces y-coordinates only, x-coordinates remain unaffected. With this we can also understand the skewX transformation as a displacement of any point in the plane in the x-direction.

Learn SVG

Chapter 6 Coordinate system and Transformations

19

This displacement depends on the y-coordinate, i.e. points with greater y-values are displaced more than points with smaller y-values. To describe that mathematically, we can define the ratio kx = x y ;ky = y x

Finally there is a relation between those ratios and the angles

tan x = k x ; tan y = k y
As we also remember, that the tangent of 90 is infinite, we now understand, that a skew angle of 90 is not defined. Here we learned about the skewing transformation: an element can be skewed in x- and y-direction independently by the skewX and skewY transformation. the skew angle can be positive and negative, its value must be specified in degrees. the skew angles magnitude must not be greater or equal to 90. the skewX transformation only preserves lengths in x-direction. the skewY transformation only preserves lengths in y-direction. the skewing transformation does not preserve angles. the skewX transformations centre is the x-axis. the skewY transformations centre is the y-axis. the skew angle angle = 0 results in the identity transformation for skewX and skewY. The inverse transformation to skewX(angle) is the transformation skewX(-angle) (the same holds for skewY).

Concatenation of Transforms
Now that you know how the elementary transformations work you want to start transforming your elements. Translating, scaling, rotating and skewing them to your hearts content. You can do this quite comfortably, as the transform attribute is capable of holding more than one elementary transform. Syntax:
transform="trfN ... trf2 trf1" trf1 first elementary transform trf2 second elementary transform trfN Nth elementary transform

Fine, but we have to be cautious, because the sequence of the elementary transformations is of great importance.
The elementary transformations of the transform attribute are evaluated from right to left.

To introduce you into this we start with a small parts library.

Learn SVG

Chapter 6 Coordinate system and Transformations

20

Figure 6-26. Objects in library

Beside our screw we also have a nut group now. Both parts are geometrically described with respect to their red local coordinate systems. We must use these parts right now to bolt two plates together.

Figure 6-27. Two plates to bolt together

Here is the librarys code


<defs> <linearGradient id="zylinderShade" x2="0%" y2="50%" spreadMethod="reflect"> <stop offset="0%" stop-color="darkslategray"/> <stop offset="100%" stop-color="white"/> </linearGradient> <pattern id="hatch" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" stroke="none" fill="silver" /> <polyline points="0,10 10,0" stroke="gray" stroke-width="0.25"/> </pattern> <g id="screw" stroke="black" stroke-linejoin="round" > <path fill="url(#zylinderShade)" d="M0,-36 -4,-40 -4,40 0,36 z M-32,-36 -28,-40 -28,40 -32,36 z M-4,-40 -28,-40 -28,40 -4,40 z" /> <path fill="url(#zylinderShade)" d="M0,-16 120,-16 120,16 0,16 z M120,-16 120,16 124,12 124,-12 120,-16 z" /> <path stroke-width="0.4" fill="none" stroke-linecap="round" stroke-dasharray="24 12 4 12" d="M-40,0 132,0" /> <path stroke-width="0.4" fill="none" stroke-linecap="round" d="M0,-12 124,-12 M0,12 124,12" /> </g> <g id="nut" stroke="black" stroke-linejoin="round"> <path fill="url(#zylinderShade)" d="M0,-36 -4,-40 -4,40 0,36 z M-32,-36 -28,-40 -28,40 -32,36 z M-4,-40 -28,-40 -28,40 -4,40 z" /> <path fill="gray" d="M-4,-40 -28,-40 -28,-16 -4,-16 z" /> <path fill="silver" d="M-4,-16 -28,-16 -28,16 -4,16 z" /> <path fill="gray" d="M-4,16 -28,16 -28,40 -4,40 z" /> </g> <g id="plates"> <path id="upperPlate" fill="url(#hatch)" stroke="black" d="M10,100 81,100 81,120 10,120 12,116 9,113 11,111 9,107 12,104 8,101 z M81,100 119,100 M81,120 119,120 M119,100 290,100 290,120 119,120 z M290,100 310,100 M290,120 310,120 M310,100 380,100 380,120 310,120 z"/> <path id="lowerPlate" fill="url(#hatch)" stroke="black" d="M30,122 81,122 81,142 30,142 z M81,122 119,122 M81,142 119,142 M119,122 290,122 290,142 119,142 z M290,122 310,122 M290,142 310,142 M310,122 410,122 412,126 408,131 411,135 409,138 412,142 310,142 z"/>

Learn SVG

Chapter 6 Coordinate system and Transformations

21

<path stroke="black" stroke-width="0.4" fill="none" stroke-dasharray="12 6 2 6" d="M100,90 100,150 M300,90 300,150" /> <path stroke="black" stroke-width="0.5" fill="none" d="M100,100 120,80 M300,100 320,80" /> <text x="120" y="80" text-anchor="start">(100, 100)</text> <text x="320" y="80" text-anchor="start">(300, 100)</text> </g> </defs>

The plates geometry is defined with respect to the blue reference coordinate system. We start with the first screw in order to stick it into the first hole. To bring it into the drawing, we simply instance it by
<use xlink:href="#screw" />

Figure 6-28. The plates and the screw

Without a transformation the screw is positioned so, that its red local coordinate system coincides with the blue reference coordinate system. Fine, all we have to do now, is simply rotate the screw by 90 degrees. translate the screw at its destination coordinates (100,100). Ok, we remember that the elementary transformations are performed right to left, so we write
<use xlink:href="#screw" transform="translate(100,100) rotate(90)" />

Figure 6-29. The screw in place

Learn SVG

Chapter 6 Coordinate system and Transformations

22

It works. Despite the fact, that it seems to be so easy, we should have a look under the transformations hood. Here is a stop motion picture of the transforming procedure.

Figure 6-30. Transformations to put in place the screw

The first transformation process was to rotate the screw by 90. Hereafter we translated the screws local origin onto the point (100,100). As I told you, that the transformations order is important, lets simply interchange that order as an experiment. Now we translate first and rotate the screw subsequently.
<use xlink:href="#screw" transform="rotate(90) translate(100,100)" />

Figure 6-31. Steps for transformation

With this we miss the hole. Maybe we implied a rotation about the screws local red origin, but the rotation definitely occurred about the reference coordinate systems blue origin. That wrong presumption is in fact a popular beginners fault, so I need to stress here again:
The default centre of an elements rotate transformation is the origin of the parent elements reference coordinate system.

Learn SVG

Chapter 6 Coordinate system and Transformations

23

You might remember, that there were two more default arguments with the rotate transformation. We can use these to set the pivot point of the rotation explicitly. Then we can leave the transformations order as it is.
<use xlink:href="#screw" transform="rotate(90, 100,100) translate(100,100)" />

Now we can practice what we learned with the assembly of our nut. Rotate about the coinciding local and reference origin by 90 Translate onto the desired location at point (100,142).

Figure 6-32. Plates are bolted

<use xlink:href="#femaleScrew" transform="translate(100,142)

rotate(-90)"

/>

or again alternatively
<use xlink:href="#femaleScrew" transform="rotate(-90, 100,142) translate(100,142)" />

works fantastically, although the screw looks somewhat oversized. You want to start to assemble the other screw immediately, as you suddenly realise, that the holes diameter is half as wide as the previous ones. After looking quite helplessly at our screw and nut groups for a short period of time you prudently suggest to make some smaller ones. Yes, of course. We do not have only one screw of a given size. We have an infinite number of screws with different sizes each thanks to SVGs powerful scale transformation. So how should we start? To make a screw of half the size simply means to scale it down uniformly via scale(0.5). But we still have to rotate and translate also. So what transformation order should we apply here we are really extremely sensible with this now. As a precaution we reread the chapter about scaling above. Here it is. The centre of the scaling transformation is the reference coordinate systems origin. Since the screws local origin coincides with

Learn SVG

Chapter 6 Coordinate system and Transformations

24

the reference systems initially, we can start blindly with the scale transformation followed by the now familiar pair of rotate and translate transform.
<use xlink:href="#screw" transform="translate(300,100) rotate(90) scale(0.5)" />

Figure 6-33. Another screw in place

It obviously works as expected. With this success you decide lionhearted to permute the order of scaling and rotation with the nut.
<use xlink:href="#nut" transform="translate(300,142) scale(0.5) rotate(-90) " />

Figure 6-34. The two screws in place

Well, this way also works fine. Though it is no surprise, as both the scale and the rotate transformation have an identical centre. But you should also note:
You can arbitrarily change the subsequent order of uniform scale and rotate transformations with respect to the origin. But you cannot do that with the subsequent order of non-uniform scale and rotate transforms.

Learn SVG

Chapter 6 Coordinate system and Transformations

25

Just to show you the correctness of the last sentence regarding the non-uniform scale, we will simply proof that by example.
<use xlink:href="#screw" transform="scale(0.5,1) rotate(90)" /> <use xlink:href="#screw" transform="rotate(90) scale(0.5,1)" />

Figure 6-35. Order for transformations

Still heavily impressed by the enormous number of different screw sizes available, you are meditating, if it would be possible to have two screws of the same size but different thread lengths. Here I must tell you that we cant do this with SVG 1.0 based on a single group. But the wise W3C is busy all the time and Im quite sure we get a basketfull of surprises with SVG 2.0. I dont withhold the SVG code of the final screw document from you.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <!-- screw, nut and plates group go here --> </defs> <g transform="translate(60,60)"> <use xlink:href="#plates" /> <use xlink:href="#screw" transform="translate(100,100) rotate(90)" /> <use xlink:href="#nut" transform="translate(100,142) rotate(-90)" /> <use xlink:href="#screw" transform="translate(300,100) rotate(90) scale(0.5)" /> <use xlink:href="#nut" transform="translate(300,142) scale(0.5) rotate(-90) " /> </g> </svg>

Nesting of Transformations
Until here we discussed the application of multiple transforms to a single element. So we now need to analyse, how the transformation of container elements influence the contained elements. Furthermore we will consider transformed instances of transformed elements or groups.

Learn SVG

Chapter 6 Coordinate system and Transformations

26

Figure 6-36. Two squares and one circle


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <rect id="inner" width="200" height="200" fill="seagreen" transform="rotate(45) translate(-100,-100)" /> </defs> <g transform="translate(300,200)"> <rect width="100" height="100" fill="navy" stroke-width="2" transform="scale(2) translate(-50,-50)" /> <circle r="100" stroke="none" fill="tomato" /> <use xlink:href="#inner" transform="scale(0.707)" /> </g> </svg>

We have three elements in this SVG document (coordinates text omitted) two squares and one circle. The navy square is defined with its upper left corner being (0,0) and then translated so that its centre point coincides with the origin. After that it is uniformly enlarged by the factor 2. The tomato coloured circle has a centre point of (0,0) so that it also coincides with the origin. The seagreen square is defined in the defs section. It has originally twice the size as the navy one. It is also then translated so that its centre point coincides with the origin. Then it is rotated about the origin by 45. At least it is reused by an use element and scaled down by 0.707 so that it fits into the circle. All three elements are finally placed into a group by which they are transformed to the centre point of the document (300,200). We will focus on the sequence of these different transforms and analyse, how we can create the same image with a simple flat element structure, i.e. not using.<defs>, <g> and <use> elements. We start with the tomato coloured circle. To pull it out of its parent group, we simply have to apply the groups transformation directly to the circle element instead. <circle r="100" stroke="none" fill="tomato" transform="translate(300,200)" />

Learn SVG

Chapter 6 Coordinate system and Transformations

27

Figure 6-37. Translated circle

That was quite easy. We advance to the navy square. This rectangle has its own transformation defined. In order to extract it from its parent group, we have to apply the groups transformation also to the rectangle. And we have to apply the groups transformation after the elements own. <rect width="100" height="100" fill="navy" stroke-width="2" transform="translate(300,200) scale(2) translate(-50,-50)" />

Figure 6-38. Circle in a square

With that we can generalise for nested transformed groups. <g transform="t3"> <g transform="t2"> <g transform="t1"> <element transform="t0" /> </g> </g> </g> The overall resulting element transformation can be composed of the individual group transformations as follows <element transform="t3 t2 t1 t0" /> Well compose the parent groups transformations from inside out. That is, these are applied after (appended from the left to) the elements transformation. We can also think here in terms of inheritance (similar to CSS style inheritance) and state as a general rule:
An element inherits the transformation of its parent element so that the inherited transform is applied after the elements transform.

Learn SVG

Chapter 6 Coordinate system and Transformations

28

Now lets consider the seagreen square finally. In a first step we want to eliminate the <use> element. In order to preserve the <rect> elements visual appearance (overall transformation), we need to apply the <use> elements transformation to the <rect> element itself. <rect id="inner" width="200" height="200" fill="seagreen" transform=" scale(0.707) rotate(45) translate(-100,-100)" /> Please note, that we have to apply the <use> elements transformation after the elements transformation. Now we need to extract the seagreen square from its enclosing group. We are quite familiar with that, since we did exactly that with the circle and the navy square before. <rect id="inner" width="200" height="200" fill="seagreen" transform=" translate(300,200) scale(0.707) rotate(45) translate(-100,-100)" />

Figure 6-39. The three objects

With that we can also generalise for instances of elements (and groups). <element id="e0" transform="t0" /> <use id="e1" xlink:href="#e0" transform="t1" /> <use id="e2" xlink:href="#e1" transform="t2" /> <use id="e3" xlink:href="#e2" transform="t3" /> This is identical to <element id="e3" transform="t3 t2 t1 t0" /> where the uses transformation is applied after (appended left to) the reused elements transformation. We can here too think in terms of inheritance and state as another general rule:
The particular instance of a reused element inherits the transformation of its corresponding use element so that the inherited transform is applied after the elements transform.

The flat version of our document produces the same graphical output and reads finally.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" fill="navy" stroke-width="2" transform="translate(300,200) scale(2) translate(-50,-50)"/> <circle r="100" stroke="none" fill="tomato" transform="translate(300,200)" /> <rect id="inner" width="200" height="200" fill="seagreen" transform="translate(300,200) scale(0.707) rotate(45) translate(-100,-100)" />

Learn SVG
</svg>

Chapter 6 Coordinate system and Transformations

29

Now you might be surprised that we can use this quite theoretically stuff elegantly for a refreshing piece of computer art. For this we start with a simple triangle.
<?xml version="1.0" ?> <svg width="600" height="400"> <defs> <polygon id="e0" fill="navy" points="0,0 200,0 100,-200" /> </defs> <use xlink:href="#e0" transform="translate(200,300)" /> </svg>

Figure 6-40. A triangle


Now we reuse this triangle three times, while we scale it down by the factor 0.5 and position it at the corners of the now unused original triangle.

<?xml version="1.0" ?> <svg width="600" height="400"> <defs> <polygon id="e0" fill="navy" points="0,0 200,0 100,-200" /> <g id="e1"> <use xlink:href="#e0" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e0" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e0" transform="translate(50,-100) scale(0.5)" /> </g> </defs> <use xlink:href="#e1" transform="translate(200,300)" /> </svg>

Learn SVG

Chapter 6 Coordinate system and Transformations

30

Figure 6-41. First step

We repeat this transformation by simply copying the group e1 multiple times and incrementing the id names in each.

<?xml version="1.0" ?> <svg width="600" height="400"> <defs> <polygon id="e0" fill="navy" points="0,0 200,0 100,-200" /> <g id="e1"> <use xlink:href="#e0" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e0" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e0" transform="translate(50,-100) scale(0.5)" /> </g> <g id="e2"> <use xlink:href="#e1" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e1" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e1" transform="translate(50,-100) scale(0.5)" /> </g> <g id="e3"> <use xlink:href="#e2" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e2" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e2" transform="translate(50,-100) scale(0.5)" /> </g> <g id="e4"> <use xlink:href="#e3" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e3" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e3" transform="translate(50,-100) scale(0.5)" /> </g> <g id="e5"> <use xlink:href="#e4" transform="translate(0,0) scale(0.5)" /> <use xlink:href="#e4" transform="translate(100,0) scale(0.5)" /> <use xlink:href="#e4" transform="translate(50,-100) scale(0.5)" /> </g> </defs> <use xlink:href="#e5" transform="translate(200,300)" /> </svg>

Learn SVG

Chapter 6 Coordinate system and Transformations

31

Figure 6-42. More steps

With these boring transformations we have created a well known fractal the Sierpinski Triangle. If you want to learn more about these beautiful self-similar fractals, you can surf the web and type iterated function systems, IFS or simply fractals in your favourite search engine.

Transformation Matrices
Before you start reading this chapter, you should know that you not necessarily need to use this kind of transform. But if you want to use the matrix transform with scripting for performance reasons or simply want to understand how it works, this chapter is for you. So you might have noticed that we omitted a particular transformation type the matrix transform. Syntax:
matrix(a, b, c, d, e, f) a, b, c, d, e, f

matrix components as real numbers

Lets refer to the screw example again and do the transformations this time with matrices.

Learn SVG

Chapter 6 Coordinate system and Transformations

32

Figure 6-43. The plates and the screws <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <defs> <!-- screw, nut and plates group go here --> </defs> <g transform="translate(60,60)"> <use xlink:href="#plates" /> <use xlink:href="#screw" transform="matrix(0,1,-1,0,100,100)" /> <use xlink:href="#nut" transform="matrix(0,-1,1,0,100,142)" /> <use xlink:href="#screw" transform="matrix(0,0.5,-0.5,0,300,100)" /> <use xlink:href="#nut" transform="matrix(0,-0.5,0.5,0,300,142)" /> </g> </svg>

In order to fully understand this, we need to do some vector mathematics here. A matrix is a rectangular array of real numbers. The matrices here in SVG context are 3x3 matrices suited to transform coordinates.
x' a c y' = b d 1 0 0 e x f y 1 1

The 2-dimensional coordinates are expanded by an additional 1 to three vector components. With this concept of the so called homogenous coordinates we are allowed to perform the translation which is additive by nature - also per matrix/vector multiplication. The components in the first two rows of the matrix are the components of the matrix transform. Since the last row is always (0 0 1), we can omit it. Before discussing these components and compare them to the elementary transformations we already know, let us have a quick look at how the matrix/vector multiplication is performed.
x' a x + c y + e y' = b x + d y + f 1 1

With this a new point (x,y) results from another point (x,y) by the calculation (ax+cy+e, bx+dy+f), where a,b,c,d,e,f are the constant matrix elements. With this we have linear functions in the coordinates. Transformations that have this linear characteristic are called affine transformations.
Translation Matrix

Learn SVG

Chapter 6 Coordinate system and Transformations

33

The translation matrix looks like this


1 0 tx Ttrans = 0 1 t y 0 0 1 where tx and ty., the displacement in x- and y-direction, are exactly the same values we have to supply to the translate(tx,ty) transform.

Rotation Matrix The rotation matrix needs some trigonometric functions

Trotate

cos = sin 0

sin cos 0

0 0 1

where alfa is the rotation angle. Please note, that the angles value must be supplied in radians here. This is contrary to the rotate transform, where we need the angle in degrees. We can simply convert an angle from degrees into radians via

= angle

180

Scaling Matrix

Tscale

sx =0 0

0 sy 0

0 0 1

The scale factors sx and sy.are identical to the factors we will use with scale(sx,sy) transform.
Shearing Matrix
1 tan = 0 1 0 0 0 1 0 ; TskewY = tan 0 1 0 0 1 0 0 1

TskewX

The skew factor tan(alfa) for the transformation matrices must be calculated from the skewing angle of the skewX(angle) and skewY(angle) transform via the tangent function.
Concatenate Transform Matrices Transformations can be concatenated by multiplying their matrices. Since matrix multiplication is not commutative, i.e. the matrices cannot be interchanged, it is important that the matrices be composed in the correct order. The matrix multiplication has to be performed as follows.
a1 T = b1 0 e1 a 2 f1 b2 1 0 e2 a1 a 2 + c1 b2 f 2 = b1 a 2 + d 1 b2 1 0 a1 c2 + c1 d 2 b1 c2 + d 1 d 2 0 a1 e2 + c1 f 2 + e1 b1 e2 + d 1 f 2 + f1 1

c1 d1 0

c2 d2 0

Learn SVG

Chapter 6 Coordinate system and Transformations

34

Multiplying a vector with multiple matrices must be performed from right to left.
x ' a1 y ' = b1 1 0 c1 d1 0 e1 a 2 f1 b2 1 0 c2 d2 0 e2 x f2 y 1 1

This means that the rightmost transformation matrix represents the first transformation to be applied, while the leftmost matrix represents the last transformation to be applied. This is also the reason for the right-to-left evaluation of the elementary transformations of the transform attribute. That means also, if we want to transform an element that still has some transformations applied to it, we must post-multiply the new transformation matrix, that is append it to the left of the previously applied transformation matrices.
Matrix Example

Now lets practice that theoretical stuff with the small screw of our screw example.

Figure 6-44. Using matrix to put screw in place

We transformed the screw with


<use xlink:href="#screw" transform="translate(300,100) rotate(90) scale(0.5)" />

We create and compose the corresponding matrices in exactly the same order
1 0 300 cos 90 sin 90 0 0.5 0 0 T = 0 1 100 sin 90 cos 90 0 0 0.5 0 0 0 1 0 0 1 0 0 1

As we remember, that sin 90 = 1 and cos 90 = 0, we can simplify the middle matrix somewhat. 1 0 300 0 1 0 0.5 0 0 T = 0 1 100 1 0 0 0 0.5 0 0 0 1 0 0 1 0 0 1

Learn SVG

Chapter 6 Coordinate system and Transformations

35

Now we can start to multiply the matrices. You might be astonished, that I tell you that it doesnt matter, if we start from left or from right. So please note, only the order of the matrices is important, not the evaluation order. We choose to start from the left, leaving the multiplication from the right for your exercise . Multiplication of the two left matrices yields
0 1 300 0.5 0 0 T = 1 0 100 0 0.5 0 0 0 1 0 0 1

Now we multiply the remaining matrices


0 0.5 300 T = 0 .5 0 100 0 0 1

and get the resulting matrix. We remember SVGs matrix notation


a c T = b d 0 0 e f 1

in combination with the transform attribute


matrix(a, b, c, d, e, f)

With this we can now write the transform attribute in matrix notation
<use xlink:href="#screw" transform="matrix(0,0.5,-0.5,0,300,100)" />

Easy isnt it? You might ask now, why you should do such a lot calculation. Here is the answer:
SVG renderers usually convert transformation attributes into internal transformation matrices. So the use of the matrix transform attribute results in the best possible performance.

I recommend, to consider using the matrix transform attribute, if you automatically generate svg documents (server-side or client-side) or manipulate the transform attribute by SMIL animation.

Chapter 7 : Filling the picture


Opacity
Extract of svg specifications "There are several opacity properties within SVG:

Fill opacity Stroke opacity Gradient stop opacity Object/group opacity (described here)

Except for object/group opacity, all other opacity properties are involved in intermediate rendering operations. Object/group opacity can be thought of conceptually as a postprocessing operation. Conceptually, after the object/group is rendered into an RGBA offscreen image, the object/group opacity setting specifies how to blend the offscreen image into the current background." Any values outside the range 0.0 (fully transparent) to 1.0 (fully opaque) will be clamped to this range. Fill opacity and stroke opacity We can affect opacity for filling or stroking any element as shape, text .... 'fill-opacity' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: 'stroke-opacity' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

<opacity-value> | inherit 1 shapes and text content elements yes N/A visual yes

<opacity-value> | inherit 1 shapes and text content elements yes N/A visual yes

Learn SVG

Chapter 7 Filling the Shape

We can use
<rect x="0" y="0" width="200" height="200" fill-opacity="0.5" fill="red"/>

or
<rect x="0" y="0" width="200" height="200" style="fill-opacity:0.5;fill:red"/>

For opacity less than 1, result depend of background color. We create background with strips of color, we can see result of fill-opacity="0.5" for a rectangle in Figure 7-1. Source of svg file ( Example 7-1 ) :
<svg width="600" height="110" viewBox="-25 -30 600 110"> <rect x="0" y="0" width="50" height="50" style="fill:black;fill-opacity:1"/> <rect x="50" y="0" width="50" height="50" style="fill:black;fill-opacity:0.9"/> <rect x="100" y="0" width="50" height="50" style="fill:black;fill-opacity:0.8"/> <rect x="150" y="0" width="50" height="50" style="fill:black;fill-opacity:0.7"/> <rect x="200" y="0" width="50" height="50" style="fill:black;fill-opacity:0.6"/> <rect x="250" y="0" width="50" height="50" style="fill:black;fill-opacity:0.5"/> <rect x="300" y="0" width="50" height="50" style="fill:black;fill-opacity:0.4"/> <rect x="350" y="0" width="50" height="50" style="fill:black;fill-opacity:0.3"/> <rect x="400" y="0" width="50" height="50" style="fill:black;fill-opacity:0.2"/> <rect x="450" y="0" width="50" height="50" style="fill:black;fill-opacity:0.1"/> <rect x="500" y="0" width="50" height="50" style="fill:black;fill-opacity:0"/> <rect x="20" y="10" width="510" height="30" style="fill:yellow;fill-opacity:0.5"/> </svg>

Figure 7-1. Rectangle with 0.5 as fill-opacity on strips

Gradient stop opacity

Learn SVG

Chapter 7 Filling the Shape

See below about gradients Object/group opacity 'opacity' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

<alphavalue> | inherit 1 container elements and graphics elements no N/A visual yes

Figure 7-2 show that if opacity of 0.5 apply to group, yellow circle cover red circle and then opacity of group apply to rendered raster. If opacity apply to each circle, we get common part of circles in orange. Source for svg file (Example 7-2 ) :
<svg width="450" height="250" viewBox="-25 -25 450 250"> <g opacity="0.5"> <circle cx="75" cy="100" r="50" fill="red" fill-opacity="1"/> <circle cx="125" cy="100" r="50" fill="yellow" fill-opacity="1"/> </g> <g> <circle cx="275" cy="100" r="50" fill="red" fill-opacity="0.5"/> <circle cx="325" cy="100" r="50" fill="yellow" fill-opacity="0.5"/> </g> <text x="100" y="180" style="text-anchor:middle"> opacity on group </text> <text x="300" y="180" style="text-anchor:middle"> opacity on elements </text> </svg>

Figure 7-2. Opacity on group or on elements

Learn SVG

Chapter 7 Filling the Shape

Gradients
Gradients are used to fill or stroke basic shapes, paths or text elements, using many colors with color transitions from one to other. Colors in gradients or gradients stop elements This is the syntax for the stop element : <stop id="name" offset="NumberOrPercentage" stop-color="Color" stop-opacity="Opacity-value" />

Diagram 7-1. Chart for 'stop' syntax

Values for offset are from 0% to 100% or from 0 to 1. For each stop element, offset must be equal to or greater than the previous stop's offset value. Gradient offset values less than 0 (or less than 0%) are rounded up to 0%. Gradient offset values greater than 1 (or greater than 100%) are rounded down to 100%. How understand offset attribute ? To begin, we create linear gradient with two colors only. Colors are defined in stop elements.
<defs> <linearGradient id="MyGradient"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> </defs>

We create also radial gradient with same 'stop' elements :


<defs> <radialGradient id="MyGradient"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient>

Learn SVG
</defs>

Chapter 7 Filling the Shape

For linear gradients, the offset attribute represents a location along the gradient vector. For radial gradients, it represents a percentage distance from (fx,fy) to the edge of the outermost/largest circle. We can see result in Figure 7-3.

Figure 7-3. How work offset for stop element

In linear gradient, to fill shape, red is used from begin to 30% of total length, yellow is used from 70% to end. From 30% to 70%, color goes smoothly from red to yellow. We go from red ( rgb(255,0,0) ) to yellow ( rgb(255,255,0) ), so colors at x% of gradient vector is rgb(255,y,0) with y = 255 * (x 30 ) / 40. For radial gradient 'offset' apply to radius of circles ( we can choose center of circles see after ) To fill shape, red is used for circle with radius of 30% of area's radius , yellow is used from 70% to end. From 30% to 70%, color goes smoothly from red to yellow. Figure 7-4 show some values for offset in linear gradient. For 0 and 100, all rectangle is filled with continuously smooth color transitions from red to yellow. For 50 and 50, we get only red for left part and yellow for right part. Source of svg file ( Example 7-4 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient>

Learn SVG

Chapter 7 Filling the Shape

<linearGradient id="MyGradient2"> <stop offset="20%" stop-color="red"/> <stop offset="80%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient3"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient4"> <stop offset="50%" stop-color="red"/> <stop offset="50%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">Offset 0 and 100</text> <text x="225" y="175" style="text-anchor:middle">Offset 20 and 80</text> <text x="375" y="175" style="text-anchor:middle">Offset 30 and 70</text> <text x="525" y="175" style="text-anchor:middle">Offset 50 and 50</text> <g style="stroke-dasharray:2 2;stroke:black"> <path d="M180 0l0 150"/> <path d="M270 0l0 150"/> <path d="M0 0l0 150"/> <path d="M150 0l0 150"/> <path d="M345 0l0 150"/> <path d="M405 0l0 150"/> <path d="M525 0l0 150"/> <path d="M525 0l0 150"/> </g> </svg>

Figure 7-4.

Some values for offset in linearGradient element

We get this effects with radial gradient in Figure 7-5 for different values of offset attributes. Source of svg file ( Example 7-5 ) :

Learn SVG

Chapter 7 Filling the Shape

<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <radialGradient id="MyGradient1"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </radialGradient> <radialGradient id="MyGradient2"> <stop offset="20%" stop-color="red"/> <stop offset="80%" stop-color="yellow"/> </radialGradient> <radialGradient id="MyGradient3"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </radialGradient> <radialGradient id="MyGradient4"> <stop offset="50%" stop-color="red"/> <stop offset="50%" stop-color="yellow"/> </radialGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">Offset 0 and 100</text> <text x="225" y="175" style="text-anchor:middle">Offset 20 and 80</text> <text x="375" y="175" style="text-anchor:middle">Offset 30 and 70</text> <text x="525" y="175" style="text-anchor:middle">Offset 50 and 50</text> <g style="stroke-dasharray:2 2;stroke:black;fill:none"> <circle cx="75" cy="75" r="0"/> <circle cx="75" cy="75" r="75"/> <circle cx="225" cy="75" r="15"/> <circle cx="225" cy="75" r="60"/> <circle cx="375" cy="75" r="22"/> <circle cx="375" cy="75" r="52"/> <circle cx="525" cy="75" r="37.5"/> <circle cx="525" cy="75" r="37.5"/> </g> </svg>

Figure 7-5.

Some values for offset in radialGradient element

Learn SVG

Chapter 7 Filling the Shape

Other attributes With stop-color we choose color used ( name, RGB or hexadecimal value ). It's not possible to choose "none", but with any color and stop-opacity="0" we get same result. We can use this to get transparency effect or 3D lighting with filters on gradient. 'stop-color' property Value: currentColor |<color> [icc-color(<name>[,<icccolorvalue>]*)] | inherit Initial: black Applies to: 'stop' elements Inherited: no Percentages: N/A Media: visual Animatable: yes

With stop-opacity we choose opacity for color from 0 to 1. 'stop-opacity' property Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: <alphavalue> | inherit 1 'stop' elements no N/A visual yes

Rendering properties For gradients, one property is important : 'color-interpolation'. By default, 'color-interpolation' has value 'sRGB' 'color-interpolation' property Value: Initial: Applies to: Inherited: Percentages: auto | sRGB | linearRGB | inherit sRGB container elements, graphics elements and 'animateColor' yes N/A

Learn SVG

Chapter 7 Filling the Shape

Media: visual Animatable: yes 'auto' means that author doesn't require that color interpolation occur in a particular color space . We can see on this example ( Figure 7-6 ) that to go from red to yellow, repartition of colors is not the same with 'sRGB' and 'linearRGB'.

Figure 7-6. 'color-interpolation' property value

Common attributes for linear and radial gradients gradientUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x1 y1 x2 y2 for linearGradient and cx cy r fx fy for radialGradient. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the gradient is applied. In this case, it's more easy to use percentages for attributes. You can see after for linearGradient that this choice give different results on a square and a rectangle by example. gradientTransform allow to add transform to coordinate system. We can use translate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a b c d e f).

Learn SVG

Chapter 7 Filling the Shape

Figure 7-7 show three transforms applied to linearGradient element. Source of svg file ( Example 7-7 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient2" gradientTransform="rotate(45)"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient3" gradientTransform="scale(0.5)"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient4" gradientTransform="skewX(45)"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">identity</text> <text x="225" y="175" style="text-anchor:middle">rotate(45)</text> <text x="375" y="175" style="text-anchor:middle">scale(0.5)</text> <text x="525" y="175" style="text-anchor:middle">skewX(45)</text> </svg>

Figure 7-7. Three transforms applied to linearGradient element

spreadMethod attribute can be pad, reflect or repeat. This attribute indicates what happens if the gradient starts or ends inside the bounds of the target rectangle. With pad, default value, first or last color is used to complete before begining or after end of gradient.

Learn SVG 10

Chapter 7 Filling the Shape

With reflect, gradient is used start to end, then end to start , start to end ... to fill the rectangle. With repeat, gradient is used start to end, start to end ... to fill the rectangle. To see effect of this attribute, we define this linear gardient:
<defs> <linearGradient id="MyGradient" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> </defs>

With this values for x1 y1 x2 and y2, gradient start at 20% of shape and end at 50%. Figure 7-8 show effect of spreadMethod attribute, by default or with "pad" value, red is used from 0% to 20% and yellow from 50% to 100%. With reflect and repeat, we can see how gradient is used to fill the rectangle. Source of svg file ( Example 7-8 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient2" spreadMethod="pad" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient3" spreadMethod="reflect" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient4" spreadMethod="repeat" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="30%" stop-color="red"/> <stop offset="70%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">default</text> <text x="225" y="175" style="text-anchor:middle">pad</text> <text x="375" y="175" style="text-anchor:middle">reflect</text> <text x="525" y="175" style="text-anchor:middle">repeat</text> </svg>

Learn SVG 11

Chapter 7 Filling the Shape

Figure 7-8. Different values for spreadMethod attribute

How apply gradient to shape ? We define gradient in <defs> section and give id, here "MyGradient" to linearGradient element.
<defs> <linearGradient id="MyGradient" x1="20%" y1="0%" x2="50%" y2="0%"> <stop offset="10%" stop-color="red"/> <stop offset="90%" stop-color="yellow"/> </linearGradient> </defs>

We can use this gradient to fill or stroke any element, as basic shape, path, text. This rectangle will be filled with linear gradient :
<rect x='0' y='0' width='200' height='200' fill='url(#MyGradient)'/>

We can also use style attribute :


<rect x='0' y='0' width='200' height='200' style='stroke:black;fill:url(#MyGradient)'/>

Figure 7-9 show some examples for using linear gradient to fill or stroke svg elements. Source of svg file ( Example 7-9 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1" x2="5%" spreadMethod="reflect"> <stop offset="10%" stop-color="red"/> <stop offset="90%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="stroke:black;fill:url(#MyGradient1)"/> <circle cx="225" cy="75" r="60" style="fill:none; stroke-width:10;stroke:url(#MyGradient1)"/> <path d="M320 20l 70 0 0 60 20 50 -100 0z" style="stroke:black;fill:url(#MyGradient1)"/>

Learn SVG 12

Chapter 7 Filling the Shape

<text x="525" y="100" style="stroke:black;fill:url(#MyGradient1); font-family:Balloon;text-anchor:middle;font-size:100">SVG</text> <text x="75" y="175" style="text-anchor:middle">fill rectangle</text> <text x="225" y="175" style="text-anchor:middle">stroke circle</text> <text x="375" y="175" style="text-anchor:middle">fill path</text> <text x="525" y="175" style="text-anchor:middle">fill text</text> </svg>

Figure 7-9. Examples using gradient

Linear Gradients This is the syntax for the linearGradient element : <linearGradient id="name" gradientUnits="userSpaceOnUse|objectBoundingBox" gradientTransform="transform-list" spreadMethod="pad|repeat|reflect" x1="NumberOrPercentage" y1="NumberOrPercentage" x2="NumberOrPercentage" y2="NumberOrPercentage"> <!-- stop elements --> </linearGradient>

Learn SVG 13

Chapter 7 Filling the Shape

Diagram 7-2. Chart for 'linearGradient' syntax

Figure 7-10 show results for three values of attribute "spreadMethod". In this exemple, x1="10%" and x2="40%".

Figure 7-10. Attributes for linearGradient

Learn SVG 14

Chapter 7 Filling the Shape

x1 y1 x2 y2 attributes define vector for linear gradient. This vector provides starting and ending points onto which the gradient stops are mapped. Colored strips are perpendicular to this vector. Default values are 0% 0% 100% 0% Figure 7-11 show four examples : vertical strips with default values 0 0 100 0, 0 x 100 x will give same result diagonally strips with 0 0 100 100 from upper left corner to lower right corner diagonally strips with 0 100 100 0 from lower left corner to upper right corner horizontal strips with 0 0 0 100, x 0 x 100 will give same result. Source of svg file ( Example 7-11 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient2" x1="0%" y1="0%" x2="100%" y2="100%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient3" x1="0%" y1="100%" x2="100%" y2="0%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient4" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">0 0 100 0</text> <text x="225" y="175" style="text-anchor:middle">0 0 100 100</text> <text x="375" y="175" style="text-anchor:middle">0 100 100 0</text> <text x="525" y="175" style="text-anchor:middle">0 0 0 100</text> </svg>

Learn SVG 15

Chapter 7 Filling the Shape

Figure 7-11. Different values for x1 y1 x2 y2

Effect of x1, y1, x2 and y2 with gradientUnits="objectBoundingBox" depend of filled object. Result is not the same on a square and a rectangle. For a rectangle, coordinate system is not orthogonal and strips of color are perpendicular to gradient vector in calculus in this system, but not in common sense.

Figure 7-12. gradientUnits and shapes

By example, in Figure 7-12, we use same gradient for gradientUnits = "objectBoundingBox" with x1="0%" y1="0%" x2="100%" and y2="100%". Stop elements offset are 20% and 80%, we draw limits of colors. If we want same orientation on the two shapes, we must use gradientUnits = "userSpaceOnUse" and define a gradient for each shape with different values for x1, y1, x2 and y2. We have same problem using gradientTransform.

Learn SVG 16

Chapter 7 Filling the Shape

Figure 7-13 allow comparison using x1 y1 x2 y2 or gradientTransform : Source of svg file ( Example 7-13 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <linearGradient id="MyGradient1" x1="0%" y1="0%" x2="100%" y2="100%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient2" gradientTransform="rotate(45)"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient3" x1="0%" y1="100%" x2="100%" y2="0%"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="MyGradient4" x1="450" y1="150" x2="600" y2="150" gradientTransform="rotate(-45,450,150)"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle">0 0 100 100</text> <text x="225" y="175" style="text-anchor:middle">rotate(45)</text> <text x="375" y="175" style="text-anchor:middle">0 100 100 0</text> <text x="525" y="175" style="text-anchor:middle">rotate(-45)</text> </svg>

Figure 7-13. Play with x1 y1 x2 y2 and gradientTransform

Learn SVG 17

Chapter 7 Filling the Shape

We can see that gradientTransform="rotate(45)" give not same result that 0 100 100 0, reason come from length of gradient vector, in rotate, vector keep same length and cover only a part of rectangle. gradientTransform="rotate(-45,-450,150)" apply to 0 100 100 100 and 0 100 100 0 are different for same reason, and here we can not use percentages to give center of rotation. We cannot define such gradient for many objects. Radial Gradients This is the syntax for the radialGradient element : <radialGradient id="name" gradientUnits="userSpaceOnUse|objectBoundingBox" gradientTransform="transform-list" spreadMethod="pad|repeat|reflect" cx="NumberOrPercentage" cy="NumberOrPercentage" r="NumberOrPercentage" fx="NumberOrPercentage" fy="NumberOrPercentage"> <!-- stop elements --> </radialGradient>

Diagram 7-3. Chart for 'radialGradient' syntax

Learn SVG 18

Chapter 7 Filling the Shape

Figure 7-14. Attributes for radialGradient element

cx, cy, r define the largest circle for the radial gradient. Default values are 50%. fx, fy define the focal point for the radial gradient. The gradient will be drawn such that the 0% gradient stop is mapped to (fx, fy). If values are not specified for fx and fy, focal point is in cx,cy. Figure 7-14 show example with cx="50%" cy="50%" r="50%" fx="20%" fy="20%" and offset="0%" for black and offset="100%" for white. We can play with focal point distinct from center and spreadMethod to fill rectangle. Figure 7-15 show two examples where focal point is in center with reflect and repeat values for spreadMethod. For two others, focal point is distinct from center. Source of svg file ( Example 7-15 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <radialGradient id='MyGradient1' spreadMethod='reflect' cx='50%' cy='50%' r='5%' fx='50%' fy='50%'> <stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/> <stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/> </radialGradient> <radialGradient id='MyGradient2' spreadMethod='repeat' cx='50%' cy='50%' r='5%' fx='50%' fy='50%'> <stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/> <stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/> </radialGradient>

Learn SVG 19

Chapter 7 Filling the Shape

<radialGradient id='MyGradient3' spreadMethod='reflect' cx='50%' cy='50%' r='5%' fx='25%' fy='25%'> <stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/> <stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/> </radialGradient> <radialGradient id='MyGradient4' spreadMethod='repeat' cx='50%' cy='50%' r='35%' fx='5%' fy='5%'> <stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/> <stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/> </radialGradient> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> <rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/> <rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/> <text x="75" y="175" style="text-anchor:middle"> reflect 50 50 5 50 50 </text> <text x="225" y="175" style="text-anchor:middle"> repeat 50 50 5 50 50 </text> <text x="375" y="175" style="text-anchor:middle"> reflect 50 50 5 25 25 </text> <text x="525" y="175" style="text-anchor:middle"> repeat 50 50 35 5 5 </text> </svg>

Figure 7-15. spreadMethod and focal point

Gradients and filters We can apply filters to gradients. To get 3D lighting effect, we can use stop-opacity="0" for some stop elements. Figure 7-16 show radial gradient, lighting and composite of the two. Source of svg file ( Example 7-16 ) :

Learn SVG 20

Chapter 7 Filling the Shape

<svg width="660" height="300" viewBox="-30 -30 660 300"> <defs> <radialGradient id='gradient' spreadMethod='repeat' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'> <stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/> <stop id='c2' offset='95%' stop-color='yellow' stop-opacity='0'/> </radialGradient> <filter id='Filter0' filterUnits='objectBoundingBox' x='0%' y='0%' width='100%' height='100%'> <feImage result="pict0" xlink:href="#Image2"/> <feDiffuseLighting result='pict1' in='pict0' lighting-color='white' diffuseConstant='1' kernelUnitLength='1,1' surfaceScale='4.2'> <feDistantLight azimuth='60' elevation='25'/> </feDiffuseLighting> <feComposite in2='pict1' in='pict0' operator='xor'/> </filter> <filter id='Filter1' filterUnits='objectBoundingBox' x='0%' y='0%' width='100%' height='100%'> <feImage result="pict0" xlink:href="#Image1"/> <feDiffuseLighting result='pict1' in='pict0' lighting-color='white' diffuseConstant='1' kernelUnitLength='1,1' surfaceScale='4.2'> <feDistantLight azimuth='60' elevation='25'/> </feDiffuseLighting> </filter> <rect id="Image1" x="200" y="0" width='200' height='200' fill='url(#gradient)'/> <rect id="Image2" x="400" y="0" width='200' height='200' fill='url(#gradient)'/> </defs> <rect x='0' y='0' width='200' height='200' fill='url(#gradient)'/> <rect x="200" y="0" width='200' height='200' filter='url(#Filter1)'/> <rect x="400" y="0" width='200' height='200' filter='url(#Filter0)'/> <text x="100" y="225" style="text-anchor:middle">radial gradient</text> <text x="300" y="225" style="text-anchor:middle">lighting gradient</text> <text x="500" y="225" style="text-anchor:middle"> composite pictures </text> </svg>

Figure 7-16. Composite radial gradient with lighting

Learn SVG 21 How create gradients ?

Chapter 7 Filling the Shape

In design tools, we can choose gradient, but you cannot try all parameters, so you can find online ( at pilat.free.fr ) or on companion cd a tool to create gradient, test all parameters and get code for gradient ( using PHP ) Figure 7-17 is screenshot of tool to create radial gradient. This tool exist also as reusable component that you can add at your application.

Figure 7-17. Tool to create radial gradient

Learn SVG 22

Chapter 7 Filling the Shape

Patterns
'pattern' element "A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted." This is syntax for "pattern" element : <pattern id="name" patternUnits=" userSpaceOnUse|objectBoundingBox" patternContentUnits=" userSpaceOnUse|objectBoundingBox" patternTransform="transform-list" viewBox="min-x min-y width height" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"> <!-- some objects as pattern content --> </pattern>

Diagram 7-4. Chart for 'pattern' syntax

Learn SVG 23

Chapter 7 Filling the Shape

In previous chapters, you see pictures with grid background using pattern :
<pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern>

We define pattern element, give attributes for rectangular tile, x ( 0 by default ), y ( 0 by default ), width ( 0 by default ) and height ( 0 by default ). patternUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x y width and height for pattern tile. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the pattern is applied. In this case, it's more easy to use percentages for attributes. x attribute give x-coordinate for left upper corner for tile ( 0 by default ) y attribute give y-coordinate for left upper corner for tile ( 0 by default ) width attribute give width for tile ( 0 by default ) height attribute give height for tile ( 0 by default ) patternContentUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for the contents of the 'pattern' element. Here, "userSpaceOnUse" is the default value. viewBox attribute apply for pattern contents. If we define viewBox attribute, patternContentUnits attribute has no effect. patternTransform attribute allow to add transform to coordinate system. We can use translate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a b c d e f). Figure 7-18 show effect of patternTransform attribute : Source of svg file ( Example 7-18 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern> <pattern id="Pat02" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000"

Learn SVG 24

Chapter 7 Filling the Shape

stroke-width="0.1"/> </pattern> <pattern id="Pat03" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="scale(2)"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern> <pattern id="Pat04" width="10" height="10" patternUnits="userSpaceOnUse" patternTransform="skewX(45)"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern> </defs> <rect x="0" y="0" width="150" height="150" style="stroke:black;fill:url(#Pat01)"/> <rect x="150" y="0" width="150" height="150" style="stroke:black;fill:url(#Pat02)"/> <rect x="300" y="0" width="150" height="150" style="stroke:black;fill:url(#Pat03)"/> <rect x="450" y="0" width="150" height="150" style="stroke:black;fill:url(#Pat04)"/> <text x="75" y="175" style="text-anchor:middle">identity</text> <text x="225" y="175" style="text-anchor:middle">rotate(45)</text> <text x="375" y="175" style="text-anchor:middle">scale(2)</text> <text x="525" y="175" style="text-anchor:middle">skewX(45)</text> </svg>

Figure 7-18. Some values for patternTransform attribute

Pattern contents are childs of pattern element, they can be any svg object basic shape, path, text, gradient, filter, mask, symbol, marker ....... For our example, one rectangle is the only content. How apply pattern to shape ? We define pattern in <defs> section and give id, here "MyPattern" to pattern element.
<pattern id="MyPattern" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern>

Learn SVG 25

Chapter 7 Filling the Shape

We can use this pattern to fill or stroke any element, as basic shape, path, text. This rectangle will be filled with pattern :
<rect x='0' y='0' width='200' height='200' fill='url(#MyPattern)'/>

We can also use style attribute :


<rect x='0' y='0' width='200' height='200' style='stroke:black;fill:url(#MyPattern)'/>

Figure 7-19 show some examples of filling and stroking with pattern. Source for svg file ( Example 7-19 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220"> <defs> <pattern id="MyPattern" width="10" height="10" patternUnits="userSpaceOnUse"> <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/> </pattern> </defs> <rect x="0" y="0" width="150" height="150" style="stroke:black;fill:url(#MyPattern)"/> <circle cx="225" cy="75" r="60" style="fill:none;stroke-width:10;stroke:url(#MyPattern)"/> <path d="M320 20l 70 0 0 60 20 50 -100 0z" style="stroke:black;fill:url(#MyPattern)"/> <text x="525" y="100" style="stroke:black;fill:url(#MyPattern); font-family:Balloon;text-anchor:middle;font-size:100">SVG</text> <text x="75" y="175" style="text-anchor:middle">fill rectangle</text> <text x="225" y="175" style="text-anchor:middle">stroke circle</text> <text x="375" y="175" style="text-anchor:middle">fill path</text> <text x="525" y="175" style="text-anchor:middle">fill text</text> </svg>

Figure 7-19. Fill and stroke with pattern

Figure 7-20 show classical examples of pattern used in statistical charts or maps.

Learn SVG 26

Chapter 7 Filling the Shape

Figure 7-20. Some classical examples of pattern

How create patterns ? In design tools, we can choose pattern, but you cannot create our own pattern, so you can find online ( at pilat.free.fr ) a tool to create pattern content using rectangle, ellipse, polygon, line and path elements and get code for pattern ( using HTML form ). Figure 7-21 is screenshot of this tool to create pattern content. To fill shapes, you can create your gradient with previous tool as reusable component.

Learn SVG 27

Chapter 7 Filling the Shape

Figure 7-21. Screenshot of tool to create pattern content

Use filter on pattern We can add filter to create effect on pattern Figure 7-22 show two effects on very simple pattern. We use lighting filter on pattern and composite it with pattern. Source for svg file ( Example 7-22 ) :
<svg width="650" height="270" viewBox="-30 -30 650 270"> <defs> <pattern id='motif' x='0' y='0' width='20' height='20' patternUnits="userSpaceOnUse"> <circle cx='5' cy='5' r='5' style='stroke:black; stroke-width:1;fill:red'/> <circle cx='15' cy='15' r='5' style='stroke:black; stroke-width:1;fill:red'/> </pattern> <filter id='Filter0' x="0%" y="0%" width="100%" height="100%"> <feImage result='pict0' xlink:href='#Image1'/> <feDiffuseLighting result='pict1' in='pict0'

Learn SVG 28

Chapter 7 Filling the Shape

lighting-color='white' diffuseConstant='1' kernelUnitLength='1,1' surfaceScale='1'> <feDistantLight azimuth='45' elevation='45'/> </feDiffuseLighting> <feComposite result='pict2' in2='pict0' in='pict1' operator='over'/> </filter> <rect id='Image1' x="200" y="0" width='200' height='200' fill="url(#motif)"/> <rect id='Image2' x="400" y="0" width='200' height='200' fill="url(#motif)"/> <filter id='Filter1' x="0%" y="0%" width="100%" height="100%"> <feImage result='pict0' xlink:href='#Image2'/> <feDiffuseLighting result='pict1' in='pict0' lighting-color='white' diffuseConstant='1' kernelUnitLength='1,1' surfaceScale='1'> <feDistantLight azimuth='95' elevation='35'/> </feDiffuseLighting> <feComposite result='pict2' in2='pict0' in='pict1' operator='in'/> </filter> </defs> <rect x="0" y="0" width="200" height="200" fill="url(#motif)"/> <rect x='200' y='0' width='200' height='200' filter='url(#Filter0)'/> <rect x='400' y='0' width='200' height='200' filter='url(#Filter1)'/> <text x="100" y="225" style="text-anchor:middle">pattern</text> <text x="300" y="225" style="text-anchor:middle">lighting</text> <text x="500" y="225" style="text-anchor:middle">other composite</text> </svg>

Figure 7-22. Example of effects on pattern with filters

With figure 7-23, we have Europa map as lego pieces using pattern with filters. Only color of lighting change for the two patterns.

Learn SVG 29

Chapter 7 Filling the Shape

Figure 7-23. Using pattern and filters for Europa map

To go further with patterns Pattern create tile to fill shape or other element, but tiling use only translation of same tile. Why not try to create tilings of plane in the same way as M.C. Escher ? At same URL, you can find tool to choose type of tiling and create your tile with basic shapes. Figure 7-24 show example of tiling of plane create with some Bezier curves and lighting effect

Learn SVG 30

Chapter 7 Filling the Shape

Figure 7-24. Example of tiling of plane and lighting effect

Learn SVG 31

Chapter 7 Filling the Shape

Clipping paths
"The clipping path restricts the region to which paint can be applied. Conceptually, any parts of the drawing that lie outside of the region bounded by the currently active clipping path are not drawn." How define clipping path ? We use "clipPath" element : The syntax is <clipPath id="name" clipPathUnits = "userSpaceOnUse | objectBoundingBox"> <!-- shapes paths text use ... elements as children --> </clipPath>

Diagram 7-5. Chart for 'clipPath' syntax

clipPathUnits defines the coordinate system for the contents of the 'clipPath' element. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the clipping path is applied. How apply clipping path? For complex shapes, to define which points are inside shape, we can choose value for clip-rule attribute, nonzero or evenodd.

Learn SVG 32 'clip-rule' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

Chapter 7 Filling the Shape

nonzero | evenodd | inherit nonzero graphics elements within a 'clipPath' element yes N/A visual yes

nonzero This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a path segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside.. evenodd This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside. We use clip-path property : 'clip-path' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

<uri> | none | inherit none container elements and graphics elements no N/A visual yes

Figure 7-25 show a circle on a text, and text color change inside circle. For that we define in <defs> section : - text in black - clipPath define by a circle We draw black rectangle, white text and use element with circle as clip-path and black text as xlink:href value. We can animate the spot by moving circle, cx of circle going from 50 to 450 ... Source code for svg example ( Example 7-25 ) :

Learn SVG 33

Chapter 7 Filling the Shape

<svg width="550" height="130" viewBox="-50 -30 550 130"> <defs> <g id="new_text"> <rect x="0" y="0" width="500" height="100" fill="white"/> <text x="250" y="60" style="text-anchor:middle;font-size:35; font-family:Arial;fill:black">Scalable Vector Graphics</text> </g> <clipPath id="spot"> <circle cx="200" cy="50" r="50"/> </clipPath> </defs> <rect x="0" y="0" width="500" height="100" fill="black"/> <text x="250" y="60" style="text-anchor:middle;font-size:35; font-family:Arial;fill:white;fill-opacity:1"> Scalable Vector Graphics </text> <use clip-path="url(#spot)" xlink:href="#new_text"/> </svg>

Figure 7-25. ClipPath with circle on text

We can use clipPath element for drop-down list with scrolling.

Figure 7-26. Drop-down selection list with scrolling

Figure 7-26 is a screenshot of a drop-down selection list with scrolling. This reusable svg component use a script file and a svg file for design of window. Values of the list are passed as parameters and put in <defs> section:
<defs> <g id="scroll_textes" transform="translate(0,90)" style="text-anchor:left;font-size:12;font-family:Arial;fill:black">

Learn SVG 34

Chapter 7 Filling the Shape

<text x="10" y="15" startOffset="0">red</text> <text x="10" y="35" startOffset="0">yellow</text> <!-other text elements --> </g> <clipPath id="txt_spot"> <rect id="txt_list" x="0" y="90" width="260" height="120"/> </clipPath> </defs>

ClipPath element define part of list to be show. When user click on scroll buttons or slide cursor, script change value of y in rectangle "txt_list" content of clipPath. We can use clipPath and animation to simulate one-armed bandit : Figure 7-27 show animation to choose number between 0 and 999. Script is only used to change numbers for begining. We get random number ... We use two animations : - first apply to clipPath content to change selected numbers. - second apply to group using clipPath to put always in same place numbers. Source code for this example ( Example 7-27) :
<svg width='200' height='200'> <script type="text/ecmascript"> <![CDATA[ function alea(evt) { svgdoc=evt.target.ownerDocument; for (i=1;i<=3;i++) { n=Math.floor(10*Math.random())-1; node=svgdoc.getElementById("move_"+i.toString()); node.setAttribute("from",20+40*n); node.setAttribute("to",40*n+380); node=svgdoc.getElementById("number_"+i.toString()); node.setAttribute("from",20+50*(i-1)+","+(-40*n)); node.setAttribute("to",20+50*(i-1)+","+(-360-40*n)); } } ]]> </script> <defs> <style type="text/css"> <![CDATA[ .lettre {text-anchor:middle;font-family:Verdana;font-weight:bold; font-size:30;stroke:black} ]]> </style> <text id="ico1" class="lettre" x="25" y="30">1</text> <text id="ico2" class="lettre" x="25" y="30">2</text> <text id="ico3" class="lettre" x="25" y="30">3</text> <text id="ico4" class="lettre" x="25" y="30">4</text> <text id="ico5" class="lettre" x="25" y="30">5</text> <text id="ico6" class="lettre" x="25" y="30">6</text>

Learn SVG 35

Chapter 7 Filling the Shape

<text id="ico7" class="lettre" x="25" y="30">7</text> <text id="ico8" class="lettre" x="25" y="30">8</text> <text id="ico9" class="lettre" x="25" y="30">9</text> <text id="ico0" class="lettre" x="25" y="30">0</text> <g id="rolling_numbers"> <use x="0" y="0" xlink:href="#ico1"/> <use x="0" y="40" xlink:href="#ico2"/> <use x="0" y="80" xlink:href="#ico3"/> <use x="0" y="120" xlink:href="#ico4"/> <use x="0" y="160" xlink:href="#ico5"/> <use x="0" y="200" xlink:href="#ico6"/> <use x="0" y="240" xlink:href="#ico7"/> <use x="0" y="280" xlink:href="#ico8"/> <use x="0" y="320" xlink:href="#ico9"/> <use x="0" y="360" xlink:href="#ico0"/> <use x="0" y="400" xlink:href="#ico1"/> <use x="0" y="440" xlink:href="#ico2"/> <use x="0" y="480" xlink:href="#ico3"/> <use x="0" y="520" xlink:href="#ico4"/> <use x="0" y="560" xlink:href="#ico5"/> <use x="0" y="600" xlink:href="#ico6"/> <use x="0" y="640" xlink:href="#ico7"/> <use x="0" y="680" xlink:href="#ico8"/> <use x="0" y="720" xlink:href="#ico9"/> <use x="0" y="760" xlink:href="#ico0"/> <use x="0" y="800" xlink:href="#ico1"/> <use x="0" y="840" xlink:href="#ico2"/> <use x="0" y="880" xlink:href="#ico3"/> </g> </defs> <rect x='0' y='0' width='200' height='200' style='stroke:green;fill:yellow'/> <rect x="20" y="20" width="150" height="80" fill="white"/> <path d="M70 20l0 80 M120 20l0 80" stroke="black"/> <clipPath id="spot1"> <rect x="0" y="20" width="50" height="80"> <animate id="move_1" attributeName="y" dur="4s" repeatCount="2" fill="freeze" from="0" to="240" begin="go.click"/> </rect> </clipPath> <clipPath id="spot2"> <rect x="0" y="60" width="50" height="80"> <animate id="move_2" attributeName="y" dur="3s" repeatCount="3" fill="freeze" from="40" to="280" begin="go.click"/> </rect> </clipPath> <clipPath id="spot3"> <rect x="0" y="100" width="50" height="80"> <animate id="move_3" attributeName="y" dur="2s" repeatCount="4" fill="freeze" from="80" to="320" begin="go.click"/> </rect> </clipPath> <g transform="translate(20,0)" clip-path="url(#spot1)"> <use xlink:href="#rolling_numbers"/> <animateTransform id="number_1" attributeName="transform" type="translate" from="20,20" to="20,-220" fill="freeze" dur="4s" repeatCount="2" begin="go.click"/> </g> <g transform="translate(70,-40)" clip-path="url(#spot2)">

Learn SVG 36

Chapter 7 Filling the Shape

<use xlink:href="#rolling_numbers"/> <animateTransform id="number_2" attributeName="transform" type="translate" from="70,-20" to="70,-260" fill="freeze" dur="3s" repeatCount="3" begin="go.click"/> </g> <g transform="translate(120,-80)" clip-path="url(#spot3)"> <use xlink:href="#rolling_numbers"/> <animateTransform id="number_3" attributeName="transform" type="translate" from="120,-60" to="120,-300" fill="freeze" dur="2s" repeatCount="4" begin="go.click"/> </g> <rect x="10" y="180" width="50" height="18" fill="black"/> <text x="35" y="195" style="text-anchor:middle;font-weight:bold;font-size:15; font-family:Arial;fill:white;stroke:black">GO</text> <rect id="go" x="10" y="180" width="50" height="18" opacity="0.1" onclick="alea(evt)"/> </svg>

Figure 7-27. Screenshot of one-armed bandit

Using clipping path for puzzle We can create puzzle game with some scripts. In this example, user can change picture used for pieces, number of pieces, paths for clipping. When svg is loaded, clipPath elements are created in <defs> section in group "clips", paths used are defined in file "clip_paths.js". Init function create also pieces for puzzle in group "pieces". Source code for this game ( Example 7-28 ) :
<svg width="800" height="450" onload="init(evt)"> <defs> <g id="picture"> <image id="source" x="0" y="0" width="400" height="400"

Learn SVG 37

Chapter 7 Filling the Shape

xlink:href="puzzle.jpg"/> </g> <g id="clips"> </g> </defs> // Load paths for clipPath elements: <script type="text/ecmascript" xlink:href="clip_paths.js" /> <script type="text/ecmascript"> <![CDATA[

// Some variables used in script var svgdoc="",xd1,xd2,yd1,yd2,num; var click_piece=false,cible="", nb_trials=0; var played=new Array(); // Variables which can be changed by user to get more or less pieces var size=5,nb_pieces=25,large=80, // Function init, on loading svg, define svgdoc, values for large and nb_pieces. // Call create_pieces to create pieces and distribution to arrange pieces before // starting game

function init(evt) { svgdoc=evt.target.ownerDocument; large=Math.round(400/size);nb_pieces=size*size; create_pieces(evt); distribution(evt); } // Function create pieces, first clipPath elements, then pieces as use elements function create_pieces(evt) { contents = svgdoc.getElementById ('clips'); contents2 = svgdoc.getElementById ('pieces'); k=-1; for (i=0;i<size;i++) { for (j=0;j<size;j++) { k+=1; node=svgdoc.createElement("clipPath"); name="clip_path"+(1+i+size*j).toString(); node.setAttribute("id",name); contents.appendChild(node); node2=svgdoc.createElement("path"); node2.setAttribute("d",chemin[k]); node.appendChild(node2); node=svgdoc.createElement("use"); node.setAttribute("id","tile"+(1+i+size*j).toString());

Learn SVG 38

Chapter 7 Filling the Shape


node.setAttribute("transform","translate(400,0)"); name="url(#clip_path"+(1+i+size*j).toString()+")"; node.setAttribute("clip-path",name); node.setAttributeNS('http://www.w3.org/2000/xlink/namespace/', "xlink:href","#picture"); contents2.appendChild(node); }

} } // Function put pieces in random order beside picture to complete and initialise // values function distribution(evt) { var place_allowed=new Array(); for (i=0;i<size;i++) { for (j=0;j<size;j++) { place_allowed[i+size*j]=0 } }; for (i=1;i<=nb_pieces;i++) { played[i]=0 }; for (i=0;i<size;i++) { for (j=0;j<size;j++) { while (place_allowed[i+size*j]==0) { k=1+Math.floor(nb_pieces*Math.random()); if (played[k]<1) { played[k]=played[k]+1; place_allowed[i+size*j]=k } }; line=Math.floor((k-1)/size); row=k-1-size*line; dx=400-large*(line-i); dy=large*(j-row); transfo="translate("+dx.toString()+","+dy.toString()+")"; node = svgdoc.getElementById("tile"+k.toString()); node.setAttribute("transform",transfo); } } for (i=1;i<=nb_pieces;i++) { played[i]=0 }; nb_trials=0; node=svgdoc.getElementById("trials"); child=node.firstChild; child.setData(nb_trials) }

Learn SVG 39

Chapter 7 Filling the Shape

// Functions to move pieces // On mouseup, piece is no more actived function mouse_up(evt) { click_piece=false } // On click, piece is actived, nb_trials incremented, new value writed, // We get position of piece on click (xd1,yd1) and pointer position (xd2,yd2)

function mouse_down(evt) { if (click_piece==false) { cible=evt.target.getAttribute("id"); click_piece=true; nb_trials+=1; node=svgdoc.getElementById("trials"); child=node.firstChild; child.setData(nb_trials); xm=evt.clientX; ym=evt.clientY; num=parseInt(cible.substring(4,cible.length)); objet=svgdoc.getElementById("tile"+num.toString()); transfo=new String(objet.getAttribute("transform")); posi2=transfo.lastIndexOf(","); tranx=transfo.substring(10,posi2); xd1=parseInt(tranx,10); longueur=transfo.length-1; trany=transfo.substring(posi2+1,longueur); yd1=parseInt(trany,10); xd2=xm;yd2=ym } } // On mousemove piece is moved of (x_pointer+xd1-xd2,y_pointer+yd1-yd2) // If piece is nearest good position ( less than 5 pixels in x and y ), piece is // in place and played[piece_number] get value of 1.

function mouse_move(evt) { xm=evt.clientX; ym=evt.clientY; if (click_piece==true) { depx=xm+xd1-xd2; depy=ym+yd1-yd2; if ((Math.abs(depx)<5)&&(Math.abs(depy)<5)) { depx=0; depy=0; played[num]=1 } else { played[num]=0

Learn SVG 40

Chapter 7 Filling the Shape

}; transfo="translate("+depx+","+depy+")"; node = svgdoc.getElementById("tile"+num.toString()); node.setAttribute("transform",transfo) } }

// Function to put pieces in place on user request function solution(evt) { for (i=1;i<=nb_pieces;i++) { node = svgdoc.getElementById("tile"+i.toString()); node.setAttribute("transform","translate(0,0)"); } } // Function to give result of game function bilan(evt) { var win_game=true; for (i=1;i<=nb_pieces;i++) { if (played[i]==0) { win_game=false } }; if (win_game==true) { alert("You win in "+nb_trials+" trials") } else { alert("It's not finished!") } } ]]> </script> <rect x="0" y="0" width="800" height="450" fill="green" opacity="0.3"/> <rect x="10" y="410" width="100" height="20" style="fill:white"/> <text x="60" y="425" style="text-anchor:middle;font-size:15; font-family:Arial;fill:red">Result</text> <rect x="10" y="410" onclick="bilan(evt)" width="100" height="20" style="fill:green;fill-opacity:0"/> <rect x="120" y="410" width="120" height="20" style="fill:white"/> <text x="180" y="425" style="text-anchor:middle;font-size:15; font-family:Arial;fill:red">New game</text> <rect x="120" y="410" onclick="distribution(evt)" width="120" height="20" style="fill:green;fill-opacity:0"/> <rect x="250" y="410" width="120" height="20" style="fill:white"/> <text x="310" y="425" style="text-anchor:middle;font-size:15; font-family:Arial;fill:red">Solution</text> <rect x="250" y="410" onclick="solution(evt)" width="120" height="20" style="fill:green;fill-opacity:0"/>

Learn SVG 41

Chapter 7 Filling the Shape

<text x="450" y="425" style="text-anchor:left;font-size:15; font-family:Arial;fill:black">Trials: </text> <text id="trials" x="580" y="425" style="text-anchor:right;font-size:15; font-family:Arial;fill:black">0</text> <g onmouseup="mouse_up(evt)"> <use opacity="0.3" xlink:href="#picture"/> <g id="pieces" onmousemove="mouse_move(evt)" onmousedown="mouse_down(evt)"> </g> </g> </svg>

When svg is loaded, we get for svg elements: In <defs> section :


<g id="clips"> <clipPath id="clip_path1"> <path d="M0 0 l80 0 c-10,10 -10,25 0,40 c10,10 10,30 0,40 c-5,-10 -25,-10 -30,0 a10,10 0 1,1 -10,0 c-5,-5 -35,-5 -40,0 l0 -80z"/> </clipPath> <clipPath id="clip_path6"> <path d="M80 0 c-10,10 -10,25 0,40 c10,10 10,30 0,40 c5,10 25, 10 30,0 a10,10 0 1,1 10,0 c5,5 35,5 40,0 l-5 -35 a10,10 0 1,0 0,-10 l5 -35z"/> </clipPath> <!-- other clipPath elements --> </g>

In group "pieces" :
<g id="pieces" onmousemove="mouse_move(evt)" onmousedown="mouse_down(evt)"> <use id="tile1" transform="translate(400,80)" clip-path="url(#clip_path1)" xlink:href="#picture"/> <use id="tile6" transform="translate(320,160)" clip-path="url(#clip_path6)" xlink:href="#picture"/> <!-- other pieces for puzzle --> </g>

Using HTML form, user can choose local file for picture. We can add choice for clipping paths, number of pieces .....

Learn SVG 42

Chapter 7 Filling the Shape

Figure 7-28. Sceenshot of puzzle game

Learn SVG 43

Chapter 7 Filling the Shape

Masks
"A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted." This is syntax for "mask" element : <mask id="name" maskUnits=" userSpaceOnUse|objectBoundingBox" maskContentUnits=" userSpaceOnUse|objectBoundingBox" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"> <!-- some objects as mask content --> </mask>

Diagram 7-6. Chart for 'mask' syntax

maskUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x y width and height for largest possible offscreen buffer. With "userSpaceOnUse", values are defined in current user coordinate system.

Learn SVG 44

Chapter 7 Filling the Shape

With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the mask is applied. In this case, it's more easy to use percentages for attributes. x attribute give x-coordinate for left upper corner for tile ( -10% by default ) y attribute give y-coordinate for left upper corner for tile ( -10% by default ) width attribute give width for tile ( 120% by default ) height attribute give height for tile ( 120% by default ) maskContentUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for the contents of the 'mask' element. Here, "userSpaceOnUse" is the default value. To use mask for object, we use 'mask' property : 'mask' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: <uri> | none | inherit none container elements and graphics elements no N/A visual yes

We can get same result as Figure 7-25 with this code ( Example 7-25 ) :
<svg width="550" height="130" viewBox="-50 -30 550 130"> <defs> <g id="new_text"> <rect x="0" y="0" width="500" height="100" fill="white"/> <text x="250" y="60" style="text-anchor:middle;font-size:35; font-family:Arial;fill:black">Scalable Vector Graphics</text> </g> <mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0" width="500" height="100"> <circle cx="200" cy="50" r="50" fill="white"/> </mask> </defs> <rect x="0" y="0" width="500" height="100" fill="black" fillopacity="1"/> <text x="250" y="60" style="text-anchor:middle;font-size:35; font-family:Arial;fill:white;fill-opacity:1"> Scalable Vector Graphics </text> <use mask="url(#spot)" xlink:href="#new_text"/> </svg>

Learn SVG 45

Chapter 7 Filling the Shape

What are differences between clipPath and mask ?


"The clipping path restricts the region to which paint can be applied...." To get picture, only geometry of clipPath element modify drawing. If you choose filling or stroking for clipPath content, drawing keep the same. "You can specify that any other graphics object or 'g' element can be used as an alpha mask for compositing the current object into the background ..." Here, geometry give boundaries of drawing and filling for mask content change drawing : Figure 7-29 show result with
<mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0" width="500" height="100"> <circle cx="200" cy="50" r="50" fill="white"/> </mask>

for upper drawing and with


<mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0" width="500" height="100"> <circle cx="200" cy="50" r="50" fill="green"/> </mask>

for other

Figure 7-29. Only filling color of mask content change ...

Chapter 8 : Using filters SVG specifications allow using filters on vector and raster pictures. Filters can create object, light existing object, modify object or composite objects.

Filter element
Syntax for 'filter' element This is the syntax for filter element : <filter id="name" filterUnits="userSpaceOnUse|objectBoundingBox" primitiveUnits=""userSpaceOnUse|objectBoundingBox" filterRes="NumberOptionalNumber" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"> <!--. filter primitives --> </filter>

Diagram 8-1. Chart for 'filter' syntax

You can put filter element in "defs" section :

Learn SVG

Chapter 8 Effective Filters

<defs> <filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <!-- filter primitives as children of filter element --> </filter> </defs>

Attributes for filter element filterUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x y width and height for filter. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the filter is applied. In this case, it's more easy to use percentages for attributes. primitiveUnits attribute can be "userSpaceOnUse" or "objectBoundingBox" for x, y, width and height within the filter primitives. filterRes indicates the width and height of the intermediate images in pixels. By default, a reasonable default resolution appropriate for the target device will be used. Figure 8-1 show pixelation effect for too small values for filterRes.

Figure 8-1. Values for filterRes of 10 20 and 50 for width of 200

Learn SVG

Chapter 8 Effective Filters

x y width height defines a rectangular region on the canvas to which this filter applies. This value can be percentages or values. By default, we get 10% for x and y and 120% for width and height.

Filter primitives
Rendering properties Filter primitives use rendering properties of other elements, but there is a single property 'color-interpolation-filters' property Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: auto | sRGB | linearRGB | inherit linearRGB filter primitives yes N/A visual yes

auto : the user agent can choose either the sRGB or linearRGB spaces for filter effects color operations. sRGB : filter effects color operations should occur in the sRGB color space. linearRGB : filter effects color operations should occur in the linearized RGB color space.

Figure 8-2. 'color-interpolation-filters' values

Learn SVG

Chapter 8 Effective Filters

Note that 'color-interpolation-filters' has a different initial value than 'color-interpolation'. 'color-interpolation-filters' has an initial value of linearRGB, whereas 'color-interpolation' has an initial value of sRGB. Thus, in the default case, filter effects operations occur in the linearRGB color space, whereas all other color interpolations occur by default in the sRGB color space. Common attributes x y width height defines a rectangular subregion which restricts calculation and rendering of the given filter primitive. This value can be percentages or values. By default, we get 0% for x and y and 100% for width and height. result name for graphic that result from processing this filter primitive. It can be referenced by an in attribute on a subsequent filter primitive within the same filter element. in in2 identifies inputs for filter primitive. The value can be either one of six keywords SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint - or can be a string which matches a previous result attribute value within the same filter element If no value is provided for in attribute and this is the first filter primitive, then this filter primitive will use SourceGraphic as its input. If no value is provided and this is a subsequent filter primitive, then this filter primitive will use the result from the previous filter primitive as its input.

Figure 8-3. SourceGraphic and SourceAlpha

Learn SVG

Chapter 8 Effective Filters

Figure 8-3 show examples of SourceGraphic and SourceAlpha for some svg objects and for bitmap.

How use filters elements


We use 'filter' property to apply filter to any graphic element or container

'filter' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable: <uri> | none | inherit none container elements and graphics elements no N/A visual yes

If your filter create picture you can write this :


<rect filter="url(#MyFilter)" x='100' y='100' width='200' height='200'/>

If you want to apply filter to external picture, you can write :


<image filter="url(#MyFilter)" x="0" y="0" width='400' height='400' xlink:href='fondu1.jpg'/>

You can apply filter to group of objects :


<g filter="url(#MyFilter)"> <!-- here your objects </g> -->

You can use filter to create pattern and fill or stroke objects
<pattern id="motif" patternUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <rect filter="url(#MyFilter)" x="0" y="0" width="400" height="400"/> </pattern> <circle cx='200' cy='200' r='200' style='stroke:black;fill:url(#motif)'/>

Filter primitives to modify colors of a picture:


There is two primitives to modify colors of svg objects or raster, feColorMatrix and feComponentTransfer feColorMatrix primitive

Learn SVG

Chapter 8 Effective Filters

feColorMatrix : apply matrix transformation for calculate new values for RGB and alpha for each pixel : | R' | | G' | | a00 a01 a02 a03 a04 | | a10 a11 a12 a13 a14 | |R| |G|

| B' | = | a20 a21 a22 a23 a24 | * | B | | A' | |1 | | a30 a31 a32 a33 a34 | | 0 0 0 0 1 | |A| |1|

This is syntax for feColorMatrix element : <feColorMatrix id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" type="matrix|hueRotate|saturate|luminanceToAlpha" values="list of numbers"/>

Diagram 8-2. Chart for 'feColorMatrix' syntax

attribute type can be : matrix : you give all values for 5x4 matrix ( for most terms, you can see effect between

Learn SVG

Chapter 8 Effective Filters

-1 and 1, between 0 and 1 for alpha ) hueRotate : you give value of angle in degrees ( 0 has no effect on picture ) matrix is
| a00 a01 a02 0 0 | | a10 a11 a12 0 0 | | a20 a21 a22 0 0 | | 0 0 0 1 0| | 0 0 0 0 1 |

with
| a00 a01 a02 | [0.213 0.715 0.072] | a10 a11 a12 | = [0.213 0.715 0.072] + | a20 a21 a22 | [0.213 0.715 0.072] [0.787 -0.715 -0.072] [-0.213 -0.715 0.928] cos(hueRotate value) * [-0.213 0.285 -0.072] + sin(hueRotate value) * [0.143 0.140 -0.283] [-0.213 -0.715 0.928] [-0.787 0.715 0.072]

saturate : you give value s between 0 and 1 ( 1 don't change, 0 give black and white picture ) matrix is
| 0.213+0.787s 0.715-0.715s 0.072-0.072s | 0.213-0.213s 0.715+0.285s 0.072-0.072s | 0.213-0.213s 0.715-0.715s 0.072+0.928s | 0 0 0 | 0 0 0 0 0 0 1 0 0| 0| 0| 0| 1|

luminanceToAlpha : no parameter (give negative black and white picture ) matrix is


| 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0.2125 0.7154 0.0721 0 | 0 0 0 0 0| 0| 0| 0| 1|

Example of code with type="matrix":


<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 .5 0"/> </filter>

Example of code with type="hueRotate":

Learn SVG

Chapter 8 Effective Filters

<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feColorMatrix type="hueRotate" values="45"/> </filter>

Figure 8-4 show some examples of effect on raster.

Figure 8-4. Some values for feColorMatrix

feComponentTransfer primitive feComponentTransfer apply function for each RGBA channel using feFuncR, feFuncG, feFuncB and feFuncA elements. It allows operations like brightness adjustment, contrast adjustment, color balance or thresholding. This is syntax for feColorMatrix element : <feComponentTransfer id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>"

Learn SVG

Chapter 8 Effective Filters

x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"> <feFuncR feFuncG feFuncB or feFuncA type="identity|linear|gamma|table|discrete" slope="number" intercept="number" amplitude="number" exponent="number" offset="number" tableValues="list of numbers"/> </feComponentTransfer>

Diagram 8-3. Chart for 'feComponentTransfer' syntax

attribute type can be: identity : C'=C linear : C'=slope*C+intercept need values for slope ( 1 by default ) and intercept ( 0 by default ) gamma : C'=amplitude*pow(C,exponent)+offset

Learn SVG

Chapter 8 Effective Filters

10

need values for amplitude ( 1 by default ) exponent ( 1 by default) and offset ( 0 by default ) table : linear interpolation between values given discrete : step function define by given values These two need tableValues ( empty table by default ) With this code there is no effect on each channel :
<feComponentTransfer> <feFuncR type='identity' /> <feFuncG type='linear' slope='1' intercept='0' /> <feFuncB type='gamma' amplitude='1' exponent='1' offset='0'/> <feFuncA type='table' tableValues='1' > </feComponentTransfer>

If there is no element as feFuncR, red channel is not modified.

Figure 8-5. Some values for feComponentTransfer

Figure 8-5 show some effects on svg picture, by example, we can adjust brightness using type="linear" on RGB channels, with slope greater than 1, we increase brightness.

Learn SVG

Chapter 8 Effective Filters

11

Filter primitives to create lighting on objects


We can use feSpecularLighting or feDiffuseLighting and choose light source feSpotLight, fePointLight or feDistantLight. This light source is child of primitive. Lighting source : feSpotLight element This is syntax for feSpotLight element : <feSpotLight id="name" x="number" y="number" z="number" pointsAtX="number" pointsAtY="number" pointsAtZ="number" specularExponent="number" limitingConeAngle="number"/>

Diagram 8-4. Chart for 'feSpotLight' syntax

For feSpotLight, attributes are : x = X location for the light source in the coordinate system ( 0 by default ) y = Y location for the light source in the coordinate system ( 0 by default ) z = Z location for the light source in the coordinate system ( 0 by default ) pointsAtX = X location of the point at which the light source is pointing. ( 0 by default ) pointsAtY = Y location of the point at which the light source is pointing. ( 0 by default ) pointsAtZ = Z location of the point at which the light source is pointing. ( 0 by default )

Learn SVG

Chapter 8 Effective Filters

12

specularExponent = Exponent value controlling the focus for the light source. ( 1 by default ) limitingConeAngle = A limiting cone which restricts the region where the light is projected. Angle in degrees. ( no limiting cone by default ) Lighting source : fePointLight element This is syntax for fePointLight element : <fePointLight id="name" x="number" y="number" z="number"/>

Diagram 8-5. Chart for 'fePointLight' syntax

For fePointLight, attributes are : x = X location for the light source in the coordinate system ( 0 by default ) y = Y location for the light source in the coordinate system ( 0 by default ) z = Z location for the light source in the coordinate system ( 0 by default ) Lighting source : feDistantLight element This is syntax for feDistantLight element : <feDistantLight id="name" azimuth="number" elevation="number"/>

Learn SVG

Chapter 8 Effective Filters

13

Diagram 8-6. Chart for 'feDistantLight' syntax

For feDistantLight, attributes are : azimuth = Angle of lighting source in XY plane in degrees. ( 0 by default ) elevation = Angle of lighting source in YZ plane in degrees. ( 0 by default ) Lighting-color property The 'lighting-color' property defines the color of the light source for filter primitives 'feDiffuseLighting' and 'feSpecularLighting'. 'lighting-color' Value:

currentColor |<color> [icc-color(<name>[,<icccolorvalue>]*)] |inherit Initial: white Applies to: 'feDiffuseLighting' and 'feSpecularLighting' elements Inherited: no Percentages: N/A Media: visual Animatable: yes

feSpecularLighting primitive This filter primitive feSpecularLighting lights a source graphic using the alpha channel as a bump map. The resulting image is an RGBA image based on the light color, feSpecularLighting produces a non-opaque image. This is syntax for feSpecularLighting element : <feSpecularLighting id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint |

Learn SVG

Chapter 8 Effective Filters

14

<filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" surfaceScale="Number" specularConstant="Number" specularExponent="Number" lighting-color="property"> <feSpotLight feDistantLight or fePointLight element /> </feSpecularLighting> We can put several lighting sources as children of feSpecularLighting element.

Diagram 8-7. Chart for 'feSpecularLighting' syntax

For feSpecularLighting, attributes are in, result and surfaceScale : height of surface when Ain = 1. ( 1 by default ) specularConstant : ks in Phong lighting model. In SVG, this can be any non-negative number. ( 1 by default ) specularExponent : Exponent for specular term, larger is more "shiny". Range 1.0 to 128.0. ( 1 by default ) lighting-color : color value for light ( white by default ) Here an example of lighting using feSpotLight as lighting source :

Learn SVG

Chapter 8 Effective Filters

15

<feSpecularLighting lighting-color='white' specularConstant ='1' specularExponent='16'> <feSpotLight x='200' y='200' z='200' pointsAtX='200' pointsAtY='100' pointsAtZ='0' specularExponent='16' limitingConeAngle='45' /> </feSpecularLighting>

feDiffuseLighting primitive This filter primitive feDiffuseLighting lights a source graphic using the alpha channel as a bump map.The resulting image is an RGBA opaque image based on the light color with alpha = 1.0 everywhere, it's opaque image. This is syntax for feDiffuseLighting element : <feDiffuseLighting id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" surfaceScale="Number" diffuseConstant="Number" kernelUnitLength="NumberOptionalNumber" lighting-color="property"> <feSpotLight feDistantLight or fePointLight element /> </feDiffuseLighting> We can put several lighting sources as children of feDiffuseLighting element. For feDiffuseLighting attributes are in, result and surfaceScale : height of surface when Ain = 1. ( 1 by default ) diffuseConstant : This can be any non-negative number. ( 1 by default ) kernelUnitLength : One or two positive numbers. ( space or comma as separator ) lighting-color : color value for light

Learn SVG

Chapter 8 Effective Filters

16

Diagram 8-8. Chart for 'feDiffuseLighting' syntax

Here example of code :


<filter id="MyFilter" filterUnits='objectBoundingBox' x='0%' y='0%' width='100%' height='100%'> <feColorMatrix in='SourceGraphic' result='pict0' type='luminanceToAlpha'/> <feDiffuseLighting in='pict0' result='pict1' lighting-color='white' diffuseConstant='1' surfaceScale='9'> <feDistantLight azimuth='45' elevation='45'/> </feDiffuseLighting> <feComposite in2='pict1' in='SourceGraphic' operator='arithmetic' k1='0.6' k2='1.1' k3='0.6' k4='0'/> </filter> <image x="100" y="80" width='200' height='200' filter='url(#MyFilter)' xlink:href='fondu1.jpg'/>

Figure 8-6 show effect for values of attribute surfaceScale. We use lighting on feTurbulence.

Learn SVG

Chapter 8 Effective Filters

17

Figure 8-6. Different values for surfaceScale attribute

Figure 8-7 show some nice effects on raster. We use feColorMatrix with type="luminanceToAlpha" to get new picture, we light this picture and composite lighting with original picture.

Figure 8-7. Some effects using feColorMatrix and feDiffuseLighting

Learn SVG

Chapter 8 Effective Filters

18

Filter primitives to composite objects


We can use feBlend, feComposite or feMerge. feBlend primitive This is syntax for feBlend element : <feBlend id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" in2="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" mode="normal|multiply|screen|darken|lighten"/>

Diagram 8-9. Chart for 'feBlend' syntax

For feBlend attributes are in in2 and mode : values are normal multiply screen darken lighten Example of code

Learn SVG

Chapter 8 Effective Filters

19

<filter id='Filter2' filterUnits='userSpaceOnUse' x='0' y='0' width='400' height='400'> <feImage xlink:href='bateau.jpg' result='pict1'/> <feImage xlink:href='memo.svgz' result='pict2'/> <feBlend id='fbl' in='pict1' in2='pict2' mode='lighten'/> </filter>

Figure 8-8. show values of attribute mode. First picture is raster and second svg objects, we see that for mode="darken" and mode="multiply", we get very close results. For mode="lighten" and mode="screen" also.

Figure 8-8. Values for attribute mode

feComposite primitive This is syntax for feComposite element : <feComposite id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" in2="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint |

Learn SVG

Chapter 8 Effective Filters <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" operator="over|in|out|atop|xor|arithmetic" k1="number" k2="number" k3="number" k4="number"/>

20

Diagram 8-10. Chart for 'feComposite' syntax

For feComposite attributes are in in2 and operator : values are over in out atop xor and arithmetic. For operator="arithmetic", we must give values for k1 k2 k3 and k4 ( 0 by default for each attribute ) Code using operator="atop"
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage xlink:href='memo.svgz' result='pict1'/> <feImage xlink:href='bandes.svg' result='pict2'/> <feComposite in='pict1' in2='pict2' operator='atop'/> </filter>

Code using operator="arithmetic"


<filter id='MyFilter' filterUnits='userSpaceOnUse' x='0' y='0' width='400' height='400'> <feImage xlink:href='memo.svgz' result='pict1'/>

Learn SVG

Chapter 8 Effective Filters

21

<feImage xlink:href='bandes.svg' result='pict2'/> <feComposite in='pict1' in2='pict2' operator='arithmetic' k1='0.4' k2='1' k3='0.5' k4='0'/> </filter>

Figure 8-9 show effect with svg objects as in picture and strips as in2 picture.

Figure 8-9. Result for different values of attribute operator

feMerge primitive This is syntax for feMerge element : <feMerge id="name" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"> <feMergeNode elements/> </feMerge> This is syntax for feMergeNode element

Learn SVG

Chapter 8 Effective Filters

22

<feMergeNode

id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>"/>

Diagram 8-11. Chart for 'feMerge' syntax

For feMerge, pictures to merge are feMergeNode elements, childs of feMerge element. feMergeNode elements are draw on top of each other. We can only play with opacity of pictures. Example of code :
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage xlink:href='fondu3.jpg' result='pict1'/> <feImage xlink:href='bateau.jpg' result='pict2'/> <feMerge> <feMergeNode in="pict1"/> <feMergeNode in="pict2"/> </feMerge> </filter>

Figure 8-10 show example of merging two rasters playing with opacities

Learn SVG

Chapter 8 Effective Filters

23

Figure 8-10. feMerge apply to two rasters and playing with opacities

Filter primitives to create objects


feFlood primitive With feFlood, we fill a rectangle with flood-color and flood-opacity selected. The 'flood-color' property indicates what color to use to flood the current filter primitive subregion. 'flood-color' Value:

currentColor |<color> [icc-color(<name>[,<icccolorvalue>]*)] | inherit Initial: black Applies to: 'feFlood' elements Inherited: no Percentages: N/A Media: visual Animatable: yes

The 'flood-opacity' property defines the opacity value to use across the entire filter primitive subregion. 'flood-opacity' Value: Initial: Applies to: Inherited: Percentages: Media: Animatable:

<alphavalue> | inherit 1 'feFlood' elements no N/A visual yes

This is syntax for feFlood element :

Learn SVG <feFlood

Chapter 8 Effective Filters id="name" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" flood-color="property" flood-opacity="property"/>

24

Diagram 8-12. Chart for 'feFlood' syntax

Attributes are result and flood-color : color name to fill rectangle flood-opacity : opacity for filling between 0 and 1 Example of code to use feFlood primitive :
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feFlood flood-color="red" flood-opacity='0.3' result='pict1'/> </filter>

feImage primitive Primitive feImage create raster from external graphic or defined element. This is syntax for feImage element : <feImage id="name" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage"

Learn SVG

Chapter 8 Effective Filters height="NumberOrPercentage" xlink:href="URI"/>

25

Diagram 8-13. Chart for 'feImage' syntax

Attributes are result and xlink:href :URL of external graphic or defined element

Examples of code to use feImage primitive :


<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage xlink:href='fondu3.jpg' result='pict1'/> </filter>

or
<filter id='Filter0' filterUnits='userSpaceOnUse' x='0' y='0' width='400' height='400'> <feImage xlink:href='#MyImage1' result='pict1'/> </filter> <g id='MyImage1'> <circle cx="200" cy="200" r="200" style="stroke:none;fill:red"/> <circle cx="200" cy="200" r="180" style="stroke:none;fill:white"/> <!-- other elements --> </g>

feTile primitive With feTile, we create tiling with given picture This is syntax for feTile element :

Learn SVG <feTile

Chapter 8 Effective Filters id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>"/> result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"/>

26

Diagram 8-14. Chart for 'feTile' syntax

Attributes for feTile are only x y width and height to define rectangular subregion where create tiling and in for source.
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage x="0" y="0" width="100" height="100" xlink:href='memo2.svg' result='pict1'/> <feTile x="0" y="0" width="400" height="400" in="pict1"/> </filter>

We can obtain same result using pattern, but with feTile result is defined for next primitives in the same filter element. feTurbulence primitive With feTurbulence, we create texture. This is syntax for feTurbulence element : <feTurbulence id="name" result="<filter-primitive-reference>"

Learn SVG

Chapter 8 Effective Filters x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" type="fractalNoise|turbulence" baseFrequency="NumberOptionalNumber" numOctaves="Integer" seed="Number" stitchTiles="stitch|noStitch"/>

27

Diagram 8-15. Chart for 'feTurbulence' syntax

Attributes are type: fractalNoise or turbulence for each type: baseFrequency : two positives values for x and y. ( 0 by default ) numOctaves : positive integer ( 1 by default ) seed : positive integer ( change random colors ) ( 0 by default ) stitchTiles : "stitch | noStitch" to achieve or not smooth transitions at the border Example of code using feTurbulence primitive
<filter id="Filter5" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feTurbulence type="turbulence" baseFrequency="0.21,0.21" numOctaves="4" seed='10'/> </filter>

Figure 8-11 show some examples of textures with feTurbulence. We can change colors with feColorMatrix ( Figure 8-13 ) or feComponentTransfer ( Figure 8-12 ) primitives as in this filter:
<filter id="Filter1" filterUnits="userSpaceOnUse" x="0" y="0" width="400"

Learn SVG

Chapter 8 Effective Filters

28

height="400"> <feTurbulence type='turbulence' baseFrequency='0.01,0.09' numOctaves='4' seed='2'/> <feColorMatrix type='matrix' values='0.1 0 0 0 0 0 0.3 0 0 0 0 0 0.8 0 0 0 0 0 1 0 '/> </filter>

To complete, we can add lighting ( Figure 8-14 ) to get clouds, grass or others ..
<filter id="Filter5" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feTurbulence result='pict0' type='fractalNoise' baseFrequency='0.2,0.2' numOctaves='4' seed='0' stitchTiles='noStitch'/> <feDiffuseLighting result='pict1' in='pict0' lighting-color='#d7eb2f' diffuseConstant='1' kernelUnitLength='1,1' surfaceScale='12.7'> <feDistantLight azimuth='45' elevation='35'/> </feDiffuseLighting> <feComposite in2='pict1' in='pict0' operator='arithmetic' k1='0.4' k2='0.4' k3='1' k4='0'/> </filter>

Figure 8-11. Some examples created with feTurbulence

Learn SVG

Chapter 8 Effective Filters

29

Figure 8-12. feTurbulence and feComponentTransfer

Figure 8-13. feTurbulence and feColorMatrix

Learn SVG

Chapter 8 Effective Filters

30

Figure 8-14. feTurbulence and lighting examples

Filter primitives to modify objects


feGaussianBlur primitive feGaussianBlur performs a Gaussian blur on the input image. This is syntax for feGaussianBlur element : <feGaussianBlur id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" stdDeviation="NumberOptionalNumber"/>

Learn SVG

Chapter 8 Effective Filters

31

Diagram 8-16. Chart for 'feGaussianBlur' syntax

feGaussianBlur primitive attributes are in result and stdDeviation : two positives integer for x and y ( 0 by default ) Example of code using 'feGaussianBlur' primitive
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage xlink:href='pie.svgz' result='image1'/> <feGaussianBlur in='image1' stdDeviation='2,2' /> </filter>

Figure 8-15 show effect of feGaussianBlur on SourceGraphic and SourceAlpha.

Figure 8-15. feGaussianBlur ( SourceGraphic and SourceAlpha)

Learn SVG

Chapter 8 Effective Filters

32

feMorphology primitive feMorphology performs "fattening" or "thinning" of artwork. It is particularly useful for fattening or thinning an alpha channel. This is syntax for feMorphology element : <feMorphology id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" operator="erode|dilate" radius="NumberOptionalNumber"/>

Diagram 8-17. Chart for 'feMorphology' syntax

feMorphology primitive attributes are in result and operator : erode dilate radius : two positives integer for x and y ( 0 by default ) Example of code using 'feMorphology' primitive
<filter id='Filter1' filterUnits='userSpaceOnUse' x='0' y='0' width='400' height='400'> <feImage xlink:href='memo.svgz' result='image1'/> <feMorphology in='image1' radius='4,4' operator='erode'/> </filter>

Learn SVG

Chapter 8 Effective Filters

33

Figure 8-16 show effect of 'feMorphology' primitive on svg objects and bitmap ( with erode and dilate for attribute 'operator'.

Figure 8-16. feMorphology on SVG objects and raster.

feDisplacementMap primitive feDisplacementMap uses the pixels values from the image from in2 to spatially displace the image from in. Displacement can use R G B or A channel for x-axis and y-axis. This is syntax for feDisplacementMap element : <feDisplacementMap id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" in2="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage"

Learn SVG

Chapter 8 Effective Filters width="NumberOrPercentage" height="NumberOrPercentage" scale="Number" xChannelSelector="R|G|B|A" yChannelSelector="R|G|B|A"/>

34

Diagram 8-18. Chart for 'feDisplacementMap' syntax

feDisplacementMap attributes are in in2 result and scale : number ( 0 by default give no effect ) xChannelSelector : R G B or A yChannelSelector : R G B or A In this code, we create pattern, fill rectangle (MyGrid), this rectangle is used as grid to transform jpeg picture. In Figure 8-17 we get picture named "dots".
<pattern id='motif1' x='0' y='0' width='40' height='40' patternUnits="userSpaceOnUse"> <circle cx='10' cy='10' r='10' style='stroke:black; stroke-width:1;fill:red'/> <circle cx='30' cy='30' r='10' style='stroke:black; stroke-width:1;fill:red'/> </pattern> <rect id='MyGrid' x="0" y="0" width="400" height="400" fill="url(#motif1)"/> <filter id='Filter1' filterUnits='userSpaceOnUse' x='0' y='0' width='400' height='400'> <feImage xlink:href='puzzle.jpg' result='pict1'/> <feImage xlink:href='#MyGrid' result='pict2'/> <feDisplacementMap id='fdm' scale='19' xChannelSelector='R' yChannelSelector='R' in2='pict2' in='pict1'/> </filter>

Learn SVG

Chapter 8 Effective Filters

35

Figure 8-17. feDisplacementMap on bitmap with some grids

With feDisplacementMap, we can animate attribute "scale" and get fade-in out with fine effects. feOffset primitive feOffset offsets the input image relative to its current position in the image space by the specified vector. This is syntax for feOffset element : <feOffset id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" dx="Number"

Learn SVG

Chapter 8 Effective Filters dy="Number"/>

36

Diagram 8-19. Chart for 'feOffset' syntax

feOffset primitive offsets the input image. feOffset attributes are in result and dx : offset for x ( 0 by default ) dy : offset for y ( 0 by default )

feConvolveMatrix primitive feConvolveMatrix combines pixels in the input image with neighboring pixels to produce a resulting image. This is syntax for feConvolveMatrix element : <feConvolveMatrix id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" order="NumberOptionalNumber" kernelMatrix="list of numbers" bias="Integer" targetX="Integer" targetY="Integer" preserveAlpha="true|false"

Learn SVG

Chapter 8 Effective Filters divisor="Integer" edgeMode="duplicate|wrap|none"/>

37

Diagram 8-20. Chart for 'feConvolveMatrix' syntax

feConvolveMatrix attributes are in result and order : two positives integer for x and y ( 3 by default ) kernelMatrix : order_x*order_y values to compute pixel targetX, targetY : positives integer to center effect ( order_x/2 by default ) preserveAlpha : true / false ( false by default ) bias : value to add ( 0 by default ) divisor : integer, by default sum of terms of kernelMatrix edgeMode : duplicate / wrap / none ( none by default ) Figure 8-18 show effect on svg objects. Source code of this example :
<svg width="450" height="250" viewBox="-50 -50 900 500"> <defs> <filter id="MyFilter" filterUnits="userSpaceOnUse" x="400" y="0" width="400" height="400"> <feImage xlink:href='memo.svgz' result='pict1'/> <feConvolveMatrix in='pict1' order="5 5" targetX="2" targetY="2" kernelMatrix="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1" preserveAlpha='true'/> </filter> </defs> <image x="0" y="0" width="400" height="400" xlink:href="memo.svgz"/> <rect filter="url(#MyFilter)" x="400" y="0" width="400" height="400"/> </svg>

Learn SVG

Chapter 8 Effective Filters

38

Figure 8-18. Example with feConvolveMatrix

Learn SVG

Chapter 8 Effective Filters

39

Filter primitives combination


We see some combination of primitives, as feTurbulence, feColorMatrix and feDiffuseLighting to create texture.

How create 3D lighting effect ? We can use feGaussianBlur to create shadow of object feOffset to offset this shadow feSpecularLighting on picture feComposite to composite original picture with shadow and lighting You can find online ( pilat.free.fr ) tools to test some predefined combination of primitives. Figure 8-19 is screenshot of tool to test values for attributes to create 3D lighting effect.

Figure 8-19. Screenshot of tool to create 3D lighting effect

Learn SVG How create filters ?

Chapter 8 Effective Filters

40

In design tools, you can choose filter but not create our own combination of primitives. You can find online ( pilat.free.fr ) tool to try any combination of filters : you choose your primitives, your pictures, modify values for all attributes, see final and all partial results. You get code for filter using PHP server script. Figure 8-20 show list of primitives that you can choose and Figure 8-21 show reusable svg components to modify values of attributes.

Figure 8-20. Screenshot of tool : choose a primitive

Figure 8-21. Screenshot of tool : modify values for all attributes

Learn SVG

Chapter 8 Effective Filters

41

Filters and animation


All attributes of primitives can be animated. First example : focussing on a picture using feMorphology, values for attribute radius go from 8,8 to 0,0 Figure 8-22 show some steps of animation. Code for this animation : In <defs> section
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="400" height="400"> <feImage xlink:href='puzzle.jpg' result='image1'/> <feMorphology in='image1' radius='8,8' operator='dilate'> <animate attributeName='radius' from='8,8' to='0,0' dur='5s' fill='freeze' begin='go.click' calcMode='paced'/> </feMorphology> </filter>

To use animated filter


<rect filter="url(#MyFilter)" x='0' y='0' width='400' height='400'/>

Figure 8-22. Focussing on a picture using feMorphology

Learn SVG

Chapter 8 Effective Filters

42

Second example : Simulate volcano eruption using feComponentTransfer and in feFuncR, slope go from 0.2 to 2.2 Code for this animation : In <defs> section
<filter id='MyFilter' filterUnits='objectBoundingBox' x='0%' y='0%' width='100%' height='100%'> <feComponentTransfer> <feFuncR type='linear' slope='0.2' intercept='0'> <animate repeatCount="indefinite" attributeName='slope' values="0.2;2;0.2" dur='6s' begin='0s' calcMode='paced'/> </feFuncR> </feComponentTransfer> </filter>

To use this animated filter


<image filter='url(#MyFilter)' xlink:href='volcan.jpg' x='0' y='0' width="600" height="400"/>

Figure 8-23 show some steps of this animation.

Figure 8-23. Volcano eruption with feComponentTransfer

Chapter 9 : Interactivity and Animation


"SVG content can be interactive (i.e., responsive to user-initiated events) by utilizing the following features in the SVG language:

User-initiated actions such as button presses on the pointing device (e.g., a mouse) can cause animations or scripts to execute. The user can initiate hyperlinks to new Web pages (see Links out of SVG content: the 'a' element) by actions such as mouse clicks when the pointing device is positioned over particular graphics elements. In many cases, depending on the value of the zoomAndPan attribute on the 'svg' element and on the characteristics of the user agent, users are able to zoom into and pan around SVG content. User movements of the pointing device can cause changes to the cursor that shows the current position of the pointing device." Extract of W3C specifications

Linking
Linking out of the svg content SVG provides an 'a' element, analogous to HTML's 'a' element, to indicate links. The destination for the link is defined by a URI specified by the xlink:href attribute on the 'a' element. The remote resource may be any Web resource (e.g., an image, a video clip, a sound bite, a program, another SVG document, an HTML document, an element within the current document, an element within a different document, etc.). By activating these links (by clicking with the mouse, through keyboard input, voice commands, etc.), users may visit these resources. This is the syntax for 'a' element : <a id="name" xlink:href = '<uri>' xlink:type = 'simple' xlink:role = '<uri>' xlink:arcrole = '<uri>' xlink:title = '<string>' xlink:show = 'new | replace' xlink:actuate = 'onRequest' target = "<frame-target>" > <!-- svg objects to activate link --> </a> Attributes for 'a' are

Learn SVG

Chapter 9 Interactivity and Animation

Example of code for 'a' element :


<a xlink:href="MyFile.svg"> <rect x="0" y="0" width="150" height="150" style="fill:green"/> </a>

When pointer is on rectangle, cursor become a hand and if user click, MyFile.svg is open in same window.

Linking into svg content We can link into any element using 'id' of element, but because SVG content often represents a picture or drawing of something, a common need is to link into a particular view of the document. We can define in svg, a view element, give id and call it. This is the syntax for view element <view id="name" viewBox="ViewBoxSpec" preserveAspectRatio="PreserveAspectRatioSpec" zoomAndPan="disable|magnify" viewTarget = "XML_Name [XML_NAME] "/ > To link into defined 'view' element :
<defs> <view id="MyView" viewBox="150 0 200 200"/> </defs>

We can use
<a xlink:href="#MyView"> <!-- target element --> </a>

or
<a xlink:href="#xpointer(id('MyView'))"> <!-- target element --> </a>

We can also link into new view with


<a xlink:href="#svgView(viewBox(0,200,1000,1000))"> <!-- target element --> </a>

Figure 9-1 show zoom on object by clicking it, without script :

Learn SVG

Chapter 9 Interactivity and Animation

Source code of this example ( Example 9-1 ) :


<svg width="340" height="320" viewBox="-20 -20 340 320" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="MyGradient1"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="yellow"/> </linearGradient> <linearGradient id="MyGradient2"> <stop offset="20%" stop-color="red"/> <stop offset="80%" stop-color="yellow"/> </linearGradient> <view id="MyView" viewBox="140 0 170 150"/> </defs> <rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/> <a xlink:href="#MyView"> <rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/> </a> <text x="75" y="175" style="text-anchor:middle">Offset 0 and 100</text> <text id="MyText" x="225" y="175" style="text-anchor:middle"> Offset 20 and 80 </text> <g style="stroke-dasharray:2 2;stroke:black"> <path d="M180 0l0 150"/> <path d="M270 0l0 150"/> <path d="M0 0l0 150"/> <path d="M150 0l0 150"/> </g> </svg>

Figure 9-1. Zoom on object using view element in link

Learn SVG

Chapter 9 Interactivity and Animation

Supported events
Events can be used in script or in attributes as 'begin' or 'end' for animation elements. First DOM2 category : UIEvent

Event name focusin focusout

Description Occurs when an element receives focus, such as when a 'text' becomes selected. Occurs when an element loses focus, such as when a 'text' becomes unselected. Occurs when an element is activated, for instance, thru a mouse click or a keypress. A numerical argument is provided to give an indication of the type of activation that occurs: 1 for a simple activation (e.g. a simple click or Enter), 2 for hyperactivation (for instance a double click or Shift Enter).

DOM2 name DOMFocusIn DOMFocusOut

Event attribute name onfocusin onfocusout

activate

DOMActivate

onactivate

Learn SVG

Chapter 9 Interactivity and Animation

Second DOM2 category : MouseEvent

Event name

Description

DOM2 name

Event attribute name

Occurs when the pointing device button is clicked over an element. A click is defined as a mousedown and mouseup over the same screen location. The sequence of these events is: click mousedown, mouseup, click. If multiple clicks occur at the same screen location, the sequence repeats with the detail attribute incrementing with each repetition. Occurs when the pointing device button is pressed over an mousedown element. Occurs when the pointing device button is released over an mouseup element. mouseover Occurs when the pointing device is moved onto an element. Occurs when the pointing device is moved while it is over an mousemove element. Occurs when the pointing device is moved away from an mouseout element.

(same)

onclick

(same) (same) (same) (same) (same)

onmousedown onmouseup onmouseover onmousemove onmouseout

An event set designed for use with keyboard input devices will be included in a later version of the DOM and SVG specifications.
How use this events ?

We can start animation element on event, we use event name in begin attribute : By example, animation will start by click on object with 'go' as id :
<animate begin="go.click" ................... /> <!---> <rect id="go" ........................... />

We can also start script on event, we use in this case event attribute name :
<rect onclick="MyFunction(evt)" .................... />

Learn SVG

Chapter 9 Interactivity and Animation

Third DOM2 category : MutationEvent


Event name Description DOM2 name Event attribute name none

This is a general event for notification of all changes to DOMSubtree the document. It can be used instead of the more specific Modified events listed below. (The normative definition of this event is the description in the DOM2 specification.) Fired when a node has been added as a child of another DOMNode node. (The normative definition of this event is the Inserted description in the DOM2 specification.) Fired when a node is being removed from another node. DOMNode (The normative definition of this event is the description Removed in the DOM2 specification.) Fired when a node is being removed from a document, DOMNode either through direct removal of the Node or removal of a RemovedFrom subtree in which it is contained. (The normative Document definition of this event is the description in the DOM2 specification.) Fired when a node is being inserted into a document, DOMNode either through direct insertion of the Node or insertion of InsertedInto a subtree in which it is contained. (The normative Document definition of this event is the description in the DOM2 specification.) Fired after an attribute has been modified on a node. (The DOMAttr normative definition of this event is the description in the Modified DOM2 specification.) Fired after CharacterData within a node has been DOM modified but the node itself has not been inserted or CharacterData deleted. (The normative definition of this event is the Modified description in the DOM2 specification.)

(same)

(same)

none

(same)

none

(same)

none

(same)

none

(same)

none

(same)

none

Learn SVG

Chapter 9 Interactivity and Animation

Events on document

Event name

Description

DOM2 name

Event attribute name

The event is triggered at the point at which the user agent has fully parsed the element and its descendants and is ready to act appropriately upon that element, such as being ready to render the element to the target device. SVGLoad Referenced external resources that are required must be loaded, parsed and ready to render before the event is triggered. Optional external resources are not required to be ready for the event to be triggered. Only applicable to outermost 'svg' elements. The unload SVGUnload event occurs when the DOM implementation removes a document from a window or frame. The abort event occurs when page loading is stopped SVGAbort before an element has been allowed to load completely. The error event occurs when an element does not load SVGError properly or when an error occurs during script execution. The resize event occurs when a document view is resized. SVGResize (Only applicable to outermost 'svg' elements.) The scroll event occurs when a document view is shifted in X or Y or both, such as when the document view is SVGScroll scrolled or panned. (Only applicable to outermost 'svg' elements.) Occurs when the document changes its zoom level based SVGZoom on user interaction. (Only applicable to outermost 'svg' elements.)

(same)

onload

(same) (same) (same) (same)

onunload onabort onerror onresize

(same)

onscroll

none

onzoom

Most used is SVGLoad, we can call function init(evt) on loading svg :


<svg ........ onload="init(evt)">

We use SVGResize, SVGScroll and SVGZoom when we need coordinates of pointer in viewport coordinate system for scripting. With this code :
<svg width="100%" height="100%" viewBox="0 0 600 400" preserveAspectRatio="xMinYMin meet" onresize="coordinates(evt)" >

when user resize window, svg is redraw in window, we know coordinates of pointer in window with getClientX and getClientY but not in viewport. We can use this code :
ratio=Math.min(window.innerHeight/400,window.innerWidth/600); xm=evt.getClientX()/ratio; ym=evt.getClientY()/ratio;

to get coordinates of pointer in viewport.

Learn SVG

Chapter 9 Interactivity and Animation

If origin in viewBox is not 0,0 we add coordinates of origin. If user zoom or pan, we can use currentScale, currentTranslate.x and currentTranslate.y to get coordinates of pointer. Figure 9-2 is screenshot of svg to test formula. In this case, SVG is embedded in HTML with values for width and height. We can use :
ratio=Math.min(width_svg/width_viewBox,height_svg/height_viewBox); xm=x0_viewBox+ (evt.getClientX()-svgdoc.currentTranslate.x)/ratio/svgdoc.currentScale; ym=y0_viewBox+ (evt.getClientY()-svgdoc.currentTranslate.y)/ratio/svgdoc.currentScale;

Figure 9-2. To get coordinates of pointer in viewport

Learn SVG

Chapter 9 Interactivity and Animation

Events about animations

Event name beginEvent

Description

DOM2 name none

Event attribute name onbegin

Occurs when an animation element begins. For details, see the description of Interface TimeEvent in the SMIL Animation specification. Occurs when an animation element ends. For details, see endEvent the description of Interface TimeEvent in the SMIL Animation specification. Occurs when an animation element repeats. It is raised each time the element repeats, after the first iteration. For repeatEvent details, see the description of Interface TimeEvent in the SMIL Animation specification.

none

onend

none

onrepeat

Pointer-events property The 'pointer-events' property specifies under what circumstances a given graphics element can be the target element for a pointer event. 'pointer-events' Value:

visiblePainted | visibleFill | visibleStroke | visible |painted | fill | stroke | all | none | inherit Initial: visiblePainted Applies to: graphics elements Inherited: yes Percentages: N/A Media: visual Animatable: yes

The given element can be the target element for pointer events visiblePainted when the visibility property is set to visible and when the pointer is over a "painted" area. visibleFill when the visibility property is set to visible and when the pointer is over the interior (i.e., fill) of the element. visibleStroke when the visibility property is set to visible and when the pointer is over the perimeter (i.e., stroke) of the element. visible

Learn SVG

Chapter 9 Interactivity and Animation

10

when the visibility property is set to visible and the pointer is over either the interior (i.e., fill) or the perimeter (i.e., stroke) of the element. painted when the pointer is over a "painted" area. The value of the visibility property does not effect event processing. fill when the pointer is over the interior (i.e., fill) of the element. stroke when the pointer is over the perimeter (i.e., stroke) of the element. all whenever the pointer is over either the interior (i.e., fill) or the perimeter (i.e., stroke) of the element. none The given element does not receive pointer events. For text elements, hit detection is performed on a character cell basis: The values visibleFill, visibleStroke and visible are equivalent The values fill, stroke and all are equivalent For raster images, hit detection is either performed on a whole-image basis (i.e., the rectangular area for the image is one of the determinants for whether the image receives the event) or on a per-pixel basic (i.e., the alpha values for pixels under the pointer help determine whether the image receives the event): The values visibleFill, visibleStroke and visible are equivalent. The values fill, stroke and all are equivalent.

Cursor property and element


Cursor Property 'cursor' Value: [ [<uri> ,]* [ auto | crosshair | default | pointer | move | e-resize | neresize | nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize| text | wait | help ] ] | inherit Initial: auto Applies to: container elements and graphics elements Inherited: yes Percentages: N/A Media: visual, interactive Animatable: yes This property specifies the type of cursor to be displayed for the pointing device. Values have the following meanings: auto The UA determines the cursor to display based on the current context. crosshair A simple crosshair (e.g., short line segments resembling a "+" sign).

Learn SVG

Chapter 9 Interactivity and Animation

11

default The platform-dependent default cursor. Often rendered as an arrow. pointer The cursor is a pointer that indicates a link. move Indicates something is to be moved. e-resize, ne-resize, nw-resize, n-resize, se-resize, sw-resize, s-resize, w-resize Indicate that some edge is to be moved. For example, the 'se-resize' cursor is used when the movement starts from the south-east corner of the box. text Indicates text that can be selected. Often rendered as an I-bar. wait Indicates that the program is busy. Often rendered as a watch or hourglass. help Help is available for the object under the cursor. Often rendered as a question mark or a balloon. <uri> The user agent retrieves the cursor from the resource designated by the URI. If the user agent cannot handle the first cursor of a list of cursors, it shall attempt to handle the second, etc. If the user agent cannot handle any user-defined cursor, it must use the generic cursor at the end of the list. Cursor element The 'cursor' element can be used to define a platform-independent custom cursor. A recommended approach for defining a platform-independent custom cursor is to create a PNG image and define a 'cursor' element that references the PNG image and identifies the exact position within the image which is the pointer position (i.e., the hot spot). Syntax for 'cursor' element : <cursor id = "name" x = "number" y = "number" xlink:href = "URI" />

Attributes are x : The x-coordinate of the position in the cursor's coordinate system which represents the precise position that is being pointed to. y : The y-coordinate of the position in the cursor's coordinate system which represents the precise position that is being pointed to. xlink:href : URI reference to the file or element which provides the image of the cursor

Animation
Common attributes Target element for animation We use 'xlink:href' attribute as URI reference to the target of the animation.

Learn SVG

Chapter 9 Interactivity and Animation

12

If the xlink:href attribute is not provided, then the target element will be the immediate parent element of the current animation element. Target attribute or property We use 'attributeName' and 'attributeType' attributes to specify the name of the target attribute to be modified in animation. Values for attributes : attributeName="AttributeName" attributeType="CSS|XML|auto" CSS for a CSS property XML for XML attribute auto : The implementation must first search through the list of CSS properties for a matching property name, and if none is found, search the default XML namespace for the element.
Controling the timing

This attributes are common to all animation elements : To define when animation begin : begin= 'begin-value-list' begin-value='offset-value | syncbase-value | event-value | repeat-value | accessKey-value | wallclock-sync-value | "indefinite"' offset-value : for SVG, the implicit syncbase begin is defined to be relative to the document begin. With begin="10" animation start 10 seconds after loading SVG. syncbase-value : relative to begin or end of another animation With begin="MyAnim.end+5" animation start 5 seconds after end of MyAnim animation. event-value : begin on event With begin="MyRect.click+3" animation start 3 seconds after click on MyRect object repeat-value : begin after the repeat event is raised With begin="MyAnim.repeat(2)" animation start when MyAnim is repeated 2 times. accessKey-value : begin after key pressed With begin="accessKey(g)" animation start when user press 'g' key

Learn SVG

Chapter 9 Interactivity and Animation

13

wall-clock-sync-value : begin at a real-world clock time "indefinite" : begin is determined by beginElement() method call or hyperlink targeted to the element. To define duration of animation Specifies the simple duration dur = 'Clock-value|"media"|"indefinite"' Clock-value : specifies the duration in seconds "media" is ignored for SVG animation elements "indefinite" can be usefull for 'set' element To define end of animation Defines an end value for the animation that can constrain the active duration. end = 'end-value-list' end-value='offset-value | syncbase-value | event-value | repeat-value | accessKey-value | wallclock-sync-value | "indefinite"' See begin-value for this values. With end="indefinite" end is determined by endElement() method call To define minimum and maximum values for duration of animation min = 'Clock-value|"media"' Value by default is 0 max = 'Clock-value|"media"' To define when animation can restart restart = '"always"|"whenNotActive"|"never"' "always" : animation can restart at any time. It's default value. "whenNotActive" : animation can restart when it is not active ( after end ) "never" : animation cannot be restarted for the remainder of the document duration. To define how repeat animation We determine iterations of animation by number or duration : repeatCount = 'Integer|"indefinite"'

Learn SVG

Chapter 9 Interactivity and Animation

14

repeatDur = 'Clock-value|"indefinite"' With "indefinite", animation repeat indefinitely ( until th document ends ) To define effect when animation stop fill = '"freeze"|"remove"' With fill="freeze", the animation effect is frozen for the document duration or until animation restart. With fill="remove", the animation no longer affects the target. It is the default value.
Animation values over time

This attributes have no effect for 'set' element except 'to' attribute. To define interpolation mode for the animation calcMode = "discrete | linear | paced | spline" discrete : Animation function will jump from one value to the next without any interpolation. linear : Simple linear interpolation between values is used to calculate the animation function. Except for 'animateMotion', this is the default value. paced : Defines interpolation to produce an even pace of change across the animation. This is only supported for values that define a linear numeric range, and for which some notion of "distance" between points can be calculated (e.g. position, width, height, etc.). keyTimes or keySplines will be ignored. For 'animateMotion', this is the default value. spline : Interpolates from one value in the values list to the next according to a time function defined by a cubic Bzier spline. The points of the spline are defined in the keyTimes attribute, and the control points for each interval are defined in the keySplines attribute. To define values to use We can use : values = "list of values" By example for 'viewBox' attribute, we can write values="0,0,200,200;0,0,100,100;0,0,200,200" and in animation, viewBox will go from "0 0 200 200" to "0 0 100 100" and return to "0 0 200 200". For filling color we can write values="red,yellow,green" and filling color will go from red to yellow and then to green. from = "value"

Learn SVG

Chapter 9 Interactivity and Animation

15

We give value to start animation. In our example for viewBox, we can write from="0,0,200,200" to = "value" We give value to end animation. by = "value" We give relative offset value for animation. To define pacing for animation KeyTimes keyTimes = "list of values between 0 and 1" There must be exactly as many values in keyTimes list as in values list. Each successive time value must be greater than or equal to the preceding time value. Each value represents a proportional offset into the simple duration of the animation element. With calcMode = 'paced', this attribute is ignored. With this example : keyTimes="0;0.195;0.405;0.7;1" values="0;400;47.5;450;500", if we have a duration of 10 seconds ( dur="10" ), and that values are for width attribute of a rectangle, we get this animation : From 0 to 1.95s, width of rectangle increase from 0 to 400 from 1.95s to 4.05s width of rectangle decrease from 400 to 47.5 from 4.05s to 7s width of rectangle increase from 47.5 to 450 and from 7s to 10s ( end of animation ) width increase from 450 to 500. If we get no values for keySplines, speed of animation is the same on each part.

Figure 9-3. KeyTimes and values

Learn SVG KeySplines

Chapter 9 Interactivity and Animation

16

keySplines = "list of list of 4 numbers between 0 and 1" A set of Bzier control points associated with the keyTimes list, defining a cubic Bzier function that controls interval pacing. If there is no value for keyTimes, we can use a cubic Bezier function that controls pacing for the whole animation. If calcMode is not "spline", this attribute is ignored. With our previous example : keyTimes="0;0.195;0.405;0.7;1" values="0;400;47.5;450;500" we add keySplines="0,0.5,0.5,1;0.5,0,1,0.5;0,0.5,0.5,1;0,0.5,0.5,1" and calcMode="spline" we get same four steps in animation, but we have speed which increase on steps 1 3 4 and decrease on step 2

Figure 9-4. KeySplines and speed

Figure 9-5. KeySplines and speed

Learn SVG

Chapter 9 Interactivity and Animation

17

Figures 9-4 and 9-5 show how is speed with two examples of values for keySplines We can use keyPoints for animateMotion ( see below )
To control if animations effects are additive

Values given for attribute can be added to existing value or replace it : additive = "replace|sum" replace : animation values replace existing value. It's default value. sum : animation values added to existing value When we repeat animation, effects can be cumulative or not : accumulate = "none|sum" sum : for each iteration of animation ( with repeat ) we start with new value of attribute. none : effects are not cumulative. It's default value. Data types used with 'additive' and 'accumulate' can be : <angle>, <color>, <coordinate>, <integer>, <length>, <number>, <paint>, <percentage>, <uri> and <transform-list>. Set element The 'set' element provides a simple means of just setting the value of an attribute for a specified duration or until event. This is the syntax of this element : <set id = "name" xlink:href = "URI" attributeName = "AttributeName" attributeType = "CSS|XML|auto" begin = 'begin-value-list' end = 'end-value-list' dur = 'Clock-value|"media"|"indefinite"' min = 'Clock-value|"media"' max = 'Clock-value|"media"' restart = '"always"|"whenNotActive"|"never"' repeatCount = 'Integer|"indefinite"' repeatDur = 'Clock-value|"indefinite"' fill = '"freeze"|"remove"' to = "value" />

Learn SVG

Chapter 9 Interactivity and Animation

18

All this attributes are explained above. For 'to' attribute, data types can be : <angle>, <color>, <coordinate>, <integer>, <length>, <list of xxx>, <number>, <paint>, <percentage>, <uri> or all other data types used in animatable attributes and properties.

Diagram 9-1. Chart for 'set' syntax

To show utility of this element, we create a drop down list to select a color to fill a rectangle or other element. When user click on , list of colors is writed, when pointer is on color, there is a gray rectangle on it to show that this color is selected. If user click on it, color is choosed, list of colors disappear. To cancel choice, user must click outside the list. We use no script, only 'set' elements ( Example 9-6 ) :
<svg width="400" height="400"> <!-- rectangle to apply choice of color --> <rect x="40" y="100" width="320" height="80" fill="white"> <set attributeName="fill" fill="freeze" to="red" begin="red.click"/>

Learn SVG

Chapter 9 Interactivity and Animation

19

<set attributeName="fill" fill="freeze" to="yellow" begin="yellow.click"/> <set attributeName="fill" fill="freeze" to="blue" begin="blue.click"/> <set attributeName="fill" fill="freeze" to="fuchsia" begin="fuchsia.click"/> </rect> <rect x="120" y="270" width="100" height="15" style="fill:white;stroke:none"/> <text x="130" y="282" style="text-anchor:left;font-size:12"> choose color </text> <rect x="220" y="270" width="15" height="15" style="fill:white;stroke:black"/> <path d="M222 272l11 0 -5.5 11z" style="fill:black"/> <!-- by click on rectangle list of colors is writed --> <rect id="go" x="220" y="270" width="15" height="15" style="fill:white;fill-opacity:0"/> <!-- list of colors, background, text, shadow for each --> <g display="none"> <rect x="120" y="285" width="100" height="60" fill="white"/> <text x="130" y="297" style="text-anchor:left;font-size:12"> red </text> <rect id="red" x="120" y="285" width="100" height="15" style="fill:black;fill-opacity:0"> <!-- shadow when mouse is on color --> <set attributeName="fill-opacity" to="0.2" begin="red.mouseover" end="red.mouseout"/> </rect> <text x="130" y="312" style="text-anchor:left; font-size:12">yellow</text> <rect id="yellow" x="120" y="300" width="100" height="15" style="fill:black;fill-opacity:0"> <set attributeName="fill-opacity" to="0.2" begin="yellow.mouseover" end="yellow.mouseout"/> </rect> <text x="130" y="327" style="text-anchor:left;font-size:12"> blue </text> <rect id="blue" x="120" y="315" width="100" height="15" style="fill:black;fill-opacity:0"> <set attributeName="fill-opacity" to="0.2" begin="blue.mouseover" end="blue.mouseout"/> </rect> <text x="130" y="342" style="text-anchor:left;font-size:12"> fuchsia </text> <rect id="fuchsia" x="120" y="330" width="100" height="15" style="fill:black;fill-opacity:0"> <set attributeName="fill-opacity" to="0.2" begin="fuchsia.mouseover" end="fuchsia.mouseout"/> </rect> <!-- show list of colors by click on go element, hide after choice --> <set attributeName="display" to="inline" begin="go.click" end="red.click;blue.click;yellow.click;fuchsia.click;bk.click"/> </g> </svg>

Learn SVG

Chapter 9 Interactivity and Animation

20

Figure 9-6. Drop down list to select color

Animate element The 'animate' element is used to animate a single attribute or property over time. This is the syntax of this element : <animate id = "name" xlink:href = "URI" attributeName = "AttributeName" attributeType = "CSS|XML|auto" begin = 'begin-value-list' end = 'end-value-list' dur = 'Clock-value|"media"|"indefinite"' min = 'Clock-value|"media"' max = 'Clock-value|"media"' restart = '"always"|"whenNotActive"|"never"' repeatCount = 'Integer|"indefinite"' repeatDur = 'Clock-value|"indefinite"' fill = '"freeze"|"remove"' calcMode = "discrete | linear | paced | spline" values = "list of values" from = "value" to = "value" by = "value" keyTimes = "list of values" keySplines = "list of values" additive = "replace|sum" accumulate = "none|sum" />

All this attributes are explained above.

Learn SVG

Chapter 9 Interactivity and Animation

21

Diagram 9-2. Chart for 'animate' syntax

For 'values', 'from','to' and 'by' attributes, data types can be : <angle>, <color>, <coordinate>, <integer>, <length>, <list of xxx>, <number>, <paint>, <percentage>, <uri> or all other data types used in animatable attributes and properties. SVG allows both attributes and properties to be animated. We see in chapter 7 example of animations for clipPath and in chapter 8 for filters. Some other examples :
Animate stroke-dashoffset attribute of a basic shape

Some attributes give very interesting effect, by example stroke-dashoffset allow progressive drawing of any object ( basic shape, path, text ... ) . To explain this, a very simple example, we take a line defined by a path :
<defs> <path id="line" style="stroke-width:2;stroke:black" d="m0 0l400 0"/> </defs> <use style="stroke-dasharray:400 400;stroke-dashoffset:400" xlink:href="#line" x="20" y="50"/>

Learn SVG

Chapter 9 Interactivity and Animation

22

As length of line is 400, with "stroke-dasharray:400 400;stroke-dashoffset:400" the line is not drawed. If we change value for stroke-dashoffset, we see that if we go from 400 to 800, we get progressive drawing from right to left. If we go from 400 to 0, we get progressive drawing from left to right.

Figure 9-7. Effect of stroke-dashoffset

To get progressive drawing of line we can write :


<path d="M20 20l400 0" style="stroke-dasharray:400 400;strokedashoffset:400"> <animate attributeName="stroke-dashoffset" from="400" to="0" dur="4" begin="0" repeatCount="1" fill="freeze"/> </path>

As xlink:href value is not provided, target of animate element is immediate parent, path element. We use fill="freeze" to keep drawing of line at the end of animation.
Morphing with animate on 'd' attribute of path

If we give values over animation for 'd' attribute of a path, we can obtain 'morphing' in some cases, by example : - we have only 'lineto' commands and there is same number in all values - we have Bezier cubics or quadratics First example with only 'lineto' commands in paths : The square become a star, Figure 9-8 show some steps of morphing Source code for this example ( Example 9-8 ) :

Learn SVG

Chapter 9 Interactivity and Animation

23

<svg width="600" height="400" viewBox="-300 -200 600 400"> <rect x="-300" y="-200" width="600" height="400" style="fill:#E0E0E0"/> <path d="M-100 -100l100 0 100 0 0 100 0 100 -100 0 -100 0 0 -100z" style="stroke:blue;fill-opacity:0.8; fill:blue"> <animate begin="go.click" dur="10s" repeatCount="1" attributeName="d" values="M-100 -100l100 0 100 0 0 100 0 100 -100 0 -100 0 0 100z; M-20 -20l20 -80 20 80 80 20 -80 20 -20 80 -20 -80 -80 20z; M-100 -100l100 0 100 0 0 100 0 100 -100 0 -100 0 0 100z"/> <animate begin="go.click" dur="10s" repeatCount="1" attributeName="fill" values="blue;green;blue"/> </path> <text x="250" y="180" style="font-size:25;fill:black;text-anchor:middle"> GO </text> <rect id="go" x="220" y="155" width="60" height="30" style="fill:black;fill-opacity:0.1"/> </svg>

Figure 9-8. From square to star

Second example with quadratic Bezier curves and text on path : We get morphing for text on path Figure 9-9 show some steps for animation Source code for this example ( Example 9-9 ) :

Learn SVG

Chapter 9 Interactivity and Animation

24

<svg xml:space="preserve" width="600" height="400"> <rect id="bkgrnd" x="0" y="0" width="600" height="400" style="fill:#E0E0E0"/> <defs> <path id="courbe" d="M100 200Q200,200 300,200 T500,200" style="stroke:blue;fill-opacity:0.3;stroke-width:3;fill:none"> <animate begin="go.click" dur="10s" repeatCount="1" attributeName="d" values="M100 200Q200,200 300,200 T500,200; M100 200Q200,100 300,200 T500,200; M100 200Q200,200 300,200 T500,200; M100 200Q200,300 300,200 T500,200; M100 200Q200,200 300,200 T500,200"/> </path> </defs> <text style="font-size:25;fill:red;text-anchor:middle"> <textPath id="result" method="align" spacing="auto" startOffset="50%" xlink:href="#courbe"> <tspan dy="-10"> Textpath on morphing Bezier's curve </tspan> </textPath> <animate begin="go.click" dur="10s" repeatCount="1" attributeName="fill" values="red;green;red;green;red"/> </text> <use xlink:href="#courbe"/> <text x="550" y="380" style="font-size:25;fill:black;text-anchor:middle"> GO </text> <rect id="go" x="520" y="355" width="60" height="30" style="fill:black;fill-opacity:0.1"/> </svg>

Figure 9-9. Morphing of text using animated textPath

Learn SVG

Chapter 9 Interactivity and Animation

25

Moving text on path with startOffset

We can animate 'startOffset' attribute, and text move from left to right along path. If we put in 'd' attribute the path twice, text disappear by right and reappear on left. Figure 9-10 show some steps of this animation.

Figure 9-10. Text moving along Bezier's curve

Source code for this example ( Example 9-10 ) :


<svg xml:space="preserve" width="600" height="400"> <rect x="0" y="0" width="600" height="400" style="fill:#E0E0E0"/> <defs> <path id="courbe" d="M100 200Q200,100 300,200 T500,200" style="stroke:blue;stroke-opacity:0.1;stroke-width:1;fill:none"/> </defs> <text style="font-size:25;fill:red;text-anchor:left"> <textPath id="result" method="align" spacing="auto" startOffset="0%" xlink:href="#courbe"> <tspan dy="-10"> Textpath on Bezier's curve </tspan> <animate begin="go.click" dur="5s" repeatCount="1" attributeName="startOffset" values="0%;100%"/> </textPath> </text> <use xlink:href="#courbe"/> <text x="550" y="380" style="font-size:25;fill:black;text-anchor:middle"> GO

Learn SVG

Chapter 9 Interactivity and Animation

26

</text> <rect id="go" x="520" y="355" width="60" height="30" style="fill:black;fill-opacity:0.1"/> </svg>

AnimateColor element The 'animateColor' element specifies a color transformation over time.

Diagram 9-3. Chart for 'animateColor' syntax

This is the syntax of this element : <animateColor id = "name" xlink:href = "URI" attributeName = "AttributeName" attributeType = "CSS|XML|auto" begin = 'begin-value-list' end = 'end-value-list' dur = 'Clock-value|"media"|"indefinite"' min = 'Clock-value|"media"' max = 'Clock-value|"media"' restart = '"always"|"whenNotActive"|"never"' repeatCount = 'Integer|"indefinite"' repeatDur = 'Clock-value|"indefinite"' fill = '"freeze"|"remove"' calcMode = "discrete | linear | paced | spline" values = "list of values"

Learn SVG

Chapter 9 Interactivity and Animation from = "value" to = "value" by = "value" keyTimes = "list of values" keySplines = "list of values" additive = "replace|sum" accumulate = "none|sum" />

27

All this attributes are explained above. For 'values', 'from','to' and 'by' attributes, data types can be only <color>. AnimateTransform element The 'animateTransform' element animates a transformation attribute on a target element, we can use translation, scaling, rotation and/or skewing. If we will animate 'matrix' transform, we have to use script because 'animate' can not use <transform-list> data. This is the syntax of this element : <animateTransform id = "name" xlink:href = "URI" attributeName = "AttributeName" attributeType = "CSS|XML|auto" begin = 'begin-value-list' end = 'end-value-list' dur = 'Clock-value|"media"|"indefinite"' min = 'Clock-value|"media"' max = 'Clock-value|"media"' restart = '"always"|"whenNotActive"|"never"' repeatCount = 'Integer|"indefinite"' repeatDur = 'Clock-value|"indefinite"' fill = '"freeze"|"remove"' calcMode = "discrete | linear | paced | spline" values = "list of values" from = "value" to = "value" by = "value" keyTimes = "list of values" keySplines = "list of values" additive = "replace|sum" accumulate = "none|sum" type = "translate | scale | rotate | skewX | skewY" />

Learn SVG

Chapter 9 Interactivity and Animation

28

Diagram 9-4. Chart for 'animateTransform' syntax

All this attributes are explained above except 'type' . Attribute 'type' Indicates the type of transformation which is to have its values change over time. Values in 'from' 'to' 'by' or 'values' have to be : for a type="translate", as <tx> [,<ty>]. for a type="scale", as <sx> [,<sy>]. for a type="rotate", as <rotate-angle> [<cx> <cy>]. for a type="skewX" and type="skewY", as <skew-angle>.

Figure 9-11. Effects using type="scale"

Learn SVG

Chapter 9 Interactivity and Animation

29

Figure 9-11 show some examples using type="scale". We can get rotation around horizontal or vertical axis, or decrease/increase size of object. Figure 9-12 show effect of skewX and skewY.

Figure 9-12. Effects using skewX or skewY

We can use 'animateTransform' element to create effect on letters of word 'SVG', each letter turn around vertical axis. We add 'animateColor' element to change color for filling letters to give impression that we see back of letters. Figure 9-13 show some steps of animation.

Figure 9-13. Letters of SVG turn around vertical axis

As we use 'scale' transformation, center is at origin, so we define letters with y="0" and put them in place in the word with a translation. Animation begin by click on button ( with "go" as 'id' ) Source code for this example ( Example 9-13 ) :
<svg width="200" height="200"> <rect id='contour' x='0' y='0' width='200' height='200' style='stroke:green;fill:yellow'/> <g transform="translate(42,101)"> <text x="-22.76" y="0" style="text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black;" transform="scale(1,1)" startOffset="0">

Learn SVG

Chapter 9 Interactivity and Animation

30

S <animateTransform attributeName="transform" type="scale" values="1,1;0,1;-1,1;0,1;1,1" begin="go.click" repeatCount="1" dur="5s"/> <animateColor attributeName="fill" values="red;gray;gray;gray;red" begin="go.click" repeatCount="1" dur="5s"/> </text> </g> <g transform="translate(98,101)"> <text x="-26.1737" y="0" style="text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black;" transform="scale(1,1)" startOffset="0"> V <animateTransform attributeName="transform" type="scale" values="1,1;0,1;-1,1;0,1;1,1" begin="go.click" repeatCount="1" dur="5s"/> <animateColor attributeName="fill" values="red;gray;gray;gray;red" begin="go.click" repeatCount="1" dur="5s"/> </text> </g> <g transform="translate(153,101)"> <text x="-26.4801" y="0" style="text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black;" transform="scale(1,1)" startOffset="0"> G <animateTransform attributeName="transform" type="scale" values="1,1;0,1;-1,1;0,1;1,1" begin="go.click" repeatCount="1" dur="5s"/> <animateColor attributeName="fill" values="red;gray;gray;gray;red" begin="go.click" repeatCount="1" dur="5s"/> </text> </g> <rect x="10" y="180" width="50" height="18" fill="black"/> <text x="35" y="195" style="text-anchor:middle;font-weight:bold; font-size:15;font-family:Arial;fill:white;stroke:black"> GO </text> <rect id="go" x="10" y="180" width="50" height="18" opacity="0.1"/> </svg>

With script, we can automatize this animation, we have only to give text to be animated. See below about script and SMIL animation. AnimateMotion element The 'animateMotion' element causes a referenced element to move along a motion path. Type of element can be : 'g' , 'defs' , 'use' , 'image' , 'switch' , 'path' , 'rect' , 'circle' , 'ellipse', 'line', 'polyline', 'polygon' , 'text' , 'clipPath' , 'mask' , 'a' or 'foreignObject' This is the syntax of this element : <animateMotion id = "name" xlink:href = "URI" attributeName = "AttributeName"

Learn SVG

Chapter 9 Interactivity and Animation attributeType = "CSS|XML|auto" begin = 'begin-value-list' end = 'end-value-list' dur = 'Clock-value|"media"|"indefinite"' min = 'Clock-value|"media"' max = 'Clock-value|"media"' restart = '"always"|"whenNotActive"|"never"' repeatCount = 'Integer|"indefinite"' repeatDur = 'Clock-value|"indefinite"' fill = '"freeze"|"remove"' calcMode = "discrete | linear | paced | spline" values = "list of values" from = "value" to = "value" by = "value" keyTimes = "list of values" keySplines = "list of values" additive = "replace|sum" accumulate = "none|sum" path = "<path-data>" keyPoints = "<list-of-numbers>" rotate = "<angle> | auto | auto-reverse" origin = "default"> <mpath id = "name" xlink:href = "URI" /> < /animateMotion>

31

All this attributes are explained above except : path : The motion path, expressed in the same format and interpreted the same way as the 'd' attribute on 'path' element. keyPoints : a semicolon-separated list of floating point values between 0 and 1 and indicates how far along the motion path the object shall move at the moment in time specified by corresponding keyTimes value. rotate values auto : the object is rotated over time by the angle of the direction. auto-reverse : angle of the direction plus 180 degrees. <angle> : angle relative to the x-axis. ( 0 by default ) origin : no effect for SVG

Learn SVG

Chapter 9 Interactivity and Animation

32

Diagram 9-5. Chart for 'animateMotion' syntax

To define path for 'animateMotion' we can write :


<animateMotion path="M100,250 C 100,50 400,50 400,250" ....... />

or
<defs> <path id="MyPath" d="M100,250 C 100,50 400,50 400,250" /> </defs> <animateMotion ...................... <mpath xlink:href="#MyPath" /> </animateMotion>

>

For keyPoints attribute, if we have keyTimes = "0;0.25;0.5;0.7;1" keyPoints = "0;0.5;0.25;0.75;1" and dur = "10" We have four steps in animation : 1) Object go from begin of trajectory to middle in 2.5 seconds 2) Object go back to quarter of trajectory in 2.5 seconds 3) Object go ahead to three quarters of trajectory in 2 seconds 4) Object go to end of trajectory in 3 seconds

Learn SVG

Chapter 9 Interactivity and Animation

33

Figure 9-14 show this example.

Figure 9-14. keyPoints and keyTimes

We can add keySplines to give various speed for each step. Figure 9-15 show effect of values for 'rotate' attribute.

Figure 9-15. Different values for 'rotate' attribute

Learn SVG

Chapter 9 Interactivity and Animation

34

Animation and scripting


We can create animations by script or use script to create animated elements.
Script to create animated elements

With example of each letter of word 'SVG' turning around vertical axis, we can by script obtain all values to put letters in place and add animated elements. For each letter there is two transformations, 'scale' to turn letter around vertical axis and 'translate' to put letter in place. We must use additive='sum' to only modify values for 'scale' and keep same 'translate' transform. Example 9-16 :
<svg width='200' height='200' onload="init(evt)"> <script type="text/ecmascript"> <![CDATA[ // string to be animated var text_data='SVG'; var svgdoc="";
// function to create letters and animated elements on loading svg

function init(evt) {
// create hidden text element with text_data as data

svgdoc=evt.target.ownerDocument; node=svgdoc.createElement("text"); node.setAttribute("x","100"); node.setAttribute("y","100"); node.setAttribute("style","visibility:hidden;text-anchor:middle; font-size:80;font-family:Arial;fill:black"); node.setAttribute("id","texte"); texte=svgdoc.createTextNode(text_data); node.appendChild(texte); where=svgdoc.getElementById('word'); where.appendChild(node);
// extract of hidden text element each letter to draw it and add animation

objet=svgdoc.getElementById('texte'); for (i=0;i<text_data.length;i++) { // draw each letter f=objet.getExtentOfChar(i); node=svgdoc.createElement('text'); node.setAttribute('x',-f.width/2); node.setAttribute('y',"0");

Learn SVG

Chapter 9 Interactivity and Animation

35

node.setAttribute('style','text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black'); node.setAttribute('transform','translate('+(f.x+f.width/2)+',' +(f.y+f.height)+') scale(1 1)'); texte=svgdoc.createTextNode(text_data.substring(i,i+1)); node.appendChild(texte); // add animateTransform using scale node_anim=svgdoc.createElement('animateTransform'); node_anim.setAttribute('attributeName','transform'); node_anim.setAttribute('type','scale'); node_anim.setAttribute('additive','sum'); node_anim.setAttribute('values','1,1;0,1;-1,1;0,1;1,1'); node_anim.setAttribute('begin','go.click'); node_anim.setAttribute('repeatCount','1'); node_anim.setAttribute('dur','5s'); node.appendChild(node_anim); // add animateColor element node_anim=svgdoc.createElement('animateColor'); node_anim.setAttribute('attributeName','fill'); node_anim.setAttribute('values','red;gray;gray;gray;red'); node_anim.setAttribute('begin','go.click'); node_anim.setAttribute('repeatCount','1'); node_anim.setAttribute('dur','5s'); node.appendChild(node_anim); where.appendChild(node); } }; ]]> </script> <rect id='contour' x='0' y='0' width='200' height='200' style='stroke:green;fill:yellow'/> <g id='word'> </g> <rect x="10" y="180" width="50" height="18" fill="black"/> <text x="35" y="195" style="text-anchor:middle;font-weight:bold; font-size:15;font-family:Arial;fill:white;stroke:black"> GO </text> <rect id="go" x="10" y="180" width="50" height="18" opacity="0.1"/> </svg>

After loading svg, svg elements are the same that in first version of this example. We can also use parseXML to create svg fragment and append it to DOM
for (i=0;i<text_data.length;i++) { // draw each letter and add animate elements f=objet.getExtentOfChar(i); // build string to parse

Learn SVG

Chapter 9 Interactivity and Animation

36

string_to_parse ="<text x='" +(-f.width/2) +"' y='0' style='text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black;' transform='translate(" +(f.x+f.width/2) +"," +(f.y+f.height) +") scale(1,1)' startOffset='0'>" +text_data.substring(i,i+1) +"<animateTransform attributeName='transform' type='scale' additive='sum' values='1,1;0,1;-1,1;0,1;1,1' begin='go.click' repeatCount='1' dur='5s'/>" +"<animateColor attributeName='fill' values='red;gray;gray;gray;red' begin='go.click' repeatCount='1' dur='5s'/></text>" // parse string and add it to svgdoc svg_fragment=parseXML(string_to_parse,svgdoc); // append elements to DOM where.appendChild(svg_fragment); }

We can add in string to parse "\n" for linefeed, so with "copy SVG" we can read easier code for svg elements.
Script to create animation

We can take same example and create animation only by script. Source code for this example ( Example 9-8 ) :
<svg width='200' height='200' onload="init(evt)"> <script type="text/ecmascript"> <![CDATA[ var timevalue = 0; var timer_increment = 50; // each 50 milliseconds matrix change var max_time = 5000; // duration for animation in milliseconds var text_data='SVG'; // string to be animated var svgdoc=""; var x_letter=new Array; var y_letter=new Array; // function to create object on loading svg function init(evt) { // create hidden text element with text_data as data svgdoc=evt.target.ownerDocument; node=svgdoc.createElement("text"); node.setAttribute("x","100"); node.setAttribute("y","100"); node.setAttribute("style","visibility:hidden;text-anchor:middle; font-size:80;font-family:Arial;fill:black");

Learn SVG

Chapter 9 Interactivity and Animation

37

node.setAttribute("id","texte"); texte=svgdoc.createTextNode(text_data); node.appendChild(texte); where=svgdoc.getElementById('word'); where.appendChild(node); // extract of hidden text element each letter to draw it objet=svgdoc.getElementById('texte'); for (i=0;i<text_data.length;i++) { f=objet.getExtentOfChar(i); x_letter[i]=f.x+f.width/2; y_letter[i]=f.y+f.height; node=svgdoc.createElement('text'); node.setAttribute("id","letter"+i.toString()); node.setAttribute('x',-f.width/2); node.setAttribute('y',"0"); node.setAttribute('style','text-anchor:left;font-weight:bold; font-size:80;font-family:Verdana;fill:red;stroke:black'); node.setAttribute('transform', 'translate('+x_letter[i]+','+y_letter[i]+') matrix(1 0 0 1 0 0)'); texte=svgdoc.createTextNode(text_data.substring(i,i+1)); node.appendChild(texte); where.appendChild(node) } }; // function to create animation function anime(evt) { timevalue = timevalue + timer_increment; // end of animation on condition if (timevalue > max_time) { timevalue=0;return }; // give value for matrix if (timevalue<=2500) { taille=(1250-timevalue)/1250 } else { taille=(timevalue-3750)/1250 }; if (taille==0) { taille=0.001 }; // affect value to matrix for each letter for (i=0;i<text_data.length;i++) { node=svgdoc.getElementById('letter'+i.toString()); node.setAttribute("transform",

Learn SVG

Chapter 9 Interactivity and Animation


'translate('+x_letter[i]+','+y_letter[i]+ ') matrix('+taille+' 0 0 1 0 0)');

38

// change filling color to show back of letters if (timevalue==1250) { node.getStyle.setProperty("fill","gray") }; if (timevalue==3750) { node.getStyle.setProperty("fill","red") }; }; // recursive call to function setTimeout("anime()", timer_increment) }; // declare function as 'window' object window.anime = anime; ]]> </script> <rect x='0' y='0' width='200' height='200' style='stroke:green;fill:yellow'/> <g id='word'> </g> <rect x="10" y="180" width="50" height="18" fill="black"/> <text x="35" y="195" style="text-anchor:middle;font-weight:bold; font-size:15;font-family:Arial;fill:white;stroke:black"> GO </text> <rect onclick="anime(evt)" id="go" x="10" y="180" width="50" height="18" opacity="0.1"/> </svg>

Chapter 10 : Scripting the DOM


What well look at in this chapter An overview of the ECMAScript Language and the components it give us to work with The workings of the Document Object Model Adding and removing elements in our SVGs Adding interactivity Handling mouse events Some cool examples combining these skills

The ECMAScript Language


ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment.

To change a static non-interactive document into a highly dynamic interactive document the W3C provides us with a couple of efficient objects embedded in a framework called the Document Object Model or DOM. Since we want to communicate with these objects, well need an appropriate language a programming language. In this chapter we will be introduced to a suitable programming language ECMA script and we will be introduced to the concepts of the DOM. Now dont be put off by the word programming. I am a web designer, I am no programmer is often the reaction. However, as a designer, I can also guarantee that you wont want to miss out on the power and aesthetics scripting can bring to your design. After reading this chapter you will be able to use third party script libraries with ease. And if you are more engaged you will have a good starting point for your own scripting projects. So what is this ECMAthing, we need to learn? ECMAs JavaScript Roots A while back, Netscape decided to add a scripting language to their Navigator browser. With that, they reasoned, Web designers would be allowed to add rich interactive and dynamic features to their Web pages without the need to do complicated server-side CGI programming or Java applet development. That scripting language should have the look and feel of C++ and Java. On the other hand it had to be simple and easy to learn, so that non-programming web designers or scripters working with Basic were not intimidated. Since everybody was talking about Java at the time, they called it Javascript, although there were not many similarities between these languages apart from the syntax.

Learn SVG

Chapter 10 Scripting the DOM

Javascript was a success and web sites with embedded scripts proliferated. Stimulated by this other scripting languages emerged and threatened to litter the web with a variety of proprietary solutions. So Netscape, Microsoft, and other major players agreed to form a standards committee. They handed the language specification over to the European Computer ManufacturersAssociation (ECMA) as an Open Standard. Today the third edition of the standard called ECMAScript is considered stable and powerful. There is rarely a browser developer, that does not claim to own an ECMAScript conformant scripting language. Netscapes Javascript and Microsofts Jscript language are examples of ECMAScript compliant languages within their respective browsers. A Note on Scripting A scripting language is somewhat different from a conventional programming language such as FORTRAN, PASCAL, or C++. A script is not translated by a compiler as a whole to form an executable program. It is usually interpreted by a scripting engine (interpreter) statement-by-statement. ECMAScript is an interpreted, object-based scripting language. Although it has fewer capabilities than full-fledged object-oriented languages like C++, ECMAScript is more than sufficiently powerful for its intended purposes as a Web Scripting Language. The ECMA basics This chapter wont cover the whole of the ECMAScript language. Instead well restrict the overview to those language essentials we intend to put good use to here. An ECMAScript program is written in text format. This text is organized into statements, comments and blocks. Each block can repeatedly consist of other statements, comments and blocks. Within each statement we find data types, variables and expressions. Thus if we examine an admittedly human, weekly thought process, the result in ECMAScript may appear as below.
var action = , today = DayOfWeek(); if (today == Sunday) action = sleeping; else if (today == Saturday) action = shopping; else // waiting for weekend .. action = working;

In the example above we come across statements (the if () else () blocks), comments (waiting for weekend), expressions (today==Sunday) and variables (action). Data Types are also to be found, though we only use one type above.
Data Types

ECMAScript is a loosly typed language as opposed to the strongly typed conventional programming languages. Loosly typed here means, that we the script programmers need not to care explicitely about the types we use in our program. This doesnt mean, that ECMAScript has no different data types. ECMAScript will rather do the data type management for us and always implicitly assign the correct data type to our variable or return the correct data type from a function. With this we can define variables in a very convenient manner via the var statement. Lets have a closer look at the data types in detail ECMAScript can deal with.

Learn SVG
Number

Chapter 10 Scripting the DOM

Number is the data type for numerical values. There is no distinction between whole numbers (integers) and rational floating point numbers (floats) as in other languages. Here are some literals.
-273, 1024, 0 -6.28, 0.25, 66.666667 0.001, .001, 1.0e-3, 1E-3 // negative and positive integers .. // negative and positive fractional numbers .. // variations of one per thousand

String

String is the type for textual data. ECMAScript does not differentiate between a multi-character text and a single character as other languages do (for example C++ and Java). String literals are enclosed in single () or double () quotes.
Although it is possible to use either single or double quotes to enclose these literals you should remember that you must use them consistently. For this reason I suggest that you pick a style and stick to it to avoid receiving an error message, simply because youve opened with a single quote and closed with a double. a short text, another text mikes bike, he said: hello c, C, 4, , , \, \n, \, \\ // // // // // the text delimiters .. inverse delimiter usage .. different single characters .. the empty string .. special characters, escape via backslash

Boolean

There is also a logical data type. This Boolean type can have one of two values.
true, false // the two Boolean values .. and false

In ECMAScript the values true


Object

conform to 1

and 0.

Object is the most important data type the one, that makes ECMAScript an object oriented language. There are no discrete values assigned to this data type. An Object can instead be considered as a container that embeds other data types and other Objects. Well cover Objects in more detail later. Comments I imagine most of you are already familiar with the comment an esteemed and trusty friend of any coder. A comment in an ECMAScript program does nothing; it is not even executed, though it is not useless. A comment usually concludes additional information about the programs source code. ECMAScript adopted the single-line and multi-line comments from C++ and Java. A single-line comment starts with a pair of forward slashes (//) as in
else // waiting for weekend ..

and ends with the end of the line. A multi-line comment begins with a forward slash and asterisk (/*) and ends with the reverse pattern, an asterisk and forward slash (*/).
/* for this nontrivial comment several lines are required */

Learn SVG

Chapter 10 Scripting the DOM

All text between /* .. */ is considered by ECMAScript to be non-program code. Please also note, that multi-line comments cannot overlap or nest. I recommend you use single-line comments for commenting your source code only. Multi-line comments can then be useful to comment multiple lines out for debugging purposes. This means simply that if you receive an error message, you can test different parts of your code for bugs by fencing them off with comment slashes and running the code without them. Variables As in many programming languages you will use variables in ECMAScript programs extensively. Think of a variable as a named container that can hold exactly one value. With that we can access this value by simply using the variables name. Since ECMAScript is a loosely typed language, a variable can hold a value of any data type. During the variables lifetime that data type can even change.
var pi = 3.14, radius = 100; var circumference = 0, area = 0; circumference = 2*pi*radius; area = pi*radius*radius; pi = hello; // // // // // define two variables .. .. and another two .. assign a value .. .. to each variable change pis data type ..

A variable gets defined by using the reserved word var, and, after this definition, can be used in an expression. Under certain circumstances ECMAScript allows you to use a variable without explicit definition, but it is a good programming practice and I strongly recommend you to always define a variable. There is very little limit on what we actually call our variables. In particular the length of the name is not limited at least not practically.
It is always a good practice, to choose expressive, meaningful variable names that will tell anyone, who reads our program, what that variable is represents

We are not absolutely free with the naming of variables, we do have to follow certain rules: The first character has to be a lowercase or uppercase letter or an underscore. All subsequent characters can be letters, decimal digits and underscores. ECMAScripts reserved words (var, for, if, else, ..) are not allowed as variable names. When you are defining a variable (by var) you need not assign an initial value to it, but here too I strongly recommend that you do so. . With this you avoid usually hard to track program bugs resulting from computations with un-initialised variables. If you do not assign a value explicitly while initialisation, the variable gets the value undefined by default. Expressions An expression is a piece of ECMAScript code that results in a certain value when it is evaluated, as shown below.
var pi = 3.14, radius = 100, str = hello; var color = green; 2+3/2 (2+3)/2 radius*2/10 2*pi*radius; radius == 100 str == blue str + Mary // // // // // // // // // defining some .. .. variables 3.5 2.5 20 628 true false hello Mary

Learn SVG

Chapter 10 Scripting the DOM


// 5 // 1 // false

str.length Math.sin(Math.PI/2) color == red || color == blue

An expression can consist of Numbers, Strings, Boolean literals Operators (+, -, *, /, ) Variables Function calls Object properties or object method calls An expressions value can take the form of a number, a string or a boolean expression.
Operator please

ECMAScript supplies us with a large set of operators. Most of them are binary operators (eg +) with two operands as in 2+3. There are also unary operators as in i++ with one operand i and the increment operator ++. The operators can be subdivided into different categories.
Category Operator Arithmetic operators + * / % ++ -Assignment += operators -= *= /= % String operators Comparison operators + += == != > >= < <= Logical operators && || ! Means Addition Subtraction Multiplication Division Modulus Increment Decrement Negation Addition Subtraction Multiplication Division Modulus Concatenation Concatenation is equal to does not equal is greater than is greater than or equal to is less than is less than or equal to AND OR NOT Example 1+2 8-6 2*3 10/3 10%3 x = 3; x++ x = 5; x--2 x += y x -= y x *= y x /= y x %= y "hello "+"world" a += b 2 == 3 2 != 3 5>3 5 >= 3 5<3 5 <= 3 (3 <= 5) && (5 < 8) (5 > 3) || (3 > 5) 5 != 3 Equals 3 2 6 3.3333333333 1 x=4 x=4 negative 2 x=x+y x=x-y x=x*y x=x/y x=x%y "hello world" a=a+b false true true true false false true true true

The ECMAScript + operator has the remarkable characteristic, not only to add numbers as in 3+7, but also to concatenate strings, so SVG +is +cool would become SVG is cool.

Learn SVG

Chapter 10 Scripting the DOM

Statements A statement can be considered a meaningful sentence in the ECMAScript language. It typically makes intensive use of expressions. When the statement is executed, it performs a certain action so we can look at a program as a collection of statements in order to carry out a complete task.
var name = Robin; document.write(Hello + name + how are you?);

The scripting engine looks for any semicolon (;) as the terminating character of statements. With this you can write statements that span several lines, or you can write multiple statements in a single line. It is generally considered good programming practice to write one statement per line, though today script engines are somewhat forgiving with missing semicolons.
Despite this I strongly recommend to always add a semicolon at the end of any statement. This will ensure that your statements are executed exactly as you intend and will also cover you for forwards compatibility.

An ECMAScript program is executed top down. This default program flow starts with the first statement and ends with the last. With this sequential execution we can only write relatively simple programs, so ECMAScript as other programming languages supports junctions and repetitions in its program flow.
Conditional Statements

The conditional if statement allows us to execute a number of statements depending on the result of a certain condition.
if (<condition>) { <statements>; }

The statements following the if(..)(known as the if block) are executed only if the condition a Boolean expression enclosed in the parenthesis evaluates to true. When we need to have several statements belonging to the if, we have to enclose those within curly braces {}. In the case of just one statement we are allowed to omit them.
Handing several possibilities with ifelse

The if..else statement adds the ability to specify alternate lines of code for a case when the ifcondition evaluates to false. For example, in the code below, the containment of a point (x, y) in a square at (100, 200) with a size of 50 is checked.
if (x < 100 || y < 200 || x > 150 || y > 250) inside = false; else inside = true;

Frequently if..else statements are concatenated, so that several conditions can be tested.
if (background == black) color = white; else if (background == white) color = black; else color = blue;

Learn SVG
Iteration Statements

Chapter 10 Scripting the DOM

The repetitive while-statement works in a similar fashion to the if statement, with the difference that the affiliated statements arent executed only once, but again and again as long as the condition the Boolean expression evaluates to true.
while (hour >= 8 && hour <= 17) { action = working; }

The above example relies on a changing value of the variable hour. Otherwise wed end up implementing an endless loop, which is unable to break out of its own cycle. Frequently there is a need to visit all elements of a container. For this we generally introduce a counter variable, which must then be incremented with every iteration step as long as there is another element in the container. This is commonly referred to as initialization, condition, update.
var sum = 0; for (var i=1; i<=100; i++) { sum += i; // same as .. sum = sum + i; }

Will sum up all numbers from 1 to 100 resulting in a final sum value of 5050. With this example Ill introduce you to ECMAScripts important for statement. Lets have a closer look at its syntax.
for (<initialization>; <condition>; <update>) { <statements>; }

Beside the <condition>, a Boolean expression which we encountered in the while loop, we can also have an <initialization> and <update> section here in the for-loop. This works according to the following instructions: Enter the for loop. Define and/or initialize one or more variables in the <initializing> section. Evaluate the <condition>. If the <condition> evaluates to true, enter the loops body. Otherwise leave the loop and execute next code Otherwise Execute the <statements>. The <incrementing> section consists of addition to, or subtraction from, the value. Return to condition. The for loop is the most frequently used loop in C++, Java and ECMAScript, because it comes with the ability to also define, initialise and update the iteration variable. Please note, that we can leave one, two or even all of the three sections <initialization>; <condition>; <update> blank. But you must not omit any of the semicolons. Adherent to the iteration statement is the break statement. Whenever it is executed, the immediate surrounding loop will be exited.

Learn SVG

Chapter 10 Scripting the DOM

for (;;) // forever .. all sections are empty .. { if (hour >= 22) break; action = working; }

There are more conditional and iteration statements in ECMAScript, but we wont cover them here. Those of you wishing to discover the joys of switchcase, dowhile and forin will have to hunt elsewhere. ECMAScript Functions As Ive mentioned, the typical ECMAScript program is executed top down, and this restricts the sophistication of our code somewhat. Well supposing we could isolate a piece of code that performs a specific task give that code a descriptive name execute that code from arbitrary points in our program hand over some actual values to this piece of code

That would be handy, wouldnt it? This is exactly what a function is for. Computer scientists say:
Procedures (Functions) are the bricks of a structured programming language.

Calculating the length of a line with a simple function Lets have a look at an example of a short ECMAScript function definition. An SVG line element has the attributes x1, y1, x2, y2 to specify its start and end points. Assume that we frequently need to calculate the length of a line, so we decide to write a piece of code for exactly that purpose. Here is that code working on a html page. Please note, how we use the <script> element to embed ECMAScript code.
<html> <head> <title> 'Calculate Length Of a Line' </title> </head> <body> <h1> 'Calculate Length Of a Line' </h1> <script type="text/ecmascript"> function LengthOfLine(x1, y1, x2, y2) { var dx = x2 - x1, dy = y2 - y1, lenSqr = dx*dx + dy*dy, len = Math.sqrt(lenSqr); return len; } var xpnt1 = 3, ypnt1 = 5, xpnt2 = 6, ypnt2 = 9; var lineLength = 0; lineLength = LengthOfLine(xpnt1, ypnt1, xpnt2, ypnt2); document.write("Length of Line is " + lineLength); // 5 .. </script> </body> </html>

Learn SVG

Chapter 10 Scripting the DOM

Lets have a look at how the function code is built-up. 1. Firstly, we start to implement an ECMAScript function using the keyword function. 2. Behind this we type the function name here LengthOfLine. For this we are restricted to the same rules while choosing a variable name, i.e. only letters, underscore and decimal digits (for following characters) are allowed.
function LengthOfLine

3. Immediately following our new function name comes a pair of parenthesis that enclose a list of comma-separated formal arguments (x1, y1, x2, y2). Those arguments are the names of variables that can be used inside the functions body. 4. That function body is always enclosed in curly braces {..} immediately following the functions head. Inside the functions body we define some variables (dx, dy, lenSqr and len) and initialize them with some number expressions. 5. Now comes the Math. We build the difference of the x and y co-ordinates and calculate the square of the lines length lenSqr, according to Pythagoras' Theorem (c2 = a2 + b2).
lenSqr = dx*dx + dy*dy

6. To get the actual length len of the line, we use an ECMAScript objects function Math.sqrt, that calculates the square root for us. We then hand this back to our calling program code using the return statement.
len = Math.sqrt(lenSqr); return len

Calling Functions

We can do exactly two things with a function. We can define it, i.e. write its code, and call it, i.e. get its code executed. Now, as we understand the common skeleton of a function as well as the structure of the above example, it might be interesting to see how exactly a function is called.
var xpnt1 = 3, ypnt1 = 5, xpnt2 = 6, ypnt2 = 9; var lineLength = 0; lineLength = LengthOfLine(xpnt1, ypnt1, xpnt2, ypnt2);

// 5 ..

The function call looks very similar to the function definition. Again we use the function name LengthOfLine to call the function that is to execute the code of the function definitions body. Since our function expects four arguments, we have to provide those, again enclosed in parenthesis. We use the variables xpnt1,ypnt1,xpnt2,ypnt2 here as actual arguments. The functions data type yes, a function does have a data type is of the same type as the variable or expression we used with the return statement. With this we can use the function call wherever we can use any variable or expression of that type.

Learn SVG

Chapter 10 Scripting the DOM

10

I really urge you to become familiar with functions, not just because we will use them in detail throughout the rest of this chapter, but because they really are handy things to have at your disposal.
Function Guidelines

So what else should we know about functions? A function with a particular name must be defined only once. A particular function can be called arbitrarily from the rest of the program. A function can call other functions and itself. A function can have an arbitrary number of arguments, even none. A function with no arguments must be written with empty parenthesis () both at definition and call. The number of function arguments and their type should match in definition and call. Local variables defined in a functions body cannot be used outside that function. The functions formal arguments can be considered as local variables within the function. ECMAScript Objects ECMAScript is a language that is designed for working inside of a host environment the web browser for example. The great benefit here comes with the fact that the host environment exposes its own objects to ECMAScript, which can then access these objects for informational purpose, but also for modifying them or even for creating new objects. With this, ECMAScript can customize the facilities of any script hosting software system and add powerful functionality. As a prerequisite we need to know a little more about objects. We have already learned that we can view an object as a bag full of embedded data the Objects members. If a member is a variable, we call it an Objects property. If a member is a function, it is called an Objects method. In order to access an objects members we will use the dot-operator (.). With object variables we need the special null value quite frequently. Variables that currently hold no object will be assigned the null value to signal this.
Math.PI, list.length document.write(hello) var group = null; // Objects properties .. // Objects method call .. // variable with no value ..

But where do we meet objects? ECMAScript comes with a few intrinsic objects. The W3Cs DOM provides us with a lot of powerful objects. Java or ActiveX software components expose objects We can design our own objects with ECMAScript.

We wont be designing our own objects here, but we can cover the first three options, so lets begin with a look at the very common intrinsic ECMAScript objects. These consist of

Learn SVG
Array Boolean Date Function Global Math Number Object RegExp Error String

Chapter 10 Scripting the DOM

11

If you are experienced with other object oriented languages, you might ask, why we dont talk about classes here. So please note, that ECMAScript is a prototype-object based language, i.e. everything is an object. ECMAScript in its current version 3.0 has no classes, the next generation ECMAScript 4.0 will introduce them. ECMAScript objects must be explicitly created. This is contrary to the other so called intrinsic data types like Numbers, Strings, etc., that simply need to be defined. We create an object by calling its constructor in combination with the new operator. The constructor is a special object method a creation method, that has the same name as the object itself and is always called with the keyword new.
var today = new Date(), christmas = new Date(2001, 12, 24); Note, that an object can have multiple constructors with different numbers of arguments.

Lets focus here on the most commonly used objects Array and Math.
The Array Object

Every programming language has something like an array data type. We can look at an array as a variable that can encapsulate not just one, but multiple values. Thus an array is a useful container element. Lets illustrate this by example:
<html> <head> <title> The Array </title> </head> <body> <h1> The Array </h1> <script type="text/ecmascript"> var months = new Array(12); // create an array with 12 undefined elements var days = new Array("mon","tue","wen","thu","fri","sat","sun"); // days of week document.write(days[0] + "<br>"); document.write(days[7] + "<br>"); document.write(days.length + "<br>"); months[1] = "feb"; document.write(months + "<br>"); </script> </body> </html> // // // // // "mon" .. first element of days .. undefined .. 7 .. set months' 2nd value to "feb" .. ,feb,,,,,,,,,,,

We create an array object by calling its constructor. The length property can be used to determine the actual length of an array, i.e. the number of items it actually holds. In order to uniquely access one of these multiple values we need to append the so called array operator consisting of a pair of square brackets enclosing the array index.

Learn SVG

Chapter 10 Scripting the DOM

12

We have to bear in mind that arrays in ECMAScript are zero-based. That is, the array index with ECMAScript arrays always starts at zero (0) as in C, C++ and Java. Alongside this we should remember that n-1 is the last index of an array holding n elements. So we can comfortably use a for-statement to visit all elements of an array.

ECMAScript supports us with three types of Array constructors:


new Array(); new Array(n); new Array(x1,x2,..,xn); create empty Array (no argument) create Array of length n (one number argument) create Array of length n (n arguments)

The Math Object

Like other languages ECMAScript supplies the programmer with some prepackaged functions to perform complex mathematical computations. Properly speaking these functions are methods of a single Object the Math Object. You need not to create that object via new operator. The scripting engine provides it for us. Some of these properties and methods are very useful, particularly for the geometrical problems that often come along with SVG. Mathematical constants o Math.PI ratio of a circles circumference to its diameter, approximately 3.1416. o Math.SQRT_2 the number value of the square root of two, approximately 1.4142. o Math.E the number value of e, the base of the natural logarithm, approximately 2.7183. Mathematical methods o Math.abs(n) o Math.sin(n) o Math.cos(n) o Math.atan2(y,x) positive x-axis.
o Math.sqrt(n)

the absolute value of a number n. the sine of a number n. the cosine of a number n. the angle in radians of a vector (x,y) with respect to the the square root of a number n.

The Document Object Model


The Document Object Model (DOM) is an application programming interface (API) for HTML and XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated. (W3C)

Put another way, the DOM is the W3Cs response to the HTML scripters cry for help with DHTML clutter. However it is also more than this. It consists today of several modules. When an XML document (remember every SVG file is a XML document) is loaded by an XML parser, the parser builds a logical model of nodes from the structure of an XML document. With these nodes the DOM provides a representation of the complete document stored in memory. The nodes are objects with properties and methods for you, the programmer, to use. Since the DOM specification only defines the objects properties and methods to be implemented by others,

Learn SVG

Chapter 10 Scripting the DOM

13

those definitions are called object interfaces. We will use these interfaces extensively in this chapter, but we wont use them all, nor will we use and thus learn them completely.The ones well cover here are:
Node Document Element Text Event

Common interface for elements, attributes and text nodes Interface for the document object. Interface for element objects. Interface for text node objects. Interface for event objects.

The DOM tree Its helpful to look at the logical structure of nodes in memory as a tree-like structure of elements. Each object in the DOM tree correlates uniquely to an entry in the XML file. Here is a simple representation.
<svg> | |__ <defs> | |__ <circle> | |__ <g> | |__ <line> | |__ <polyline> | |__ <rect> | |__ <g> |__ <g> | |__ <text> | |__ <path> | |__ <use> |__ <ellipse> |__ <text>

As you can see, the root node of the tree is the <svg> document element itself. Below the root node there are two branches the <g> elements which also have branches or finally leaf nodes. But we will not talk about branches and leafs. We will use a parent/child/sibling relationship instead. Thus the <ellipse> element has two siblings, a preceding <use> element and a <text> sibling element following it. The <ellipse> element also has exactly one parent a <g> element and no child elements. With these terms we can uniquely and graphically describe the relationship an element has to its neighbours. We also have to bear in mind that everything in the DOM tree is basically a Node object. So if we meet an Element object anywhere, we know that we are able to use its Element properties and Element methods. But since we know now that it is also a Node object, it implements the Node properties and Node methods also. So lets have a look what these are. Climbing our Tree As weve learned, every element of the DOM tree, whatever it may be exactly, is a Node. Since we know the tree, we can also navigate along it. For this we need only some navigational properties of the node and document interface, and I have summarized them below.
Document navigational property: Value Property

Element

documentElement

Description the document object belonging to this node.

Learn SVG

Chapter 10 Scripting the DOM

14

Node informational properties: Description Value Property String nodeName the name of the node (its tag name). String nodeValue the value of the node depending of its type. Mostly null, for text nodes the containing text.

Number nodeType

ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE CDATA_SECTION_NODE ENTITY_REFERENCE_NODE ENTITY_NODE PROCESSING_INSTRUCTION_NODE COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE DOCUMENT_FRAGMENT_NODE NOTATION_NODE

= = = = = = = = = = = =

1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12;

Node navigational properties: Value Property

Node Node Array Node Node Node Node

ownerDocument ParentNode ChildNodes FirstChild LastChild previousSibling nextSibling

Description the document object belonging to this node. the parent node of this node. an array of the child nodes of this node. the first child node of his node. the last child node of his node. the node preceding this node. the node following this node.

From trees to trains To illustrate the DOM tree in action, I will make use of a train example. Here is the model

Figure 10-1. The train example


<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" > <defs> <g id="carriage"> <line x2="150" y2="0" stroke="gray" stroke-width="10" strokelinecap="round" /> <circle cx="20" cy="17" r="10" fill="lightgray" stroke="black" /> <circle cx="130" cy="17" r="10" fill="lightgray" stroke="black" /> </g> </defs> <g id="train"> <g id="engine" transform="translate(390, 300)" > <use xlink:href="#carriage" x="0" y="0" />

Learn SVG

Chapter 10 Scripting the DOM

15

<polyline id="cabin" points="150,0 150,-60 90,-50 90,0" stroke="gray" stroke-width="10" stroke-linejoin="round" fill="gray" /> <rect x="10" y="-90" width="70" height="80" fill="darkgreen" stroke="black" /> </g> <g id="wagon1" transform="translate(220,300)"> <use xlink:href="#carriage" x="0" y="0" /> <circle cx="40" cy="-42" r="20" stroke="darkred" stroke-width="30" fill="none" > <circle cx="110" cy="-42" r="20" stroke="steelblue" stroke-width="30" fill="none" /> </g> <g id="wagon2" transform="translate(50,300)"> <use xlink:href="#carriage" x="0" y="0" /> <text x="5" y="-10" font-family="Verdana" font-size="120" fill="purple" > A</text> <rect id="bluebox" x="90" y="-100" width="60" height="90" fill="navy" stroke="black" /> </g> </g> </svg> So, our train consists of an engine with two wagons and some cargo a big letter, two boxes and two coils. The carriages of the engine and the wagons are identical. So we implement it as a group in the <defs> section and reuse it via <use> elements. The wagons and the engine are themselves defined as groups, which include also the cargo. Engine and wagons are embedded in a group called train..

A Model Train

We dont need the entire SVG code for illustrating simple navigation, so we use the reduced model representation here.
<svg> |__ <defs> | |__ <g id=carriage> | |__ <g id=train> | |__ <g id=engine> | |__ <use href=carriage> | |__ <polyline> // cabin | |__ <rect> // green box | |__ <g id=wagon1> // we start here ! | |__ <use href=carriage> | |__ <circle> // red coil | |__ <circle> // blue coil | |__ <g id=wagon2> |__ <use href=carriage> |__ <text> // big letter |__ <rect> // blue box

Moving around our train OK. Lets try navigating around the train, with the general goal of accessing the blue box, a child element of wagon2. As we will discuss different possibilities of entering the DOM tree later in this chapter, lets assume now for simplicity that we have an ECMAScript variable wagon1 that still contains the node of the wagon1 group.
var wagon1; // magically contains the wagon1 node object ..

1. To reach the document from here, i.e. to jump to the top level, you simply type
var doc = wagon1.ownerDocument;

Learn SVG

Chapter 10 Scripting the DOM

16

wagon1. <svg> |_ <defs> | |_ <g id="carriage"> | |_ <g id="train"> | |_ <g id="engine"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <rect> // green box | |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // blue coil | |_ <g id="wagon2"> |_ <use href="carriage"> |_ <text> // big letter |_ <rect> // blue box

ownerDocument <svg> |_ <defs> | |_ <g id="carriage"> | |_ <g id="train"> | |_ <g id="engine"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <rect> // green box | |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // blue coil | |_ <g id="wagon2"> |_ <use href="carriage"> |_ <text> // big letter |_ <rect> // blue box

This is a very useful feature of the DOM the ability to access the Document object from an arbitrary tree node in a simple manner. 2. Now assume you are still standing on the middle wagon and want to jump from here onto the engine. For this you use
var engine = wagon1.previousSibling;

wagon1. <svg> : |_ <g id="train"> | |_ <g id="engine"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <rect> // green box | |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // blue coil :

previousSibling <svg> : |_ <g id="train"> | |_ <g id="engine"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <rect> // green box | |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // blue coil :

3. Here you realize that you should have jumped onto the last wagon instead. So you type
var wagon2 = engine.nextSibling.nextSibling;

engine. <svg> : |_<g id="train"> | |_<g id="engine">

nextSibling. <svg> : |_<g id="train"> | |_<g id="engine">

nextSibling <svg> : |_<g id="train"> | |_<g id="engine">

Learn SVG

Chapter 10 Scripting the DOM


| |_<use href="carriage"> | |_<polyline> // cabin | |_<rect> // green box | |_<g id="wagon1"> | |_<use href="carriage"> | |_<circle> // red coil | |_<circle> // blue coil | |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

17

| |_<use href="carriage"> | |_<polyline> // cabin | |_<rect> // green box | |_<g id="wagon1"> | |_<use href="carriage"> | |_<circle> // red coil | |_<circle> // blue coil | |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

| |_<use href="carriage"> | |_<polyline> // cabin | |_<rect> // green box | |_<g id="wagon1"> | |_<use href="carriage"> | |_<circle> // red coil | |_<circle> // blue coil | |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

You see that previousSibling and nextSibling are a comfortable way to step along the nodes of a certain tree level. Now lets remember our task to check the blue box on wagon2. 4. To achieve this, you need to navigate down one tree level and then walk on that level again.
var blueBox = wagon2.firstChild.nextSibling.nextSibling;

wagon2.firstChild <svg> : |_<g id="train"> : |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

nextSibling. <svg> : |_<g id="train"> : |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

nextSibling <svg> : |_<g id="train"> : |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

or alternatively
var blueBox = wagon2.lastChild;

wagon2. <svg> : |_<g id="train"> : |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

lastChild <svg> : |_<g id="train"> : |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

We notice here that there are two possible ways in order to access the blue box, which is a child of wagon2. We can step down at the beginning of the child list with wagon2.firstChild and then walk forward via two nextSibling calls, or we jump at the child lists end via wagon2.lastChild with a following step back to our target by previousSibling. Now, having discovered that all is well with the blue box, we might need to hurry back to the engines cabin.

Learn SVG

Chapter 10 Scripting the DOM

18

5. For this well need to go up one level, stepping back onto the engine. From there we can step down to the engines child nodes then shimmy along until we reach the cabin, as shown below.
var cabin = blueBox.parentNode.previousSibling.previousSibling.firstChild.nextSibling;

blueBox.parentNode.

previousSibling.previousSiblin firstChild.nextSibling g. <svg> : |_<g id="train"> | |_<g id="engine"> | |_<use href="carriage"> | |_<polyline> // cabin | |_<rect> // green box | |_<g id="wagon1"> | |_<use href="carriage"> | |_<circle> // red coil | |_<circle> // blue coil | |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<rect> // blue box

<svg> : |_<g id="train"> <svg> | : |_<g id="engine"> |_<g id="train"> | |_<use | href="carriage"> |_<g id="engine"> | |_<polyline> // cabin | |_<use href="carriage"> | |_<rect> // green box | |_<polyline> // cabin | | |_<rect> // green box |_<g id="wagon1"> | | |_<use |_<g id="wagon1"> href="carriage"> | |_<use href="carriage"> | |_<circle> // red | |_<circle> // red coil coil | |_<circle> // blue coil | |_<circle> // blue | coil |_<g id="wagon2"> | |_<g id="wagon2"> |_<use href="carriage"> |_<text> // big letter |_<use |_<rect> // blue box href="carriage"> |_<text> // big letter |_<rect> // blue box

Remember that we can always go up one level with parentNode we dont need to go to the beginning or end of the list of siblings first. This means that we have another method available to access the cabin. 6. We can step up two levels to the train node and go from here two levels down again instead of walking along the trains children.
var cabin = blueBox.parentNode.parentNode.firstChild.firstChild.nextSibling;

Up to here we have discovered how we can walk along the entire tree of our SVG example document. However, imagine that our train consists of many more wagons and we wish to navigate to one of them somewhere in the middle from the engine room. Rather than typing numerous nextSibling instructions, W3C provides us with a time and code-saving alternative. 7. This alternative consists of going up one level in the tree to the train node and asking it to supply us with an array of all children. This is achieved via
var wagons = engine.parentNode.childNodes;

And with this we can go directly to the 142th wagon by simply using
var wagon142 = wagons.item(141);

Learn SVG

Chapter 10 Scripting the DOM

19

Just to drum it in one more time, the ECMAScript and DOM arrays are zero-based. Because of this the array index 141 points to the 142th array element.

On the basis of this Id like to present you a small ECMAScript function, that allows us to visit the total subtree of a particular node. Note that this function is recursive, that is, a function that calls itself.
function VisitChildren(node) { for (var child = node.firstChild; child != null; child = child.nextSibling) { // do something with your child here (except removing) .. if (child.hasChildNodes()) VisitChildren(child); } }

You might find this function beneficial for your own DOM scripting projects.

Preparing for a working Example Now lets build a complete working SVG document with scripting here. For this we first have to resolve two issues. We need some event handling, which we will cover not until later in this chapter. We have to deal with additional nodes, that I did not mention previously the whitespace nodes. No problem with the event handling here. We will just use it, I will explain it to you later. Dealing with the whitespace nodes is less trivial. So what are these whitespace nodes?

Every XML document can have text nodes nodes consisting completely of text. Furthermore that text may consist purely of spaces () or newlines (). Such a series of spaces and newlines will be interpreted by an XML parser as a text node we call it whitespace node. Understanding that, we can see now several whitespace nodes in the above SVG fragment. The problem arises, if we want to get the next node of the line element. nextSibling wont provide us with the circle element, but with a whitespace node. So what shall we do? Properly deal with the whitespace text nodes. Remove all whitespace text nodes, immediately after the document has completely loaded. The previous node navigation examples ignored these whitespace nodes for simplicity. In order to get that code to work, we will decide for the second solution removing all whitespace text nodes. For this I provide you with a utility function, that does exactly that.

Learn SVG

Chapter 10 Scripting the DOM

20

function RemoveWhiteSpaceChildNodesOf(node) { if (node != null) { var child = node.lastChild; while (child != null) { if (child.nodeType == 3 && child.nodeValue.match(/\S/) == null) { var previous = child.previousSibling; child.parentNode.removeChild(child); child = previous; } else { RemoveWhiteSpaceChildNodesOf(child); child = child.previousSibling; } } } }

You might not understand that function completely yet (it is similar to the VisitChildren function), but since we know, how to call a function and as we consider this a quite useful function, we will simply use it. Since we will reuse this function in several SVG documents, we decide to put it into an external file RemoveWhiteSpace.js. We can embed this function then simply by the <script> element.
<script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js" />

Please note, that we have to deal with whitespace text node handling only under certain conditions.
When using the Node objects navigational properties (firstChild, nextSibling, etc.), we have to consider the appearance of whitespace text nodes.

With that here is our last node navigation example as a complete working document.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var blueBox = evt.target.ownerDocument.getElementById("bluebox"); var cabin = blueBox.parentNode.parentNode.firstChild.firstChild.nextSibling; window.alert(cabin.nodeName); ]]> </script> <defs> <g id="carriage"> <line x2="150" y2="0" stroke="gray" stroke-width="10" strokelinecap="round" /> <circle cx="20" cy="17" r="10" fill="lightgray" stroke="black" /> <circle cx="130" cy="17" r="10" fill="lightgray" stroke="black" /> </g> </defs> <g id="train"> <g id="engine" transform="translate(390, 300)" > <use xlink:href="#carriage" x="0" y="0" /> <polyline id="cabin" points="150,0 150,-60 90,-50 90,0"

Learn SVG

Chapter 10 Scripting the DOM

21

stroke="gray" stroke-width="10" stroke-linejoin="round" fill="gray" /> <rect x="10" y="-90" width="70" height="80" fill="darkgreen" stroke="black" /> </g> <g id="trailer1" transform="translate(220,300)"> <use xlink:href="#carriage" x="0" y="0" /> <circle cx="40" cy="-42" r="20" stroke="darkred" stroke-width="30" fill="none" /> <circle cx="110" cy="-42" r="20" stroke="steelblue" stroke-width="30" fill="none" /> </g> <g id="trailer2" transform="translate(50,300)"> <use xlink:href="#carriage" x="0" y="0" /> <text x="5" y="-10" font-family="Verdana" font-size="120" fill="purple" >A</text> <rect id="bluebox" x="90" y="-100" width="60" height="90" fill="navy" stroke="black" /> </g> </g> </svg>

Please note: The onload event handler, that causes the Init(evt) function to be called, when the document is completely loaded. (Not until then the DOM tree is fully constructed!) The use of the <script type="text/ecmascript"> element. We can in general safely omit the type="text/ecmascript" attribute, since ="text/ecmascript" is always the default value. The <![CDATA[ .. ]] section, that causes any XML parser not to interpret the enclosed text as markup. This is necessary, if we safely want to use characters as < with a particular meaning in XML inside of script.
Sophisticated Searching

The step by step method of navigating the DOM tree is quite useful, if we Walk short distances in any direction of the tree. Know the exact nature of the tree structure. Need to walk the entire tree. Of course, this is not normally the case. Much more often we are searching a particular node in the tree and want to jump directly onto it. With that we need to have some information about that node. Having this we can consult the Document object that offers some useful services regarding our problem. Document Searching Lets have a look at the methods we can use to jump directly to specified elements. They are listed below.
Document navigational property: Return Value Method Description An array of element nodes with this name. The element with an Id that has this string value.

Array Element

getElementsByTagName(tagName) getElementsById(elementId)

1. Now, as an example, lets say we know the node we wish to visit is a <g>element. Still sitting on the engine, we code

Learn SVG

Chapter 10 Scripting the DOM

22

var elements = engine.ownerDocument.getElementsByTagName(g);

which will yield an array, hopefully filled with all group elements. 2. Now we can run over the list using our new companion, the for loop.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var engine = evt.target.ownerDocument.getElementById("engine"); var elements = engine.ownerDocument.getElementsByTagName("g"); for (var i=0; i < elements.length; i++) window.alert("Element " + i + " of type: " + elements.item(i).nodeName); } ]]> </script> <!-- train's geometry goes here --> </svg>

With this we will receive the following output:


Element Element Element Element Element 0 1 2 3 4 of of of of of type: type: type: type: type: g g g g g

Somewhat astonished you look at the train document tree above and count five <g> elements including the carriage in the <defs> section. Fine, now we only need to select our target element out of five groups. Maybe we know a little more of our group the colour perhaps, or any other attribute. But hold on. There was another method offered by the document object. With this we come to the solution most often used in real code. Provided that we marked our target element with a unique identifier via the id attribute, we can use the document objects getElementById method to jump directly to it. 3. Still sitting on your engine you decide to visit the most distant wagon and type
var mostDistantWagon = engine.ownerDocument.getElementById(wagon2);

Voila, here it is. We now have an equally simple and powerful solution. Any element in the tree can beg the always accessible document object to do it a favour and perform a quick search for a particular element with a known id and every element we want to reach via this method needs to have an id in the first place. A prerequisite for this is in general:
Id attribute values must be unique across the whole xml document and should obey the syntactical rules of ECMAScript variables.

Learn SVG

Chapter 10 Scripting the DOM

23

I emphasise this, though a matter of course as for program variables, since potential scripting code relies heavily on this. current xml parsers may not complain about this (future parsers will). some xml-generating software may create duplicate or invalid id values. Accessing Attributes I promised to show you how we can access an elements attributes. This is not very mysterious. There are two different methods of the Element object to help with attribute access.
Elements attribute access methods: Return Value Method Description The value of the attribute with the name attrName as a string. set the attribute with the name attrName value to newValue.

String void

getAttribute(attrName) setAttribute(attrName, newValue)

Firstly Id like to focus on the getAttribute method in particular. Lets remember the problem. We had an array full of <g> elements and we needed to find the particular one with the id value trailer2. We temporarily neglect the fact that we solved this search problem very elegantly using the getElementById method. With our new knowledge about attributes we could iterate over the array and compare every <g> elements id value with the string trailer2.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var var var var engine = evt.target.ownerDocument.getElementById("engine"); groups = engine.ownerDocument.getElementsByTagName("g"); wagon = null; // null as long as you didn't find it .. currentGroup = null;

for (var i=0; wagon == null && i < groups.length; i++) { currentGroup = groups.item(i); if (currentGroup.getAttribute("id") == "wagon2") // found :-) wagon = currentGroup; } if (wagon != null) window.alert("wagon with id = '" + wagon.getAttribute("id") + "' found!"); } ]]> </script> <!-- train's geometry goes here --> </svg>

The last line of your code should finally produce the output:
wagon with id = 'wagon2' found!

Learn SVG

Chapter 10 Scripting the DOM

24

This technique of selecting elements by looking at the attributes is especially useful, when there is no id-attribute that can be used for the getElementById method. Dynamic elements Now we can navigate quite elegantly through the DOM tree, its about time we learned how to modify the attributes we find along the way. The Elements method setAttribute is provided by the DOM for exactly that purpose.
Altering Dynamic Elements

Your mobile phone rings and the boss tells you that you are carrying the wrong letter your train is supposed to be carrying a Y instead of an A.. Furthermore you picked up the wrong box. The correct one is twice as high as yours and its colour isnt green but gold. With your new knowledge about DOM modification you decide not to drive back to the storage to change the cargo. You would rather try to manipulate your load dynamically. 1. Modifying the box is quite simple. All you need to do is change the corresponding attributes accordingly.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var engine = evt.target.ownerDocument.getElementById("engine"); var greenBox = engine.lastChild, greenBoxHeight = parseFloat(greenBox.getAttribute("height")), greenBoxY = parseFloat(greenBox.getAttribute("y")); greenBox.setAttribute("height", 2*greenBoxHeight); greenBox.setAttribute("y", greenBoxY - greenBoxHeight); greenBox.setAttribute("fill", "gold"); } ]]> </script> <!-- the train's geometry goes here --> </svg>

2. Still sitting in the engines cabin you take a look behind you to see what happened.

Learn SVG

Chapter 10 Scripting the DOM

25

Figure 10-2. Modified train Wow, it worked! Lets look at the code again. 3. Note that we passed Number objects as well as a String object as the second argument to the setAttribute method. Contrary to the use of getAttribute we dont concern ourselves with the type. Any necessary type conversions are performed by the setAttribute method internally. Please note, that the green rect was anchored at the top and its height actually determines the position of the rects bottom. Thus to compensate for increasing the height, you must reduce the y. So our next task is to change our A to a Y. To achieve this we will jump to the last wagon. There is no problem with that, since we have its id. Then we decide to query the wagon2 element for an array with all <text> elements, which hopefully will be filled with exactly one item. 4. Having this then, you argue, the A must be the one and only child node. Its type must be a text node, whose value can be changed then to a Y. Sounds good, so you start coding.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var engine = evt.target.ownerDocument.getElementById("engine"); var wagon2 = engine.ownerDocument.getElementById("trailer2"); var texts = wagon2.getElementsByTagName("text"); // all text child elements .. if (texts.length > 0) .. { // ok, it must be our 'A'

Learn SVG

Chapter 10 Scripting the DOM

26

var letter = texts.item(0).firstChild; // text node as child of <text> element letter.nodeValue = "Y"; change. } else // oops window.alert("I lost a letter on the way - or got some more!"); } ]]> </script> <!-- the train's geometry goes here --> </svg> // whose value we need to

Its a bit strenuous to look around the big golden box just to see the result.

Figure 10-3. Changing letter Now we have learned how to change attributes and textual content of SVG elements, and with this armoury are able to put right any potential faults in our document.
Removing Elements and Attributes

Well kick off here with removal, as with the DOM, as in real life, it is always easier to destroy something than to build it. Id like to introduce you to two methods.
Nodes remove method: Node removeChild(node) Elements attribute removal method: Node removeAttribute(attr)

remove this node from the tree. remove the elements attribute.

Before you are urged now to wildly remove anything that comes up, please bear these rules in mind:
Any node - and with this any element - can be removed solely by its parent.

An attribute can be removed only by the element it belongs to.

Learn SVG

Chapter 10 Scripting the DOM

27

As always well understand this best by example. Remember that you are still sitting in the engines cabin. Since you are going to arrive at your first customer, who ordered the coils, you have a good chance now to deliver the cargo via the DOM. You are quite practised now with algorithms, so you present your plan: Go from the engine to wagon1. Pick the rearward coil from the wagon combining lastChild and the removeChild method. Pick the forward coil from the trailer using lastChild.previousSibling with the removeChild method. 1. With this in mind you immediately start programming the code:
var wagon1 = engine.ownerDocument.getElementById("wagon1"); wagon1.removeChild(wagon1.lastChild); // remove blue coil .. wagon1.removeChild(wagon1.lastChild); // remove red coil ..

2. Happy with this concise bit of coding, you look at the result:

Figure 10-4. Remove objects It works. But I also want to show you, that removing elements from the tree is a tricky task. 3. Lets have a look at the wagon1 subtree before removing any coil.
|__ <g id=wagon1> | |__ <use href=carriage> | |__ <circle> // red coil | |__ <circle> // blue coil |

4. After the first removal of the blue coil the resulting tree looks like this:
|__ <g id=wagon1> | |__ <use href=carriage>

Learn SVG
| |

Chapter 10 Scripting the DOM


|__ <circle> // red coil

28

Now it is possible to see what would have happened when you mistakenly called
wagon1.removeChild(wagon1.lastChild.previousSibling);

in order to remove the red coil. It was the last child then, so you would have removed the carriage. 5. Lets also remove the purple paper from the big Y letter on the last trailer, trying out removeAttribute.
var letterY = engine.ownerDocument.getElementById("wagon2").firstChild.nextSibling; letterY.removeAttribute("fill"); // remove purple paper ..

Now we see what we all initially expected, alongside the true colour of the Y letter. The wagon1 subtree now looks like this:
|__ <g id=wagon1> | |__ <use href=carriage> | 6.

Finally, heres a handy bit of code designed to remove all child elements of any parent
beginning to end while (parent.firstChild != null) parent.removeChild(parent.firstChild);

from

7. Or from the end to the beginning


while (parent.firstChild != null) parent.removeChild(parent.lastChild); Whenever you remove elements, especially in loops, remember that any element removal changes the tree structure. Subsequent actions operate on that new structure.

Creating Elements Lets be a bit more constructive now. Initially Ill present you with some useful methods that well need for creating elements and for adding them to the tree. Attributes are not covered here, as we have already learned how to create them by the setAttribute method.
Documents creation method: Method Return Value Description Creates a new element of type tagName.

Element

createElement(tagName)

Nodes creation method: Method Return Value

Node

cloneNode(deep)

Description Create a clone of itself.

Nodes inserting methods: Return Value Method

Description

Node Node Node

insertBefore(node, child) Insert node node before child node child into the children list. appendChild(node) Append node node at the end of the children list. replaceChild(node, child) Replace child node child with node node in the children list.

Learn SVG

Chapter 10 Scripting the DOM

29

The remarkable Document object is not only DOMs search engine, but also an element factory. So if we need a new element, we have to find the Document object which is easy achieved by using the ownerDocument property from anywhere in the tree and simply use its createElement method. As an argument we pass rect, circle or the name of whichever element we wish to create, to that method. An arbitrary Node object also has some restricted creation capability the ability to create a clone of itself. The single argument deep is of type Boolean and controls the behaviour, when the cloning node has child nodes. If deep has a value of true, a deep copy will be performed, i.e. all child nodes will get cloned also. With this feature we can create a copy of a whole subtree in a very simple manner. The value false of the deep argument will result in a shallow copy, a copy of only the cloning parent node without its children.
DOM Expansion

Usually we will expand the DOM tree with these two consecutive steps: 1. Create a new node from the Document objects createElement method. 2. Add the new node to the tree using one of the Node objects inserting methods. But we can also perform quite a special action. If we want to move an existing node from the tree onto another location in the same tree we can use the Node objects inserting methods for that too. The node to move is removed from the tree first and then reinserted again.
Back on the Train

So now you should know enough to try this out so lets return to our train delivery example. You have had a conversation with a customer that one with the coils. He asked you to transport back an olive pyramid and a defect wagon belonging to your company. So your objectives now appear like this. Pick the blue box from the last wagon and put it onto the middle one, as you want to have the defect wagon at the end of your train. Do the same with the Y letter. Take the defect wagon. Load up the defect wagon onto the last now empty wagon. Take the olive pyramid. Put the pyramid on top of the defect wagon. 1. First things first then, youll need to code the following to move goods from the end wagon to the middle.
var wagon1 = engine.ownerDocument.getElementById("wagon1"), wagon2 = engine.ownerDocument.getElementById("wagon2"); wagon1.appendChild(wagon2.lastChild); // move the blue box to the middle trailer. wagon1.appendChild(wagon2.lastChild); // move the Y letter to the middle trailer.

So why have the box and the Y letter changed their location? the customer asks. You didnt modify any coordinates. You explain patiently to this SVG amateur, that the wagons are designed as <g> elements with identical local coordinate systems. Their different positions come from suitable translations via the transform attribute. So the coordinates inside all wagon groups are the same.

Learn SVG

Chapter 10 Scripting the DOM

30

Figure 10-5. Change location of objects 2. Now onto the next points of the plan loading the defect wagon onto the now empty one. Well, the best strategy to get a defect wagon seems to be by simply cloning the last empty wagon.
var wagon1 = engine.ownerDocument.getElementById("wagon1"), wagon2 = engine.ownerDocument.getElementById("wagon2"); wagon1.appendChild(wagon2.lastChild); // move the blue box to the middle wagon. wagon1.appendChild(wagon2.lastChild); // move the Y letter to the middle wagon. var defectWagon = wagon2.cloneNode(true); defectWagon.setAttribute("transform", "translate(0,-35)"); wagon2.appendChild(defectWagon);

3. Now we must move onto creating the olive pyramid best as a <polygon> element and putting it onto the defect wagon before looking at the result.
var wagon1 = engine.ownerDocument.getElementById("wagon1"), wagon2 = engine.ownerDocument.getElementById("wagon2"); wagon1.appendChild(wagon2.lastChild); wagon1.appendChild(wagon2.lastChild); var defectWagon = wagon2.cloneNode(true); defectWagon.setAttribute("transform", "translate(0,-35)"); var pyramid = engine.ownerDocument.createElement("polygon"); pyramid.setAttribute("points", "5,-10 145,-10 75,-100"); pyramid.setAttribute("fill", "olive"); defectWagon.appendChild(pyramid); wagon2.appendChild(defectWagon);

4. With this you are finished and can cast a look at the result and the impressed customer.

Learn SVG

Chapter 10 Scripting the DOM

31

Figure 10-6. Adding new objects With this we have learned how easy it is to create new SVG elements and add them to an existing DOM tree. You should also know, that the Document object offers a lot more creation methods. You can even create a new Document object using the DOMImplementation object. But I wont cover all this here.
We should always remember, that node creation and deletion basically work upon internal memory operations. Those operations are usually expensive in runtime and memory so I recommend that if a task can be accomplished by Node creation/removal or by attribute modification, always prefer the modification strategy for performance reasons.

A Quick Trick

Related to this notion Ill let you in on something of a trick, that could well be useful in practise. Assume you need to have one or more elements to be appearing and disappearing periodically. Instead of removing and reinserting them with every cycle, it is far more advantageous to let them stay in the DOM tree and control only the elements visibility. We can achieve this with
wagon1.setAttribute("visibility","hidden");

As far as single line functionality goes, its pretty hard to beat! Finally, I want to present you the total source of the track example, with the individual actions organized as functions.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) {

Learn SVG

Chapter 10 Scripting the DOM

32

RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); var engine = evt.target.ownerDocument.getElementById("engine"); FindTrailer2ByAttribute(engine); MakeGreenBoxGolden(engine); ChangeAToY(engine); RemoveCoils(engine); MoveBoxAndLetterAndCreateDefectWagonAndPyramid(engine); } function FindTrailer2ByAttribute(engine) { var groups = engine.ownerDocument.getElementsByTagName("g"); var wagon = null; // null as long as you didn't find it .. var currentGroup = null; // .. used in loop .. for (var i=0; wagon == null && i < groups.length; i++) { currentGroup = groups.item(i); if (currentGroup.getAttribute("id") == "wagon2") // found :-) wagon = currentGroup; } if (wagon != null) window.alert("group found with id: " + wagon.getAttribute("id")); else window.alert("no group found with id 'wagon2'"); } function MakeGreenBoxGolden(engine) { var greenBox = engine.lastChild, greenBoxHeight = parseFloat(greenBox.getAttribute("height")), greenBoxY = parseFloat(greenBox.getAttribute("y")); greenBox.setAttribute("height", 2*greenBoxHeight); greenBox.setAttribute("y", greenBoxY - greenBoxHeight); greenBox.setAttribute("fill", "gold"); } function ChangeAToY(engine) { var wagon2 = engine.ownerDocument.getElementById("wagon2"); var texts = wagon2.getElementsByTagName("text"); if (texts.length > 0) // ok, it must be our 'A' .. { var letter = texts.item(0).firstChild; letter.nodeValue = "Y"; } } function RemoveCoils(engine) { var wagon1 = engine.ownerDocument.getElementById("wagon1"); wagon1.removeChild(wagon1.lastChild); // remove blue coil .. wagon1.removeChild(wagon1.lastChild); // remove red coil .. var letterY = engine.ownerDocument.getElementById("wagon2").firstChild.nextSibling; letterY.removeAttribute("fill"); // remove purple paper .. } function MoveBoxAndLetterAndCreateDefectWagonAndPyramid(engine) { var wagon1 = engine.ownerDocument.getElementById("wagon1"), wagon2 = engine.ownerDocument.getElementById("wagon2"); wagon1.appendChild(wagon2.lastChild); wagon1.appendChild(wagon2.lastChild); var defectWagon = wagon2.cloneNode(true); defectWagon.setAttribute("transform", "translate(0,-35)");

Learn SVG

Chapter 10 Scripting the DOM


var pyramid = engine.ownerDocument.createElement("polygon"); pyramid.setAttribute("points", "5,-10 145,-10 75,-100"); pyramid.setAttribute("fill", "olive"); defectWagon.appendChild(pyramid);

33

wagon2.appendChild(defectWagon); } ]]> </script> <defs> <g id="carriage"> <line x2="150" y2="0" stroke="gray" stroke-width="10" strokelinecap="round" /> <circle cx="20" cy="17" r="10" fill="lightgray" stroke="black" /> <circle cx="130" cy="17" r="10" fill="lightgray" stroke="black" /> </g> </defs> <g id="train"> <g id="engine" transform="translate(390, 300)" > <use xlink:href="#carriage" x="0" y="0" /> <polyline id="cabin" points="150,0 150,-60 90,-50 90,0" stroke="gray" stroke-width="10" stroke-linejoin="round" fill="gray" /> <rect x="10" y="-90" width="70" height="80" fill="darkgreen" stroke="black" /> </g> <g id="wagon1" transform="translate(220,300)"> <use xlink:href="#carriage" x="0" y="0" /> <circle cx="40" cy="-42" r="20" stroke="darkred" stroke-width="30" fill="none" /> <circle cx="110" cy="-42" r="20" stroke="steelblue" stroke-width="30" fill="none" /> </g> <g id="wagon2" transform="translate(50,300)"> <use xlink:href="#carriage" x="0" y="0" /> <text x="5" y="-10" font-family="Verdana" font-size="120" fill="purple" >A</text> <rect id="bluebox" x="90" y="-100" width="60" height="90" fill="navy" stroke="black" /> </g> </g> </svg>

Event Handling At the beginning of this chapter I promised you that if you learn ECMAScript and DOM you will have dynamic and interactive SVG documents. Youve had to learn a lot so far, but nothing weve achieved has really fitted either of these categories. Youve misled us I hear some of you cry. Well, to those people Ill simply say Lets get interactive. So what is interaction? Imagine the user that is the person sitting in front of his computer screen staring on your SVG document says I want this silly green rectangle to be red! If your ECMAScript modifies the DOM tree of the document, and changes the colour of the offending shape, you have a truly interactive document. This is what well achieve now without speech recognition of course. The software that implements the DOM the SVG rendering engine or the web browser passes certain events into the Document Object Model. With an incoming event the DOM looks to see if there are any registered event listeners for that particular event type. An element can register itself as an event listener by telling the DOM the event type it is interested in and incorporating an event handler, which is a piece of ECMAScript code that is executed when that particular event occurs. Heres an example :

Learn SVG

Chapter 10 Scripting the DOM

34

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"> <circle cx="80" cy="120" r="40" fill="red" onclick="window.alert('hello user!');" /> </svg>

The red <circle> element had registered itself as an event listener by exposing an event property, the onclick property in this case. The propertys value the event handler is an ECMAScript statement that will be executed if the user clicks the mouse on this red <circle> .

Figure 10-7. Click on red circle You may already be familiar with HTML events. If so youll notice that SVG events are not much different, although perhaps a little tidier. SVG supports a lot of different event types, some of which are listed below.
Document related events Description event onload the load event occurs, when the SVG rendering engine has completely loaded the element. User interface related events Description event onzoom the zoom event occurs, when the zoom level of the SVG document changes. Mouse events event

onclick onmousedown onmouseup onmouseover onmouseout onmousemove

Description the user presses and releases the mouse button. the user presses the mouse button. the user releases the mouse button. the user moves the mouse pointer over an element. the user moves the mouse pointer away from the element. the user moves the mouse pointer.

Events are important, so important that they influence the way we have to implement the script with our SVG document. Here is an example, that is frequently expected to work, but does not necessarily do so.
<?xml version="1.0"?> <svg width="600" height="400"> <script type="text/ecmascript> <![CDATA[ var rect1 = document.getElementById("greenRect"); rect1.setAttribute("fill", "red"); ]]> </script> <rect id="greenRect" x="100" y="100" width="200" height="60" fill="green" /> </svg>

Learn SVG

Chapter 10 Scripting the DOM

35

What we want to do here is to query the Document object for an element with the id greenRect. Then we want to set the green colour of the rectangle to red. Loading this document with our SVG rendering engine may fail miserably. We made two big mistakes here: 1. We cannot rely on a global document variable, as we might be used to, when scripting inside of HTML. Also the reputed cleaner window.document notation will fail here. 2. Even if the global document variable exists, we are not guaranteed to have access to any DOM objects as long as those objects arent completely loaded. And this one works! So here is a working redesign of the Rectangle.svg example.
<?xml version="1.0"?> <svg width="600" height="400" onload="Init(evt);"> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { var doc = evt.target.ownerDocument; var rect1 = doc.getElementById("greenRect"); rect1.setAttribute("fill", "red"); } ]]></script> <rect id="greenRect" x="100" y="100" width="200" height="60" fill="green" /> </svg>

We eliminate the second mistake first, in that we implement an initialisation function Init() and leave it to the onload event property to get that function called at the right time. With this provision we insure that the relevant DOM accessing code will be executed after the complete document is loaded, i.e. the Document Object Model is available. The first mistake can then be corrected with the help of the evt object, which the SVG rendering engine provides for us. We use this object by passing it over to the event handler function via Init(evt). The Event object variable evt must be written exactly this way, at least in the event handlers code (the value of the event property). With the Event object we get some useful properties, and below youll find the ones relevant to the rest of this book.
Events properties: Property Value Description the event type as a string. the registered event listener element for this event. the initiating element for this event. Usually an event listener's child.

String type Element currentTarget Element target


Events method: Method Return Value

void

stopPropagation()

Description prevent further propagation during event flow.

I need to introduce you also to the more specialised MouseEvent object.


MouseEvents properties: Property Value Description the event type as a string. the registered event listener element for this event. the initiating element for this event. Usually an event listener's child. the x-coordinate of the mouse pointers location in SVG world coordinates. the y-coordinate of the mouse pointers location in SVG world coordinates.

String Element Element Number Number

type currentTarget target clientX clientY

Learn SVG
Number button Number detail Element target

Chapter 10 Scripting the DOM

36

information about the mouse button pressed (0,1,2 for left/middle/right). count of mouse clicks (onclick only). the initiating element for this event. Usually an event listener's child.

A particular Event object is not only passed to a single elements event handler, but participates in a predefined event flow, assuming an element receives an onclick event that is, the user clicked with its mouse on it. Whether or not this element has registered itself as an event listener, that onclick event is propagated up the tree following the elements parent chain (known as event bubbling). One of these might also have registered an onclick event handler, which will get invoked too.
When designing event responsive elements, we have to take into account the complete event flow up to the document element The events stopPropagation method can interrupt this flow if necessary.

Now we know enough to play with those different kinds of events.


Touching Elements

Since we can look at the computer mouse as the elongated arm of the user, mouse events play a big role in design for interactivity.

Figure 10-8. Rectangles with events While focusing on events I chose a simple SVG document. 1. The following code defines our five rectangles
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); } ]]> </script> <g> <rect x="10" y="100" width="90" height="40" fill="blue" opacity="0.4" /> <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" /> <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4/> <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" /> <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" /> </g> <text x="55" y="160" text-anchor="middle">highlight</text> <text x="155" y="160" text-anchor="middle">magical</text> <text x="255" y="160" text-anchor="middle">changing color</text> <text x="355" y="160" text-anchor="middle">mutate</text> <text x="455" y="160" text-anchor="middle">click</text> </svg>

Learn SVG

Chapter 10 Scripting the DOM

37

All of these rectangles are child elements of a common group and have the opacity style attribute defined with a value of 0.4. We want to exploit this for a highlighting effect by setting the opacity to 1.0, when the user moves the mouse pointer over it.
Highlighting

So lets start with the leftmost blue rectangle, labelled highlight, adding appropriate event properties. 1. Add the event handler attribute to the first rectangle 2. Then we need to implement the ECMAScript functions Highlight and

Unhighlight.

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); } function Highlight(evt) { evt.target.setAttribute("opacity", "1.0"); } function Unhighlight(evt) { evt.target.setAttribute("opacity", "0.4"); } ]]> </script> <g> <rect x="10" y="100" width="90" height="40" fill="blue" opacity="0.4" onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);"/> <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" /> <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4/> <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" /> <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" /> </g> <text x="55" y="160" text-anchor="middle">highlight</text> <text x="155" y="160" text-anchor="middle">magical</text> <text x="255" y="160" text-anchor="middle">changing color</text> <text x="355" y="160" text-anchor="middle">mutate</text> <text x="455" y="160" text-anchor="middle">click</text> </svg>

Thanks to the Event objects target property we get access to <rect> element that received the event. With this we can set the rectangles opacity to 1.0, when the mouse enters its area and reset it to 0.4 when the mouse pointer leaves.

Figure 10-9. Highlight a rectangle

Learn SVG

Chapter 10 Scripting the DOM

38

Now, if we want to give the other rectangles the same behaviour, we must add these onmouseover and onmouseout event properties to them also. 4. But there seems to be a simpler solution. Remembering the event flows towards the parent element called event bubbling. We could add the onmouseover and onmouseout event properties to the <g> element instead and leave it at that.
<g onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);"> <rect x="10" y="100" width="90" height="40" fill="blue" opacity="0.4" /> <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" /> <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4/> <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" /> <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" /> </g>

Trying this out verifies that our considerations were correct. If we needed access to the <g> element inside the Highlight and Unhighlight functions, we would have used evt.currentTarget instead of evt.target.
Changing Color

Well come back to the magical rectangle shortly but for now we want the third yellowgreen rectangle to change its color to black whenever the mouse is clicked on it. 5. To achieve this effect, we have to register the <rect> element as an event listener for the onmousedown and onmouseup events.
<rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4" onmousedown="ChangeColor(evt);" onmouseup="ChangeColor(evt);"/>

6. Next we must again implement the affiliated ECMAScript function. Now we intend to use a single function instead of one for onmousedown and another for onmouseup event. Here is the complete code.
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); } function Highlight(evt) { evt.target.setAttribute("opacity", "1.0"); } function Unhighlight(evt) { evt.target.setAttribute("opacity", "0.4"); } function ChangeColor(evt) { if (evt.type == "mousedown") evt.target.setAttribute("fill", "black"); else if (evt.type == "mouseup") evt.target.setAttribute("fill", "yellowgreen"); } ]]> </script> <g onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);"> <rect x="10" y="100" width="90" height="40" fill="blue" opacity="0.4" /> <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" />

Learn SVG

Chapter 10 Scripting the DOM

39

<rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4" onmousedown="ChangeColor(evt);" onmouseup="ChangeColor(evt);"/> <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" /> <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" /> </g> <text x="55" y="160" text-anchor="middle">highlight</text> <text x="155" y="160" text-anchor="middle">magical</text> <text x="255" y="160" text-anchor="middle">changing color</text> <text x="355" y="160" text-anchor="middle">mutate</text> <text x="455" y="160" text-anchor="middle">click</text> </svg>

Figure 10-10. Change color of rectangle

Now when we move the mouse pointer onto the yellowgreen rectangle, it is highlighted due to the parents event handler. Then when we press the mouse button the colour changes to black. Releasing the button turns the colour back to yellowgreen. still highlighted. On the other hand, if we keep the mouse button pressed, move the mouse pointer away from the rectangle and then release the mouse button, the color remains black, though unhighlighted now.
Getting Invisible

For our next trick well use the 2nd rectangle that we skipped over a moment ago. The goal here is for the fourth rectangle to disappear when the mouse is over this magical rectangle. On the side we also want to suppress the highlighting effect. 7. Adjust the code accordingly
<rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" onmouseover="Magical(evt);" onmouseout="Magical(evt);"/>

8. The Magical function is similar to ChangeColor.


function Magical(evt) { if (evt.type == "mouseover") evt.target.nextSibling.nextSibling.setAttribute("visibility", "hidden"); else evt.target.nextSibling.nextSibling.removeAttribute("visibility"); evt.stopPropagation (); }

Figure 10-11. Hide rectangle As I am illustrating here, we can use the evt.target element as a start to navigate through the DOM tree and affect other elements by that particular event too. We also tested the interruption of the event flow via a call to evt.stopPropagation().

Learn SVG
Mutating Elements

Chapter 10 Scripting the DOM

40

The next task is to change the fourth rectangle when clicking with the mouse on it, so that it becomes an ellipse. As we learned so far, we know that we cannot change an elements type, we have to remove the element from the DOM tree and insert a new one instead. But I also told you, before using create and remove operations we should consider attribute manipulation in the first place. So here is one possible and simple solution. We add an <ellipse> element statically to our document and hide it with the display="none" attribute. 9. Enter the following code to the fourth rectangle
<rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" onclick="Mutate(evt);" /> <ellipse cx="355" cy="120" rx="45" ry="20" fill="orange" display="none" onclick="Mutate(evt);" />

10. Then we need only to move the display="none" attribute to the <rect> element and back to the <ellipse> element with each mouse click.
function Mutate(evt) { var elem = evt.target; elem.setAttribute("display", "none"); // hide the displayed element .. if (elem.nodeName == "rect") // rectangle was displayed .. elem.nextSibling.removeAttribute("display"); // .. show ellipse else // ellipse was be displayed .. elem.previousSibling.removeAttribute("display"); // show rectangle } }

Figure 10-12. Change shape Since the <ellipse> element is also a child of the same parent group, highlighting works automatically here too. You might be urged to ask here what the difference between the display attribute and the visibility attribute is, as you cannot see the elements then either. Regarding the mouse event sensibility there is indeed a significant difference: Elements with visibility=hidden attribute set are invisible and can receive mouse events, if they additionally define the attribute pointer-events=all. Elements with display=none attribute set are invisible and cannot receive mouse events.

And that last behaviour was exactly what we wanted here.


Double Clicks

Sometimes well want to differentiate between single and double mouse clicks. If youve read the MouseEvents properties, youll probably have noticed the detail property. This is a very commonly used property and its value varies with the event type. With the onclick event it stores the count of clicks the user performed. 11. Just to test this well register the last red rectangle as an onclick event listener.
<rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4"

Learn SVG

Chapter 10 Scripting the DOM

41

onclick="ClickCounter(evt);"/>

12. With the implementation of the ClickCounter function we need to display the number of current click counts. Well use the rectangles caption for this.
function ClickCounter(evt) { var clickText = evt.target.parentNode.parentNode.lastChild.firstChild; clickText.nodeValue = evt.detail + ". click" }

Figure 10-13. Click counter It obviously works. The first click always writes 1. click under the rectangle. The second click will produce different results based on several factors. If the time between the first and the second click is too long we get 1. click again. If the time between the first and the second click is short enough, but we displaced the mouse pointer slightly we get 1. click too. If the time between the first and the second click is short enough and we didnt displace the mouse pointer we get 2. click.

For your convenience, here is the complete example code:


<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);"> <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Init(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); } function Highlight(evt) { evt.target.setAttribute("opacity", "1.0"); } function Unhighlight(evt) { evt.target.setAttribute("opacity", "0.4"); } function ChangeColor(evt) { if (evt.type == "mousedown") evt.target.setAttribute("fill", "black"); else if (evt.type == "mouseup") evt.target.setAttribute("fill", "yellowgreen"); } function Magical(evt) { if (evt.type == "mouseover") evt.target.nextSibling.nextSibling.setAttribute("visibility", "hidden"); else

Learn SVG

Chapter 10 Scripting the DOM

42

evt.target.nextSibling.nextSibling.removeAttribute("visibility"); evt.stopPropagation(); } function Mutate(evt) { var elem = evt.target; elem.setAttribute("display", "none"); // hide the displayed element .. if (elem.nodeName == "rect") // rectangle was displayed .. elem.nextSibling.removeAttribute("display"); // .. show ellipse else // ellipse was be displayed .. elem.previousSibling.removeAttribute("display"); // show rectangle } function ClickCounter(evt) { var clickText = evt.target.parentNode.parentNode.lastChild.firstChild; clickText.nodeValue = evt.detail + ". click" } ]]></script> <g onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);"> <rect x="10" y="100" width="90" height="40" fill="blue" opacity="0.4" /> <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" onmouseover="Magical(evt);" onmouseout="Magical(evt);"/> <rect x="210" y="100" width="90" height="40" fill="yellowgreen" altfill="black" opacity="0.4" onmousedown="ChangeColor(evt);" onmouseup="ChangeColor(evt);"/> <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" onclick="Mutate(evt);" /> <ellipse cx="355" cy="120" rx="45" ry="20" fill="orange" display="none" onclick="Mutate(evt);" /> <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" onclick="ClickCounter(evt);"/> </g> <text x="55" y="160" text-anchor="middle">highlight</text> <text x="155" y="160" text-anchor="middle">magical</text> <text x="255" y="160" text-anchor="middle">changing color</text> <text x="355" y="160" text-anchor="middle">mutate</text> <text x="455" y="160" text-anchor="middle">click</text> </svg>

Dragging Around

The observant reader will have noticed that there is one mouse event still missing. That is the useful onmousemove event. With the help of this event we reach an even higher level of interactivity. We will learn now, how to manipulate geometry with the mouse. Mouse Move Event Whenever the user moves the mouse pointer over an SVG element, and that element had registered itself as an event listener for the onmousemove event, the affiliated event handler gets called. Let us investigate this by a simple example.

Learn SVG

Chapter 10 Scripting the DOM

43

Figure 10-14. Get coordinate for mouse 1. The SVG document is set out with the following code.
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="400" height="300" xmlns="http://www.w3.org/2000/svg" > <text id="coords" x="385" y="20" text-anchor="end">mouse position (?, ?)</text> <rect x="100" y="50" width="250" height="200" stroke="black" fill="moccasin" /> <text x="100" y="45" text-anchor="middle">(100,50)</text> <text x="350" y="264" text-anchor="middle">(350,250)</text> </svg> It consists of a text element with the id coords in the documents upper right corner and a moccasin coloured rectangle. The last two text elements only display the coordinates of the

rectangles upper left and lower right corner. Now we want to display the actual mouse coordinates in the upper right text string. 2. To achieve this we add an onmousemove event attribute to the <rect> element and implement a function ShowCoords that can be called by the event handler.
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="400" height="300" xmlns="http://www.w3.org/2000/svg" > <script type="text/ecmascript"> <![CDATA[ function ShowCoords(evt) { var coordText = evt.target.ownerDocument.getElementById("coords").firstChild; coordText.nodeValue = "mouse position (" + evt.clientX + "," + evt.clientY + ")"; } ]]> </script> <text id="coords" x="385" y="20" text-anchor="end">mouse position (?, ?)</text> <rect x="100" y="50" width="250" height="200" stroke="black" fill="moccasin" onmousemove="ShowCoords(evt);"/> <text x="100" y="45" text-anchor="middle">(100,50)</text> <text x="350" y="264" text-anchor="middle">(350,250)</text> </svg>

Learn SVG

Chapter 10 Scripting the DOM

44

Figure 10-15. Mouse position in rectangle It works great. When moving around with the mouse pointer the coords string is changed according to the mouse position coordinates. We can verify the coordinates of the upper left and lower right corner also, but it does not work, when we leave the moccasin rectangle. No problem, since you remember what I told you about event bubbling. We only need to take care of the onmousemove event in the rectangles parent, the document element. So our document should be adjusted to look like this
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd"> <svg width="400" height="300" xmlns="http://www.w3.org/2000/svg" onmousemove="ShowCoords(evt);"> <script type="text/ecmascript"> <![CDATA[ function ShowCoords(evt) { var coordText = evt.target.ownerDocument.getElementById("coords").firstChild; coordText.nodeValue = "mouse position (" + evt.clientX + "," + evt.clientY + ")"; } ]]> </script> <text id="coords" x="385" y="20" text-anchor="end">mouse position (?, ?)</text> <rect x="100" y="50" width="250" height="200" stroke="black" fill="moccasin"/> <text x="100" y="45" text-anchor="middle">(100,50)</text> <text x="350" y="264" text-anchor="middle">(350,250)</text> </svg>

Trying this out doesnt work either. Hmm, we are rather helpless now. So we decide to consult the SVG specification of the wise W3C. There we read: The target element (of the mouse event) is the topmost graphics element whose relevant graphical content is under the pointer at the time of the event. This basically means No paint, no event. So we need an element with a stroked or filled region under the mouse pointer, which will function as the events originator.

Learn SVG

Chapter 10 Scripting the DOM

45

3. Try giving this SVG engine what it demands: A rectangle as big as the width and the document.

height

of

<rect x="5" y="5" width="390" height="290" stroke="black" fill="none" />

This doesnt work either. 1. After playing some time with the <rect>s attributes we finally end up with a white filled rectangle and a working document.
<rect x="5" y="5" width="390" height="290" stroke="black" fill="white" />

Figure 10-16. Mouse position on canvas You need a painted elements region at first to initiate a mouse event. The actual event listener might be any ancestor of that element.

Magic eyes

Let us convert, what we learnt just now into a more illustrative example. Maybe you know Eyes, a funny little graphical application, well known to Unix users. There are two eyes on the screen, wherever you had arranged them, usually in a corner somewhere. These eyes are permanently following the mouse pointer, so that it appears they are constantly watching what you do on the screen. 1. As an extension to those Unix eyes we also want to have an optical ray from each pupil to the mouse pointer. So we start with this SVG document.
<?xml version="1.0"?> <svg width="600" height="300"> <rect width="600" height="300" stroke="none" fill="white"/> <g id="leftEye"> <circle cx="280" cy="50" r="20" stroke="black" fill="wheat" /> <line x1="280" y1="50" x2="290" y2="50" stroke="lightgray" stroke-width="0.5" /> <circle cx="290" cy="50" r="10" stroke="none" fill="black" /> </g> <g id="rightEye">

Learn SVG

Chapter 10 Scripting the DOM

46

<circle cx="320" cy="50" r="20" stroke="black" fill="wheat" /> <line x1="320" y1="50" x2="330" y2="50" stroke="lightgray" stroke-width="0.5" /> <circle cx="330" cy="50" r="10" stroke="none" fill="black" /> </g> </svg>

Figure 10-17. Eyes 2. As we discovered in the last exercise, well need a filled rectangle as an event generating background. This is the documents first element. Then follow two nearly identical groups, representing the eyes. Each eye consists of an outer wheat filled circle and an inner black circle with half the radius of the outer one the pupil. Initially covered by the pupil, hence invisible, there is also a thin grey line from each eyes centre to the affiliated pupils centre point the eye ray rubberbands. 3. Next we need to determine the mouse coordinates. We can use evt.clientX and evt.clientY here.
function Eyes(evt) { MoveEye(evt.target.ownerDocument.getElementById("leftEye"), evt.clientX, evt.clientY); MoveEye(evt.target.ownerDocument.getElementById("rightEye"), evt.clientX, evt.clientY); }

4. This is followed by code to navigate to the right eye group element.


function MoveEye(eyeGroup, x, y) {

5. Then we need to ensure pupil and ray alignment.


var pupil = eyeGroup.lastChild, ray = pupil.previousSibling,

Learn SVG

Chapter 10 Scripting the DOM

47

6. Calculate angle of the line from the eyes centre to the mouse pointer coordinates relative to the positive x-axis. Rotate the pupil about the eyes centre with this angle. We use rotate(angle, Draw the ray from the eyes centre to the mouse pointer. Navigate to the left eye group element.
function Eyes(evt) { MoveEye(evt.target.ownerDocument.getElementById("leftEye"), evt.clientX, evt.clientY); MoveEye(evt.target.ownerDocument.getElementById("rightEye"), evt.clientX, evt.clientY); } function MoveEye(eyeGroup, x, y) { var pupil = eyeGroup.lastChild, ray = pupil.previousSibling, xc = parseFloat(ray.getAttribute("x1")), // yc = parseFloat(ray.getAttribute("y1")), // angle = Math.atan2(y-yc, x-xc); // axis pupil.setAttribute("transform", "rotate(" + angle/Math.PI*180 + ray.setAttribute("x2", x); // ray.setAttribute("y2", y); // } cx, cy)

here.

eye center x-coordinate eye center y-coordinate angle between ray and x"," + xc + "," + yc + ")"); set endpoint of ray .. .. onto mousecoordinates.

Try to understand these two functions by yourself, by correlating the steps in the algorithm to the code lines. We still have to invoke the Eyes function with the onmousemove handler of the event generating rectangle.
<svg width="600" height="300" onmousemove="Eyes(evt);" >

With this we have our funny curious little Unix eyes. Figure 10-18. Magic eyes

Learn SVG

Chapter 10 Scripting the DOM Figure 10-19. Magic eyes for another position

48

If you are thinking now about other interesting applications of this useful onmousemove event, I am pleased to achieve my goal with this subchapter. Here is the complete working
<?xml version="1.0"?> <svg width="600" height="300" onmousemove="Eyes(evt);" > <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/> <script type="text/ecmascript"> <![CDATA[ function Eyes(evt) { RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement); MoveEye(evt.target.ownerDocument.getElementById("leftEye"), evt.clientX, evt.clientY); MoveEye(evt.target.ownerDocument.getElementById("rightEye"), evt.clientX, evt.clientY); } function MoveEye(eyeGroup, x, y) { var pupil = eyeGroup.lastChild, ray = pupil.previousSibling, xc = parseFloat(ray.getAttribute("x1")), // eye center x-coordinate yc = parseFloat(ray.getAttribute("y1")), // eye center y-coordinate angle = Math.atan2(y-yc, x-xc); // angle between ray and x-axis pupil.setAttribute("transform", "rotate(" + angle/Math.PI*180 + "," + xc + "," + yc + ")"); ray.setAttribute("x2", x); // set endpoint of ray .. ray.setAttribute("y2", y); // .. onto mousecoordinates. } ]]> </script> <rect width="600" height="300" stroke="none" fill="white" /> <g id="leftEye"> <circle cx="280" cy="50" r="20" stroke="black" fill="wheat" /> <line x1="280" y1="50" x2="290" y2="50" stroke="lightgrey" stroke-width="0.5" /> <circle cx="290" cy="50" r="10" stroke="none" fill="black" /> </g> <g id="rightEye"> <circle cx="320" cy="50" r="20" stroke="black" fill="wheat" /> <line x1="320" y1="50" x2="330" y2="50" stroke="lightgrey" stroke-width="0.5" /> <circle cx="330" cy="50" r="10" stroke="none" fill="black" /> </g> </svg>

Script Animation We will now do a little script animation. To be precise we will implement time-based animation scripts, scripts controlled by a timer. In this example animation will mean simple element motion. So, you might ask, why not implement a simple loop something like:
var circle = doc.getElementById(ball); for (var i=1; i<800; i++) circle.setAttribute(cx, i);

. But there is one important aspect, because of which the above loop wont work under certain conditions. The loop takes all program resources, so that there is no chance for other activities until the loop finished it work. ECMAScript is designed so that the host environment the

Learn SVG

Chapter 10 Scripting the DOM

49

browser or SVG implementation is able to kill a script after a certain time of no response. This is very important to avoid endless loops on websites or in XML documents. The consequence of this is yet, that our elegant solution does not work this way. So we obviously do need a timer of some form. ECMAScript does not supply us with a timer, but the window object does. The window object comes with every script supporting browser and is well known to HTML scripters. It has some interesting properties and methods which we can also use inside of an SVG script.
Windows property: String status

the text string in the browsers status bar. display an alert box with a message str. execute statement after time has passed.

Windows methods: void alert(str) void setTimeout(statement,time)

The setTimeout method seems to satisfy our needs. We rewrite our simple loop now, so that it works.

Figure 10-20. Moving red circle As you see, we did get managed to make the circle move continuously to the right. To achieve this we simply have to increment the circle centres x-coordinate. Let us look at the complete code.
<?xml version="1.0"?> <svg width="800" height="400" onload="Init(evt)"> <script><![CDATA[ var ball = null; function window.Animate() .. { var cx = parseFloat(ball.getAttribute("cx")); ball.setAttribute("cx", cx+1); if (cx < 200) window.setTimeout("window.Animate()", 10); } function Init(evt) { ball = evt.getTarget().getOwnerDocument().getElementById("ball"); window.Animate(); } ]]></script> <circle id="ball" cx="10" cy="200" r="20" fill="red" /> </svg> // current x-coordinate .. // set new x-coordinate .. // continuously get called after 10 milliseconds

The SVG document consists of one <circle> element which has the id="ball" attribute. When the document is completely loaded, the onload event handler of the <svg> document element invokes the Init function. This Init function stores the <circle> element object

Learn SVG

Chapter 10 Scripting the DOM

50

in a global variable ball that was initially set to null. After that the window.Animate() method is called. No I didnt forget to tell you that the window object also has an Animate() method. A particular characteristic of the window object is its expandability. That means we are able to add custom properties and methods to that object. Exactly that we did, when we defined the function
function window.Animate() { ... }

Nice feature, isnt it. But why should we use such a complicated syntax since function Animate() seems so much cleaner. Ok, I will come to that in a minute. Lets look at that functions body first. In the functions first line we store the circle centres x-coordinate in a variable cx. The next statement increments this x-coordinate via the <circle>s setAttribute method by adding 1 pixel. The third and last statement is the call of the windows setTimeout method, depending on the value of the variable cx. Now it is getting interesting. The functions first argument is a string containing an ECMAScript statement. We set this string to the literal value "window.Animate()". The second argument has the value 10, that means 10 milliseconds. With this we instruct the window object to evaluate and execute the statement string after an elapsed time of 10 milliseconds. Since the statement string concludes a recall of window.Animate(), this method will get called again and again. As the window object does not live in our document or the DOM environment, but is a browser object, the normal functions in our SVG document are invisible to it. That it the reason why it would fail to hand over something like Animate() to the window.setTimeout method. As a way out of this we make the Animate function a method of the window object itself. We should also do not confuse this call back technique with a recursive function, i.e. a function directly calling itself. Just to avoid an infinite motion of the ball, we instructed to call back window.Animate() only as long as the variable cx has a value less than 200. We should also know, that the time difference of 10 milliseconds is only a request. The scripting engine will do its best to fulfill that. But if the calculation itself lasts longer than 10 milliseconds or there is currently not so much processor time available, we will have to wait a little longer for the next animation step. The smallest possible value with window.setTimeout is 1 millisecond. An SVG Pendulum

Learn SVG

Chapter 10 Scripting the DOM

51

Now I will show you a much more elaborate example. An oscillating, and rather attractive, pendulum.

Figure 10-21. Pendulum I realise youve seen the formula below and are possibly panicking! Dont worry, I dont want you to understand a lot of mathematics and physics. I just give you the pendulum formula.

(t ) = cos(
In this formula Teta t g l alpha deflexion angle. time gravity constant. pendulum length amplitude

g t) l

As I said I do not want to focus here on the programming of this formula. This is quite similar to the previous example. I will rather show you by this example, how we can embed this SVG document into an HTML document and control the animation in a simple manner from the HTML side.
Please note, that I did not discuss any SVG implementation specific details until now. Everything I told you was pure SVG and pure DOM. Now with this example there are some implementation dependent features used, so it works only with Adobes SVG Viewer 3.0 and Internet Explorer 5.5 or above.

Here is the SVG document code first.


<?xml version="1.0"?> <svg width="800" height="400" onload="Init(evt)"> <script type="text/ecmascript"> <![CDATA[

Learn SVG

Chapter 10 Scripting the DOM

52

var pendulum = null, pendulumLen = 200, g = 9.81 * 1000, amplitude = 60, t = 0; function window.parent.Animate() { t = t + 0.01; var teta = amplitude*Math.cos(Math.sqrt(g/pendulumLen)*t); pendulum.setAttribute("transform", "translate(400,50) rotate(" + teta + ")"); if (window.parent.active) window.setTimeout("window.Animate()", 1); } function Init(evt) { pendulum = evt.getTarget().getOwnerDocument().getElementById("pendulum"); window.parent.active = false; window.parent.Animate(); } ]]> </script> <defs> <g id="pendulumGroup"> <line x1="0" y1="0" x2="0" y2="200" stroke="blue" stroke-width="5" stroke-linecap="round" /> <circle cx="0" cy="200" r="20" stroke="blue" stroke-width="5" fill="lightgray" /> </g> </defs> <rect width="800" height="400" fill="white" /> <use id="pendulum" xlink:href="#pendulumGroup" transform="translate(400,50) rotate(0)" /> <circle cx="400" cy="50" r="5" stroke="blue" stroke-width="3" fill="lightgray" /> </svg>

In order to control the animations start and stop we add a new active property to the window.parent object. As I mentioned before window is a browser object, and with window.parent we have also access to it from HTML side. Here is the HTML code.
<html> <head> <title> SVG pendulum </title> </head> <body> <center> <h1>SVG pendulum</h1> <embed src="pendulum.svg" height="400" width="800"> <form> <input type=button value="Start" onClick="window.active=true; window.Animate();"> <input type=button value="Stop" onClick="window.active=false;"> </form> </center> </body> </html>

It is not so complicated. We embed the SVG document with the HTML <embed> element using the SVGView control by Adobe here. Hereafter we create a form with two buttons start and stop. To the onclick event handler of the start button we assign the ECMAScript code
window.active=true; window.Animate();

Since the active property we introduced to the window object on SVG side is also accessible here, we set it to true now. To start the animation we simply have to invoke the window.Animate() method now from here. Voila, it works.

Learn SVG

Chapter 10 Scripting the DOM

53

To stop the animation is similar simple. We assign to the stop buttons onclick event handler the code
window.active=false;

That works, since when the window.parent.Animate() is executed the next time the conditional statement

Figure 10-22. SVG pendulum


if (window.parent.active) window.setTimeout("window.parent.Animate()", 1);

will prevent the window.setTimeout method from calling window.parent.Animate() any further. There are lot more possibilities with script animation, especially when you start getting into user interactivity. Ill leave it up to you where you take it. If you want to animate some SVG elements, consider to use SMIL animation first, before you try to solve your problem with script animation.

Chapter 11 : Mixing XML based Languages


Overview
SVG is designed to be used with other XML technologies such as DOM, XHTML, CSS, XSL, CML, MathML, SMIL and RDF. This image demonstrates some of the benefits of being able to render XHTML, SVG, and MathML in the same document.

Figure 11-1.

SVG inline with XHTML and MathML!

Learn SVG

Chapter 11 Mixing XML Languages

Namespaces and Extensibility


SVG documents use the public SVG Document Type Definition (DTD) from the W3C Web site (www.w3c.org/Graphics/SVG). The SVG DTD contains or references all the rules and syntax of the SVG language. In order to better understand how SVG works we need to take a look at XML and extensibility. XML is the markup-language grammar which is the basis for a whole new generation of markup-languages, such as custom XML "vocabularies", industry-namespaces, etc. which work hand-in-hand with other XML-namespaces including the styling-language XSL, the transformation-language XSLT, XML Linking Language (Xlink), and many other XMLlanguages. The genius of SVG lies in its vocabulary for describing vector graphic shapes, images, and text as well as in SVG's compatibility with the XML 1.0 Recommendation, Namespaces in XML Recommendation, HTML4, and XHTML as well as conformance to the Cascading Style Sheet (CSS) level 2 specification, XSL Transformations (XSLT) Version 1.0, and much of the Document Object Model (DOM) level 2 specification. SVG is to graphics what XHTML is to text, CML is to the description of chemical molecules and MathML is to mathematical equations. In this chapter we will delve into how SVG can be used with XHTML, CML and MathML using XSLT and/or mixed namespaces. There is even a W3C profile that enables mixing XHTML, MathML and SVG content in the same document using XML namespaces. This profile is explained in detail here http://www.w3.org/TR/XHTMLplusMathMLplusSVG/ .

SVG and XHTML


SVG is very robust and has been designed to excel at describing and rendering 2D graphics. SVG can do some of the things that XHTML can do. Likewise, XHTML can do some of the things that SVG can do. However, the full potential of the Web is found in the ability to mix complimentary technologies. Using namespace prefixes we can mix elements from both the XHTML and SVG specifications. The namespace prefixes act as a translator for browsers so that they can (decipher / interpret) which language is currently being used.

XHTML in Short
Everyone has heard of HTML, well, XHTML is simply a reformulation of HTML 4 as an XML 1.0 application. What are the goals of XHTML? XHTML enables the presentation of semantic textual content and images and on the Web. In more detail, XHTML is intended to:

provide for extensibility.

Learn SVG

Chapter 11 Mixing XML Languages

be human legible and simple for software to generate and process.

XHTML also provides a reliable way for search-engines to find certain on the Web.

Rendering XHTML and SVG


At the current time few browsers have "native" support for XHTML. However Mozilla and Amaya do have native support for rendering XHTML with SVG. There are also a few other browsers that will render XHTML in particular, X-Smiles (java) www.x-smiles.org from The Helsinki University of Technology. The main disadvantage of using a third party extension to render XHTML within a web page is that it requires specific markup to specify the rendering extension (so <applet> for Java applets, <embed> for plugins and <object> for Microsoft Behavior extensions). The use of such markup ties the document to one particular platform, whereas the ideal of publishing information on the Web is that it should be accessible to all using a range of tools. This next example consists of an XHTML document to contains an SVG document fragment.

Figure 11-2. Multi-Namespace XHTML/SVG Document One major advantage of this approach is that we can use script to access and manipulate both the XHTML and SVG DOM. Heres the code for this document.
<?xml version="1.0" standalone="no"?> <html xmlns:iSvg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> <div style="font-family:Verdana,Arial,san-serif;font-size:20px">Multi-Namespace Document in Internet Explorer</div> <p></p> <div style="position:absolute; left:120; top:215; width:270px; height:25px; padding:3px; border:solid; background-color: #CCCCCC; layer-background-color: #CCCCCC;font-family:Verdana,Arial,san-serif;font-size:15px;">Absolute positioned XHTML text.</div>

Learn SVG

Chapter 11 Mixing XML Languages

<iSvg:svg id="inlineSVG" width="800" height="600" viewBox="0 0 400 300" xmlns:svg="http://www.w3.org/2000/svg"> <iSvg:defs> <iSvg:pattern id="gridPattern" width="10" height="10" patternUnits="userSpaceOnUse"> <iSvg:path d="M10 0 L0 0 L0 10" style="fill:none;stroke:rgb(128,128,128);stroke-width:0.25"/> </iSvg:pattern> <!-- Pattern Gradient 01 --> <iSvg:radialGradient id="bubblePattern01" gradientUnits="objectBoundingBox" fx="20%" fy="20%" style="opacity:0.5;"> <iSvg:stop offset="0%" style="stop-color:white;" /> <iSvg:stop offset="70%" style="stop-color:pink;" /> <iSvg:stop offset="100%" style="stop-color:blue;" /> </iSvg:radialGradient> </iSvg:defs> <iSvg:rect id="grid" width="100" height="100" style="stroke:rgb(128,128,128);strokewidth:0.25;fill:url(#gridPattern)"/> <!-- grid --> <iSvg:text x="3" y="9" style="font-size:8">(0,0)</iSvg:text> <!-- example --> <iSvg:path d="M30 20 L220 20 M30 40 L220 40 M30 60 L220 60" fill="none" stroke="black" stroke-width="0.5"/> <iSvg:text fill="black"> <iSvg:tspan x="30" y="20" style="font-size:12;fontfamily:Verdana,serif;">Absolute positioned SVG text.</iSvg:tspan> <iSvg:tspan x="30" y="40" style="font-size:9;fontfamily:Verdana,serif;">This text spans multiple lines. Word</iSvg:tspan> <iSvg:tspan x="30" y="60" style="font-size:9;fontfamily:Verdana,serif;">wrapping needs more intelligence.</iSvg:tspan> </iSvg:text> <iSvg:circle cx="10" cy="90" r="10" stroke="black" stroke-width="10" fill="lightgray" /> <iSvg:circle cx="240" cy="90" r="10" stroke="black" stroke-width="10" fill="lightgray" /> <iSvg:circle id="bubble" cx="50" cy="50" r="10" style="fill:url(#bubblePattern01);opacity:0.5;"> <iSvg:animateTransform attributeName="transform" type="translate" values="0 0;40 40;0 -40;-20 0;-40 40;" additive="sum" dur="20s" repeatDur="indefinite"/> </iSvg:circle> </iSvg:svg> </body> </html>

With this reference document, we want to test now the rendering result of different browsers.

Learn SVG Amaya

Chapter 11 Mixing XML Languages

Amaya is a full-featured web client developed by W3C for experimenting and validating web specifications at an early stage of their development. The current version 6.1 supports XHTML 1.0, CSS2, and a subset of SVG 1.0. These Web technologies are tightly integrated using multi-namespace documents. And the best of all Amaya is not only a browser, it is also an editor specifically developed for math editing. With it we can comfortably create and modify formulas as well as the textual context using a consistent set of editing commands.

Figure 11-3. Multi-Namespace Document in Amaya The most significant disadvantage of the current Amaya implementation is the lack of scripting support together with DOM implementation. So we get nice static documents but still have to wait for general interactive and dynamic content. Netscape and Mozilla Netscape (version 7.0 preview release 1) and Mozilla 1.0 also have improved the support of multi-namespace documents. SVG capabilities are not robust. The Netscape browser still has no native SVG support and also doesnt allow to embed Adobes SvgViewer in contrast to earlier versions.

Learn SVG

Chapter 11 Mixing XML Languages

Figure 11-4. Multi-Namespace Document in Netscape Mozilla 1.0 did not include native support for SVG. So lets hope, that the situation becomes a lot better in the near future. Javascript/DOM support is usually no problem with both browsers. Though I didnt test it because of the lack of SVG. Internet Explorer Microsofts Internet Explorer is the only browser that has no native support for SVG. Therefore we have to rely on third party components using the proprietary behavior technology. the following examples uses the Adobes SvgViewer 3.0 which contains an SVG binary behavior.

Figure 11-5. Multi-Namespace Document in Internet Explorer

Learn SVG

Chapter 11 Mixing XML Languages

We have to modify our code as follows for Internet Explorer.


<?xml version="1.0" standalone="no"?> <html xmlns:iSvg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/1999/xhtml"> <head> <object id="AdobeSVG" classid="clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2"> <img src="rasterSVG.png" border="0"/> </object> <?import namespace="iSvg" implementation="#AdobeSVG"?> </head> <body> <div style="font-family:Verdana,Arial,san-serif;font-size:20px">Multi-Namespace Document in Internet Explorer</div> <p></p> <div style="position:absolute; left:120; top:215; width:270px; height:25px; padding:3px; border:solid; background-color: #CCCCCC; layer-background-color: #CCCCCC;font-family:Verdana,Arial,san-serif;font-size:15px;">Absolute positioned XHTML text.</div> <iSvg:svg id="inlineSVG" width="800" height="600" viewBox="0 0 400 300" xmlns:svg="http://www.w3.org/2000/svg"> same code goes here </iSvg:svg> </body> </html>

Just remember that this is a example will not work in Netscape Navigator. The changes that we had to make to our code makes this document nonstandard, proprietary, and specific to Internet Explorer. Also, if you run this examples in IE you will notice that you cannot zoom or pan; nor can you select and of the SVG text. The Semantic Web This type of reusability is a major benefit of all XML-based languagues. This is possible only because the rules of grammar are well defined and the language has been created with a vocabulary that is robust enough that it is able to reference and interpret content that has been defined elsewhere. This touches upon the concept of the Semantic Web and it has far-reaching implications. SVG fits into the larger picture as a language for describing two-dimensional vector graphics (see, www.sciam.com/2001/0501issue/0501berners-lee.html for more information on this topic).

Communication Efficiencies in SVG Meaningful Communication

Learn SVG

Chapter 11 Mixing XML Languages

Some would consider this a fine point but as we had briefly stepped back to understand the Semantic Web I felt it would be worthwhile to also contemplate the following point. There is an old saying stating that half of what we say has meaning while the other half is only there so that you will understand my meaning. It is the same with any language and is especially apparent in SVG. The actual data that was communicated to us is often only a fraction of the total text or content in the file. The rest of the content in the SVG document is there merely to communicate some abstractions to the SVG viewer. In fact computer language is usually even more abstract and efficient when it is in binary or hexadecimal format. So why is SVG written in text format rather than in a binary format? The moral, next time youre eating your soggy breakfast cereal and are frustrated that you cant find your way through the maze on the back of cereal box remember that just because something exists does not necessarily mean that it needs to be understood.

SVG Concepts: XML Grammar / Well-formed


Syntax is important in SVG. If you look back at each example you will notice some structural similarities forming. SVG is written using XML grammar, which means there are a few rules we must follow in order for our SVG graphics to be read correctly by SVG viewers. Every language has a certain grammar or set of rules that define the structure of the language. XML can be thought of as the grammar that defines the structure of the SVG language. If an SVG document does not follow the rules of XML grammar then it is not well formed and will probably not be interpreted or displayed by SVG viewers. Basically, the term well-formed means that there are some grammatical rules that must be followed. The first XML rule of grammar to learn is that there can be no overlapping element tags. For example, <p><I></I></p> is well-formed while <P><I></P></I> is not wellformed. Also, XML is case-sensitive which means that even if elements contain the same characters they will still have different meanings if each of the letters does not use the same case. In other words the following XML is not well-formed: <text>This is not well-formed and will not be displayed by viewers.</TEXT>. Currently Web browsers do interpret and display HTML documents that are not well-formed. But the browser support for rendering poorly formed HTML documents has on the one hand made HTML an easy language to use but on the other hand has resulted in large browser application sizes which render the poorly-formed HTML in different ways. The variances in the way different browsers format HTML has often required tremendous resources to go into programming for cross-browser compatibility. Out of this grew a great desire for conformance to open-standards that are coming to fruition in XML-based languages such as SVG. Another great benefit of having documents follow these basic grammar rules is that computers are able to interpret the tagged content. This allows for some excellent positive externalities such as filtering, searching, inter-language transformations, and the creation of new efficient languages such as SVG.

SVG and MathML

Learn SVG

Chapter 11 Mixing XML Languages

It is painfully ironic from a scientists point of view that the Web, which was originally invented to help them collaborate, still lacks acceptable support for one of the most essential scientific language elements mathematical equations. As a result, mathematical content is either written based on the ASCII character set which usually works only for very simple equations or it is typically presented on Web Sites in one of a number of unsatisfactory ways. Equations can be viewed as raster images embedded in HTML code or within PDF files. In these cases, however, equations end up as foreign data types, which refuse to join in naturally behavior, such as: Dynamically adjust to customizable browser font size. Styling along with the surrounding markup text. Attach hyperlink sources and targets. Search them and their surrounding text at the same time. Authoring them using conventional Web design tools. Attach scripted behavior to them.

However it is no new idea to embed Mathematics in HTML. Potential support of equations with HTML was discussed in 1993 with HTML+ and formally added in HTML 3.2 later in 1996. But it seemed to be either a nontrivial task or not very desirable from the view of the major browser vendors. So in 1997 a Math Working Group was constituted at the W3C to propose a mathematical markup langage called MathML for describing mathematical content based on XML. In April 1998, MathML 1.01 Specification was announced as a W3C recommendation and two years later in 2000 the revised version MathML 2.0 followed. But until the time of this writing the MathML support by the major browser vendors was hardly worth mentioning. One aspect of course is the persistent popularity of Donald Knuths TEX a comprehensive and widely used system for scientific publishing and math typesetting. Unfortunately this language although markup based werent easy to integrate with the Webs Xml centric model. Happily the situation seems to improve rapidly from now on, as there are recent efforts of the W3C and both commercial vendors and the open source community, which are finally bearing fruits. We will have a closer look at these results and applications later.

MathML in Short
W3Cs answer to a frequently asked MathML question reads: What are the goals of MathML ? The principal goal of MathML is to enable mathematics to be served, received, and processed on the Web, just as HTML has enabled this functionality for text. In more detail, MathML is intended to:

encode mathematical material suitable for teaching and scientific communication at all levels. encode both mathematical notation and mathematical meaning.

Learn SVG

Chapter 11 Mixing XML Languages

10

facilitate conversion to and from other math formats, both presentational and semantic. allow the passing of information intended for specific renderers and applications. support efficient browsing for lengthy expressions. provide for extensibility. be well suited to template and other math editing techniques. be human legible (though it is very verbose), and simple for software to generate and process.

The correct visual presentation of mathematical equations the mathematical notation - is the most obvious task of MathML at the first glance. This is exactly what TEX reliably does. On the other side MathML also has to support semantics in the sense of mathematical meaning. This is indeed more than TEX is providing and allows exchange of mathematical content between applications and a reliable way for search-engines to find certain mathematical (sub)expressions on the Web. In order to match those partly contrary goals the designers of the MathML specification decided for a two-layered architecture consisting of two different sets of XML elements: presentation markup and content markup. Presentation markup is intended for typesetting math and content markup is intended for treating mathematical equations semantically. We will look at presentation MathML here exclusively.

Consider the following formula to calculate the length of a vector with the Cartesian coordinates (x,y).

r = x2 + y 2
This equation reads in MathML
<math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mi>r</mi> <mo>=</mo> <msqrt> <mrow> <msup> <mi>x</mi> <mn>2</mn> </msup> <mo>+</mo> <msup> <mi>y</mi> <mn>2</mn> </msup> </mrow> </msqrt>

Learn SVG
</mrow> </math>

Chapter 11 Mixing XML Languages

11

The most common MathML presentation elements are the token elements <mi>, <mn> and <mo>. Token elements are the only elements in MathML which can contain character data. So every number, variable and operator in an expression must appear in a token element. <mi> elements are used for identifiers. Identifiers are usually displayed in italics like r, x, y in the above equation. <mn> elements contain numbers, which are displayed in an upright font. <mo> elements are exclusively used for all kind of operators. Operators in MathML not only include '+', '-' and '=' symbols, but also parentheses, punctuation and accents. Moreover mathematical functions like 'sin' or 'log' are also used with the <mo> element and appear in an upright font. Here is a complement to our equation above. With those two we can perform a conversion from Cartesian to polar coordinates.

= arctan

y x

<math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mi>&psi;</mi> <mo>=</mo> <mo>arctan</mo> <mfrac> <mi>y</mi> <mi>x</mi> </mfrac> </mrow> </math>

We should be able now to arrange tokens into mathematical expressions. For this MathML provides us with a list of layout elements. These so called layout schemata are container elements exclusively, which means that we can only use other MathML elements as child elements and no character content. The <mrow> element is the most common and important layout schema. It can contain any number of child elements, which are displayed in a horizontal row. The <mfrac> element can have exactly two children. The first one will be positioned as the numerator of a fraction, the second one will be the denominator. The <msqrt> element can be used with an arbitrary number of child elements. These are rendered under a radical sign. The <msub> and <msup> elements expect two child elements, which are displayed as a base and a sub- or superscript. For elements with both a subscript and a superscript MathML provides us with the <msubsup> element having three child elements consequently, base, subscript, superscript.

Learn SVG

Chapter 11 Mixing XML Languages

12

a11 T = a21 0

a12 a22 0

tx ty 1

<math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mstyle mathvariant='bold' mathsize='normal'> <mi>T</mi> </mstyle> <mo>=</mo> <mrow><mo>(</mo> <mrow> <mtable> <mtr> <mtd> <mrow><msub><mi>a</mi><mrow><mn>11</mn></mrow></msub></mrow> </mtd> <mtd> <mrow><msub><mi>a</mi><mrow><mn>12</mn></mrow></msub></mrow> </mtd> <mtd> <mrow><msub><mi>t</mi><mi>x</mi></msub></mrow> </mtd> </mtr> <mtr> <mtd> <mrow><msub><mi>a</mi><mrow><mn>21</mn></mrow></msub></mrow> </mtd> <mtd> <mrow><msub><mi>a</mi><mrow><mn>22</mn></mrow></msub></mrow> </mtd> <mtd> <mrow><msub><mi>t</mi><mi>y</mi></msub></mrow> </mtd> </mtr> <mtr> <mtd><mn>0</mn></mtd> <mtd><mn>0</mn></mtd> <mtd><mn>1</mn></mtd> </mtr> </mtable> </mrow> <mo>)</mo> </mrow> </mrow> </math>

In Math we often have array like structures as matrices or determinants. For displaying these MathML offers tables which are very similar to the well known HTML tables. The <mtable> element contains any number of <mtr> table row elements. A <mtr> element itself can hold an arbitrary number of <mtd> table data cells, whereas the <mtd> element is not restricted regarding its child element types and number.

Learn SVG

Chapter 11 Mixing XML Languages

13

With these few MathML elements we already can create an appreciable set of different equation types indeed most of the formulas in Appendix D.

Rendering MathML and SVG


At the current time few browsers have "native" support for MathML, and none have native support for the Content part of MathML. However Mozilla and Amaya have good support for Presentation MathML, and for other browsers there are a range of extensions that will render MathML (in particular, WebEQ and MathPlayer from Design Science and Techexplorer from IBM). The main disadvantage of using a third party extension to render MathML within a web page is that it requires specific markup to specify the rendering extension (so <applet> for Java applets, <embed> for plugins and <object> for Microsoft Behavior extensions). The use of such markup ties the document to one particular platform, whereas the ideal of publishing information on the Web is that it should be accessible to all using a range of tools. As a way out of this dilemma the W3C presents an XSLT based solution the universal MathML stylesheet.The stylesheet transforms the supplied XML file, adding whatever markup is required to render MathML in the current browser, and pass the resulting document to the browser for rendering. This solution works quite good and will be used her with our example also.

Figure 11-6. Multi-Namespace XHTML/MathML/SVG Example Document

This examples code is presented here first. It consists of an HTML document with simple embedded SVG and XHTML document fragments. Her is how it looks like. Here is the code.
<?xml version="1.0" encoding="iso-8859-1"?> <?xml-stylesheet type="text/xsl" href="http://www.w3.org/Math/Group/XSL/pmathml.xsl"?> <html xmlns="http://www.w3.org/1999/xhtml"> <head>

Learn SVG

Chapter 11 Mixing XML Languages

14

<title>MathML and SVG in Amaya 6.1</title> </head> <body> <h2 style="text-align:center">MathML and SVG Support in Amaya 6.1</h2> <p> This polynomial is the equation of the quadratic Bzier curve a simple parabolic curve </p> <p style="text-align:center"> <math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mi>p</mi><mo>(</mo><mi>t</mi><mo>)</mo><mo>=</mo> <msup> <mrow> <mo>(</mo><mn>1</mn><mo>&minus;</mo><mi>t</mi><mo>)</mo> </mrow> <mn>2</mn> </msup> <mo>&sdot;</mo> <msub> <mi>p</mi> <mn>1</mn> </msub> <mo>+</mo><mn>2</mn><mi>t</mi><mo>&sdot;</mo> <mo>(</mo><mn>1</mn><mo>&minus;</mo><mi>t</mi><mo>)</mo> <mo>&sdot;</mo> <msub> <mi>p</mi> <mn>2</mn> </msub> <mo>+</mo> <msup> <mi>t</mi> <mn>2</mn> </msup> <mo>&sdot;</mo> <msub> <mi>p</mi> <mn>3</mn> </msub> </mrow> </math> </p> <svg xmlns="http://www.w3.org/2000/svg"> <path fill="lightgray" stroke="black" stroke-width="2" d="M 100,200 Q 80,150 180,140 Q 190,120 190,100 Q 360,80 340,200 Z" /> <circle cx="160" cy="200" r="20" stroke="black" stroke-width="10" fill="lightgray" /> <circle cx="290" cy="200" r="20" stroke="black" stroke-width="10" fill="lightgray" /> </svg> </body> </html>

With this reference document, we want to test now the rendering result of different browsers.
Amaya Amaya is a full-featured web client developed by W3C for experimenting and validating web specifications at an early stage of their development. The current version 6.1 supports XHTML 1.0, CSS2, MathML 2.0 (presentation encoding only) and a subset of SVG 1.0. These Web technologies are tightly integrated using multi-namespace documents. And the best of all Amaya is not only a browser, it is also an editor specifically developed for math editing. With it we can comfortably create and modify formulas as well as the textual context using a consistent set of editing commands.

Learn SVG

Chapter 11 Mixing XML Languages

15

Figure 11-7. Multi-Namespace Document in Amaya

The most significant disadvantage of the current Amaya implementation is the lack of scripting support together with DOM implementation. So we get nice static documents but still have to wait for general interactive and dynamic content.
Netscape and Mozilla Netscape (version 7.0 preview release 1) and Mozilla 1.0 also have improved the support of multi-namespace documents. Both have MathML 2.0 presentation markup implemented and integrate this with XHTML very well. On the other side the SVG capabilities dont look bright. The Netscape browser still has no native SVG support and also doesnt allow to embed Adobes SvgViewer in contrast to earlier versions.

Learn SVG

Chapter 11 Mixing XML Languages

16

Figure 11-8. Multi-Namespace Document in Netscape

Figure 11-9. Multi-Namespace Document in Mozilla

Mozilla currently is also very buggy with inline SVG. So lets hope, that the situation becomes a lot better in the near future. Javascript/DOM support is usually no problem with both browsers. Though I didnt test it because of the lack of SVG.
Internet Explorer Microsofts Internet Explorer is the only browser that has neither native MathML nor SVG support. They rely here heavily on third party components using the proprietary behavior technology. So we test here the browser with Adobes SvgViewer 3.0 Design Sciences MathPlayer

Learn SVG

Chapter 11 Mixing XML Languages

17

Figure 11-10. Multi-Namespace Document in Internet Explorer

We have to modify our original document as follows.


<html xmlns:g="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML"> <head> <title>MathML and SVG Support in Internet Explorer</title> <object id="MathPlayer" classid="clsid:32f66a20-7614-11d4-bd11-00104bd3f987"> </object> <object id="AdobeSVG" classid="clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2"> </object> <?import namespace="g" implementation="#AdobeSVG"?> <?import namespace="m" implementation="#MathPlayer"?> </head> <body> . . . <m:math> <m:mrow> . . . </m:mrow> </m:math>

Learn SVG

Chapter 11 Mixing XML Languages

18

<g:svg width="600" height="400" > . . . </g:svg> </body> </html>

With these modifications we unfortunately distroyed our standard, non-proprietary document structure. As an advantage of this implementation we get a transparent DOM model which allows us to create interactive and dynamic XHTML/SVG/MathML solutions.

Chapter 12 Web Development and Fractals with SVG


"Your focus determines your reality." - Star Wars: Episode II "Do not be afraid to love everyone." - Wesley Eads (1930- )

Chapter Objectives
ASP.Net SVG Charting Web Application Using XSLT to Transform XML Data into SVG Adding Interactivity Using XHTML and ECMAScript Streaming Charts in SVG From a Live Data Source Fractal Creation in SVG

Overview
So far we have covered all the basics concepts related to SVG. In this chapter we will take SVG to another level by focusing on more advanced uses of SVG. In this chapter we will develop an ASP.Net SVG charting application in VisualStudio.Net using HTML, XML data, XSLT stylesheets, ECMAScript, ASP controls, C# and ultimately streaming SVG charts.

Part I: Publishing with SVG


In this section we will create an SVG charting portal that can be deployed on the new ASP.Net framework. We will explore the possibilities that open up when we are able to generate SVG on the server. The intent of this article is to explore the possibilities while emphasizing the many benefits that can result from taking the time to learn how to rollout our own SVG Web applications.

The User Interface


Basically, this SVG charting application displays an interactive HTML + SVG + ECMAScript GUI that allows users to choose a type of chart (line, bar, column, and streaming) and specify the chart size (width and height). One of the SVG chart types that we will develop demonstrates how to stream data from a live data source. Also, users will be able to display the source code of the XML, XSLT, and SVG output documents.

Learn SVG

Chapter 11 Web Development

Figure 12-1.

User Interface for our Web Application

The SVG Charting Application user interface is comprised of XHTML, SVG and ECMAScript but it is actually created as a result of a host of languages including XML, XSLT, ASP.Net, C#, HTML, ECMAScript, and ultimately SVG.

ASP.Net Application Development


I used Visual Studio.Net to create this application but all that is needed is the free .Net Framework SDK running a basic Web server environment. We will use C# in our Web application but will not discuss C# language in much depth in this book. Unlike ECMAScript, C# is a true object-oriented language that supports classes, inheritance, polymorphism, etc. As you will see, C# is much easier to wield than its forerunner, C++.

The code
This is the ASP.Net and XHTML code that is used to generate the user interface of our SVG Charting Application.
<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="SVGChart08.SVGGenerator" %> <%@ Import Namespace="SVGChart08" %> <HTML> <HEAD> <link href='<%= Request.ApplicationPath + "/style/Main.css" %>' type=text/css rel=stylesheet> </HEAD> <body bottomMargin="0" leftMargin="0" topMargin="0" rightMargin="0" marginwidth="0" marginheight="0"> <form id="Form1" runat="server"> <span id="svgFileName" runat="server" style="DISPLAY:none">Start.svg</span>

Learn SVG

Chapter 11 Web Development

<div align="center"> <table cellSpacing="0" cellPadding="4" width="100%" border="0"> <tr vAlign="top"> <td align="middle" width="*"> <table cellSpacing="0" cellPadding="0" width="700"> <tr> <td class="Head" align="left">SVG Charting Application</td> <td class="Head" align="right"> <iframe marginWidth="0" marginHeight="0" src="svg/svgtest.svg" frameBorder="0" width="100" height="100"> <embed src="svg/svgtest.svg" name="SVGEmbed" width="100px" height="100px" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" /> </iframe></td> </tr> <tr> <td colSpan="2"> <hr noShade SIZE="1"> </td> </tr> </table> <table cellSpacing="0" cellPadding="0" width="700"> <tr vAlign="top"> <td class="SubHead" align="right">Type of Chart: &nbsp;</td> <td align="left"> <asp:dropdownlist id="XslTransformSrc" runat="server" width="120" AutoPostBack="True"> <asp:listitem>Start</asp:listitem> <asp:listitem>Line</asp:listitem> <asp:listitem>Bar</asp:listitem> <asp:listitem>Column</asp:listitem> <asp:listitem>Streaming</asp:listitem> </asp:dropdownlist> &nbsp; <asp:button class="CommandButton" id="generateButton" runat="server" CausesValidation="False" Text="Go"></asp:button>&nbsp;&nbsp; </td> <td class="SubHead" align="right" width="100">Width: &nbsp;</td> <td align="left" width="50"><asp:textbox id="Width" width="50" Runat="server">500</asp:textbox></td> <td class="SubHead" align="right">Height: &nbsp;</td> <td align="left"><asp:textbox id="Height" width="50" Runat="server">300</asp:textbox></td> <td class="SubHead" align="right">Year: &nbsp;</td> <td align="left" width="50"> <asp:dropdownlist id="DropdownYear" runat="server" width="120" AutoPostBack="True"> <asp:listitem>2002</asp:listitem> <asp:listitem>2001</asp:listitem> <asp:listitem>2000</asp:listitem> </asp:dropdownlist></td> </tr> <tr vAlign="top"> <td colSpan="8">&nbsp; </td> </tr> <tr vAlign="top"> <td class="SiteLink" align="middle" colSpan="8"> <asp:button class="CommandButton" id="viewXml" runat="server" CausesValidation="False" Text="View XML"></asp:button>&nbsp;&nbsp;

Learn SVG

Chapter 11 Web Development

<asp:button class="CommandButton" id="viewXslt" runat="server" CausesValidation="False" Text="View XSLT"></asp:button>&nbsp;&nbsp; <asp:button class="CommandButton" id="viewSvgSource" runat="server" CausesValidation="False" Text="View SVG"></asp:button></td> </tr> </table> </td> </tr> </table> <p> <span id="embedSvg" runat="server"> <iframe src="svg/Start.svg" frameBorder="1" width="500" height="300"> <embed src="svg/Start.svg" name="SVGChart" width="500px" height="300px" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" /> </iframe> </span> </p> <table cellSpacing="0" cellPadding="4" width="700" border="0"> <tr vAlign="top"> <td align="left" width="*"><asp:textbox id="output1" runat="server" Width="526px"></asp:textbox><br> <textarea id="output2" rows="30" cols="80" runat="server" align="left"></textarea> <P></P> </td> </tr> </table> </div> </form> </SPAN> </body> </HTML>

Let's quickly go over some of the key parts of our ASPX file. Our ASPX file 'default.aspx, references the SVG using the <EMBED> tag. Currently, due to the fact that neither Internet Explorer nor Netscape natively support SVG, embedding the SVG is the preferred cross-browser approach to referencing SVG in HTML.
<span id="embedSvg" runat="server"> <iframe src="svg/Start.svg" frameBorder="1" width="500" height="300"> <embed src="svg/Start.svg" name="SVGChart" width="500px" height="300px" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" /> </iframe> </span>

By enclosing our embed tag in an iframe tag we can prevent Mozilla from crashing in some scenarios. On the server-side when we want to update the width, height and src our C# code actually rewrites this code with the updated values. Finally, keep in mind that some of this code runs on the server and processes all of the <asp:xxx></asp> code and also any tags that contains the attribute value pair of runat=server before sending the XHTML and ECMAScript back to the client.

SVG Chart Types


There are infinite possible chart types that you can customize to your hearts desire. This is a basic UI for a line chart.

Learn SVG

Chapter 11 Web Development

Figure 12-2.

SVG Chart Template

This is the SVG data that is used to generate the chart:


<svg width="500" height="300" viewBox="0 0 110 90" xml:space="preserve"> <g id="Chart" font-size="5" transform="translate( 10, 70 ) rotate( -90 )"> <defs> <pattern id="gridPattern" width="10" height="8.33" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="10" height="8.33" style="fill:none;stroke:rgb(128,128,128);stroke-width:.1" /> </pattern> </defs> <text x="55" y="15" style="fill:black" writing-mode="tb"> 2002 Pond <tspan fill="darkorange">Level</tspan> and <tspan fill="blue">Precip</tspan> </text> <text <text <text <text <text x="50" x="40" x="30" x="20" x="10" y="-10" y="-10" y="-10" y="-10" y="-10" writing-mode="tb">50</text> writing-mode="tb">40</text> writing-mode="tb">30</text> writing-mode="tb">20</text> writing-mode="tb">10</text>

<rect x="0" y="0" width="50" height="100" fill="url(#gridPattern)" /> <line x1="0" y1="0" x2="0" y2="100" style="stroke:black;" /> <line x1="0" y1="0" x2="50" y2="0" style="stroke:black;" /> <g id="ChartData"> </g> </g> </svg>

As you can see there is no data and there are just a few labels. We will be adding labels and chart data from our XML data source as detailed below.

The Data Source


For my data source I recorded monthly rainfall in my area and correlated it with my ponds water level readings. I found the monthly rainfall records for the nearest weather station, and together with the water level records, assembled an XML file containing this data.
<?xml version="1.0" encoding="UTF-8" ?> <!-- ====================================================================== --> <!-- Pond Wobegon Water Level and Precipitation Data -->

Learn SVG

Chapter 11 Web Development

<!-- ====================================================================== --> <pond id="Wobegon"> <title> Pond Level and Precip</title> <year id="2002"> <month id="January"> <level>31.9</level> <precip>14.3</precip> </month> <month id="February"> <level>27.6</level> <precip>11.8</precip> </month> <month id="March"> <level>34.7</level> <precip>19.5</precip> </month> and so on </year> <year id="2003"> <month id="January"> <level>35.9</level> <precip>4.3</precip> </month> and so on </year> </pond>

Though the data could be drawn from any source such as a database, flat file, or any other data structure the SVG Charting portal data comes from XML documents. XML provides several key advantages for our purposes including the ability to transform the data with XSLT into SVG! To create and manage the XML data I used both a basic text editor called Ultra-Edit (www.ultraedit.com) and an XML/XSLT IDE called Xselorator (www.MarrowSoft.com). I then needed a simple SVG chart UI for displaying this information (below you can see the chart template). You may be struck by how exceedingly simple this is - the text elements are positioned by pixel coordinates, and the last part of the SVG file defines a transformed group that includes the x and y-axis lines, hash marks, etc. and when the ActiveX component is done with it, will also contain the chart data. The XML data is then transformed using XSLT documents to produce a variety of SVG chart types.

The XSLT Stylesheet


The second step involves designing the XSLT stylesheet that will be used to transform the XML data into the UI of our SVG chart. Note that every element of the chart UI including the chart size, labels, grid and axis lines can be manipulated using XSLT. However, for the purposes of this example we will merely be adding two paths to plot out the monthly pond level data and monthly precipitation data. This is the XSLT stylesheet for the line chart type.
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- ====================================================================== --> <!-- Generate a line graph --> <!-- ====================================================================== --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Learn SVG

Chapter 11 Web Development

<xsl:output method="xml" indent="yes" version="1.0" encoding="ISO-8859-1" /> <xsl:param name="width" select="'500'"/> <xsl:param name="height" select="'500'"/> <xsl:param name="year" select="'2002'"/> <xsl:template match="//pond"> <svg width="{$width}" height="{$height}" viewBox="0 0 110 90" xml:space="preserve" onload="Init(evt); InitContextMenu();"> <script> <xsl:comment> <![CDATA[ var SVGDoc=null; var L1=null; function Init( evt ) { SVGDoc = evt.getTarget().getOwnerDocument(); } ]]> </xsl:comment> </script> <!-- chart --> <g id="Chart" font-size="5" transform="translate( 10, 70 ) rotate( -90 )"> <defs> <pattern id="gridPattern" width="10" height="8.33" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="10" height="8.33" style="fill:none;stroke:rgb(128,128,128);stroke-width:.1"/> </pattern> </defs> <!-- labels --> <text x="55" y="15" style="fill:black" writing-mode="tb"><xsl:value-of select="$year"/> <!--<xsl:apply-templates select="title"/>-->Pond <tspan fill="darkorange">Level</tspan> and <tspan fill="blue">Precip</tspan></text> <xsl:call-template name="monthLabels"/> <text x="50" y="-10" writing-mode="tb">50</text> <text x="40" y="-10" writing-mode="tb">40</text> <text x="30" y="-10" writing-mode="tb">30</text> <text x="20" y="-10" writing-mode="tb">20</text> <text x="10" y="-10" writing-mode="tb">10</text> <rect x="0" y="0" width="50" height="100" fill="url(#gridPattern)"/> <line x1="0" y1="0" x2="0" y2="100" style="stroke:black;"/> <line x1="0" y1="0" x2="50" y2="0" style="stroke:black;"/> <g id="grid"> <path id="pondLevelData" stroke="darkorange" fill="none"><xsl:attribute name="d"><xsl:text>M </xsl:text> <xsl:call-template name="monthlyLevel"/></xsl:attribute></path> <path id="pondPrecipData" stroke="blue" fill="none"><xsl:attribute name="d"><xsl:text>M </xsl:text> <xsl:call-template name="monthlyPrecip"/></xsl:attribute></path> </g>

Learn SVG
</g> </svg> </xsl:template>

Chapter 11 Web Development

<xsl:template match="title"> <xsl:apply-templates/> </xsl:template> <xsl:template name="monthLabels"> <xsl:for-each select="//year[@id=$year]//month"> <text x="-2" writing-mode="rl"><xsl:attribute name="y"><xsl:valueof select = "position() * 8.33" /></xsl:attribute><xsl:value-of select="substring( @id, 1, 3 )"/></text> </xsl:for-each> </xsl:template> <xsl:template name="monthlyLevel"> <xsl:for-each select="//year[@id=$year]//month//level[.!='']"> <xsl:choose > <xsl:when test = "position()=1" > <xsl:value-of select="."/> <xsl:text> 0</xsl:text> </xsl:when> <xsl:when test = "position()!=1" > <xsl:text> L </xsl:text> <xsl:value-of select="."/> <xsl:text> </xsl:text> <xsl:value-of select = "position() * 8.33" /> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:template> <xsl:template name="monthlyPrecip"> <xsl:for-each select="//year[@id=$year]//month//precip[.!='']"> <xsl:choose > <xsl:when test = "position()=1" > <xsl:value-of select="."/> <xsl:text> 0</xsl:text> </xsl:when> <xsl:when test = "position()!=1" > <xsl:text> L </xsl:text> <xsl:value-of select="."/> <xsl:text> </xsl:text> <xsl:value-of select = "position() * 8.33" /> </xsl:when> <xsl:when test = "lang('de')" >Germany</xsl:when> </xsl:choose> </xsl:for-each> </xsl:template> <xsl:template match = "*" > <xsl:value-of select = "*" /> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet>

Learn SVG

Chapter 11 Web Development

I have highlighted the key XSLT elements and attributes. Notice that we can call specific XSLT templates such as monthLabels like this.
<xsl:call-template name="monthLabels"/>

This will apply this template.


<xsl:template name="monthLabels"> <xsl:for-each select="//year[@id=$year]//month"> <text x="-2" writing-mode="rl"><xsl:attribute name="y"><xsl:valueof select = "position() * 8.33" /></xsl:attribute><xsl:value-of select="substring( @id, 1, 3 )"/></text> </xsl:for-each> </xsl:template>

The next important step is selecting the appropriate data from our XML document using XPath statements. XPath syntax and is used to quickly and easily navigate XML documents during XSLT processing. The XPath statement selects each of the values that are contained within the precip elements.
"//year[@id=$year]//month"

The result is twelve new text elements that contain the first three letters of the text found at this location in the XML document.
<text <text <text <text <text <text <text <text <text <text <text <text x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" x="-2" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" writing-mode="rl" y="8.33">Jan</text> y="16.66">Feb</text> y="24.990000000000002">Mar</text> y="33.32">Apr</text> y="41.65">May</text> y="49.980000000000004">Jun</text> y="58.31">Jul</text> y="66.64">Aug</text> y="74.97">Sep</text> y="83.3">Oct</text> y="91.63">Nov</text> y="99.960000000000008">Dec</text>

XPath is powerful and once mastered some might even call it fun.

Server-side Code
Server-side data binding is becoming more and more popular for companies who need to make large data sources available on their Web site. An SVG document can contain large sets of data but seeing as SVG is geared for the Web environment the 'weight' of SVG images often needs to be considered. In most cases Web users only need subsets of a data source and this is where it becomes more effective and intelligent to generate SVG on the server-side. Users need to be able to interact with Web applications in visually intuitive ways. .Net is an extremely useful way of generating dynamic SVG images. A key benefit of using server-side .Net is that it frees us from browser dependencies and opens up any number of additional options. There are a plethora of potential uses for using .Net to generate SVG on the server-side binding to a data source on the server-side to create maps, graphs, charts, interactive navigation, and many other interesting types of data intensive graphic applications will soon be mainstream.

The C# Code
The first line of the ASPX document shown in figure 12-01 contains an attribute that references some backend code like this.
<%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="SVGChart08.SVGGenerator" %> <%@ Import Namespace="SVGChart08" %>

Learn SVG

Chapter 11 Web Development

10

The next step is assembling the backend code. First of let's look at the Default.aspx.cs class file. This is the entire content of the document.
using using using using using using using using using using using using using System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls; System.IO; System.Xml; System.Xml.Xsl; System.Xml.XPath;

namespace SVGChart08 { #region SVGGenerator public class SVGGenerator : System.Web.UI.Page { protected System.Web.UI.WebControls.Button generateButton; protected System.Web.UI.WebControls.DropDownList XslTransformSrc; protected System.Web.UI.WebControls.DropDownList DropdownYear; protected System.Web.UI.WebControls.TextBox Width; protected System.Web.UI.WebControls.TextBox Height; protected System.Web.UI.WebControls.Button viewXml; protected System.Web.UI.WebControls.Button viewXslt; protected System.Web.UI.WebControls.Button viewSvgSource; protected System.Web.UI.WebControls.TextBox output1; protected System.Web.UI.HtmlControls.HtmlTextArea output2; protected System.Web.UI.HtmlControls.HtmlGenericControl embedSvg; protected System.Web.UI.HtmlControls.HtmlGenericControl svgFileName; #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// /// /// /// <summary> Required method for Designer support - do not modify the contents of this method with the code editor. </summary>

private void InitializeComponent() { this.XslTransformSrc.SelectedIndexChanged += new System.EventHandler(this.XslTransformSrc_SelectedIndexChanged); this.DropdownYear.SelectedIndexChanged += new System.EventHandler(this.DropdownYear_SelectedIndexChanged);

Learn SVG

Chapter 11 Web Development

11

this.generateButton.Click += new System.EventHandler(this.generateButton_Click); this.viewXml.Click += new System.EventHandler(this.viewXml_Click); this.viewXslt.Click += new System.EventHandler(this.viewXslt_Click); this.viewSvgSource.Click += new System.EventHandler(this.viewSvgSource_Click); this.Load += new System.EventHandler(this.Page_Load); } #endregion private void Page_Init(object sender, EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); } public SVGGenerator() { // // Initializes all event handlers // Page.Init += new System.EventHandler(Page_Init); } //**************************************************************** // // The Page_Load event is currently not being used. // //**************************************************************** private void Page_Load(object sender, System.EventArgs e) { } //**************************************************************** // // The XslTransformSrc_SelectedIndexChanged and GenerateBtn_Click // event handlers on this Page are used to generate a new SVG // chart based on user settings. // //**************************************************************** private void XslTransformSrc_SelectedIndexChanged(object sender, System.EventArgs e) { String[] args1 = { Server.MapPath( "data/wobegon.xml" ), Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; if ( XslTransformSrc.SelectedItem.Value != "Start" ) { GenerateSVG(args1); } else { //Rewrite the 'iframe' and 'embed' tags. embedSvg.InnerHtml = "<iframe src='svg/Start.svg' frameBorder='0' width='500' height='300'>" + "<embed src='svg/Start.svg' name='SVGChart' width='500px' height='300px' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' />"

Learn SVG

Chapter 11 Web Development


+ "</iframe>";

12

} } private void DropdownYear_SelectedIndexChanged(object sender, System.EventArgs e) { String[] args1 = { Server.MapPath( "data/wobegon.xml" ), Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; if ( XslTransformSrc.SelectedItem.Value != "Start" ) { GenerateSVG(args1); } } void generateButton_Click(object sender, System.EventArgs e) { String[] args1 = { Server.MapPath( "data/wobegon.xml" ), Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; if ( XslTransformSrc.SelectedItem.Value != "Start" ) { GenerateSVG(args1); } else { //Rewrite the 'iframe' and 'embed' tags. embedSvg.InnerHtml = "<iframe src='svg/Start.svg' frameBorder='0' width='500' height='300'>" + "<embed src='svg/Start.svg' name='SVGChart' width='500px' height='300px' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' />" + "</iframe>"; } } //**************************************************************** // // The viewXml, viewXslt and viewSvgSource event handlers on this // Page read and output the source of the XML, XSLT and SVG files. // //**************************************************************** private void viewXml_Click(object sender, System.EventArgs e) { output1.Text = "XML source document (wobegon.xml):"; StringWriter writer = new StringWriter(); Console.SetOut(writer); String[] args1 = { Server.MapPath( "data/wobegon.xml" ) }; ReadXML(args1); output2.InnerHtml = writer.ToString(); Console.WriteLine(); } private void viewXslt_Click(object sender, System.EventArgs e) {

Learn SVG

Chapter 11 Web Development

13

output1.Text = "XSLT source document (" + XslTransformSrc.SelectedItem.Value + ".xslt):"; StringWriter writer = new StringWriter(); Console.SetOut(writer); String[] args1 = { Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; ReadXML(args1); output2.InnerHtml = writer.ToString(); Console.WriteLine(); } private void viewSvgSource_Click(object sender, System.EventArgs e) { output1.Text = "XSLT transformation output source (SVG!):"; StringWriter writer = new StringWriter(); Console.SetOut(writer); String[] args1 = { Server.MapPath( "data/wobegon.xml" ), Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; ReadTransformation(args1); // ReadTransformation() currently does not use 'args1' parameter. output2.InnerHtml = writer.ToString(); Console.WriteLine(); } //**************************************************************** // // The GenerateSVG function is used to generate a new SVG chart // based on the users settings. // //**************************************************************** public void GenerateSVG(String[] args) { //Generate random integer for new Svg chart name. //Create the randomGenerator. Random randomGenerator = new Random(DateTime.Now.Millisecond); //Generate random number that's between 0 and 1 trillion ;D long randomNum = randomGenerator.Next(0, 1000000000); //Write the new SVG file name so that we can view the new SVG source. svgFileName.InnerText = "chart" + randomNum + ".svg"; //Rewrite the 'iframe' and 'embed' tags. embedSvg.InnerHtml = "<iframe src='svg/chart" + randomNum + ".svg' frameBorder='0' width='" + Width.Text + "' height='" + Height.Text + "'>" + "<embed src='svg/chart" + randomNum + ".svg' name='SVGChart' width='" + Width.Text + "px' height='" + Height.Text + "px' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' />" + "</iframe>"; //Create and load the XmlTextWriter. XmlTextWriter writer = new XmlTextWriter( Server.MapPath( "svg/chart" + randomNum + ".svg" ), null ); //Create and load the XPathDocument and XslTransform. XPathDocument myXPathDocument = new XPathDocument ( args[0] ); XslTransform myXslTransform = new XslTransform(); myXslTransform.Load( args[1] ); //Create the XsltArgumentList.

Learn SVG

Chapter 11 Web Development

14

XsltArgumentList xslArg = new XsltArgumentList(); //Create a parameter which represents the current date and time. xslArg.AddParam( "width", "", Width.Text ); xslArg.AddParam( "height", "", Height.Text ); xslArg.AddParam( "year", "", DropdownYear.SelectedItem.Value ); //Transform the file. myXslTransform.Transform( myXPathDocument, xslArg, writer ); writer.Close(); //Clear all the document source content. output1.Text = ""; output2.InnerHtml = ""; } //**************************************************************** // // The GenerateSVG function is used to generate a new SVG chart // based on the users settings. // //**************************************************************** public void ReadXML(String[] args) { StreamReader stream = null; try { stream = new StreamReader (args[0]); Console.Write(stream.ReadToEnd()); } catch (Exception e) { Console.WriteLine ("Exception: {0}", e.ToString()); finally { if (stream != null) stream.Close(); } } //**************************************************************** // // The GenerateSVG function is used to generate a new SVG chart // based on the users settings. // //**************************************************************** public void ReadTransformation(String[] args) { StreamReader stream = null; try { ///Read svg source. File name comes from 'svgFileName'. stream = new StreamReader ( Server.MapPath( "svg/" + svgFileName.InnerText ) ); Console.Write(stream.ReadToEnd()); } catch (Exception e) { Console.WriteLine ("Exception: {0}", e.ToString()); finally { if (stream != null) stream.Close();

Learn SVG
} } #endregion }

Chapter 11 Web Development

15

First let's step through some of the key aspects of our backend code. To begin we declare references other global variables.
using using using using using using System.Web.UI.WebControls; System.Web.UI.HtmlControls; System.IO; System.Xml; System.Xml.Xsl; System.Xml.XPath;

The WebControls reference is needed to register our ASP controls like this.
protected System.Web.UI.WebControls.Button generateButton; protected System.Web.UI.WebControls.DropDownList XslTransformSrc; protected System.Web.UI.WebControls.DropDownList DropdownYear;

The IO reference is needed for reading and writing files. The Xsl and XPath references are needed for the XSLT transformation process as we will soon describe. The MSDN Library contains extensive documentation on using the MSXML parser to do XML DOM manipulations on XML documents. The last step is simply using the MSXML parser in our C# application to perform the actual transformation and return the output to the client. The XML->SVG XSLT transformation process can be initiated through one of three different event handler functions.
void generateButton_Click(object sender, System.EventArgs e) { String[] args = { Server.MapPath( "data/wobegon.xml" ), Server.MapPath( "style/" + XslTransformSrc.SelectedItem.Value + ".xslt" ) }; if ( XslTransformSrc.SelectedItem.Value != "Start" ) { GenerateSVG(args); } } private void XslTransformSrc_SelectedIndexChanged(object sender, System.EventArgs e) { function code here } private void DropdownYear_SelectedIndexChanged(object sender, System.EventArgs e) { function code here }

The generateButton_Click() event fires as a result of clicking on the Chart Type Go button. The XslTransformSrc_SelectedIndexChanged() event fires when the user selects a chart type from the dropdown.

Learn SVG

Chapter 11 Web Development

16

The last event is the DropdownYear_SelectedIndexChanged() event that fires when the user selects to view the SVG chart containing the XML data from a different year.

Server-side Data Binding and XSLT Transformation


Each of these event handler functions call the GenerateSVG() function if the chart type dropdown value is not equal to Start. It is the GenerateSVG() function that actually performs the transformation by coordinating the loading, manipulating, and saving of our XML and XSLT documents as SVG documents. This is how the process works. When the user selects a different chart type in the chart type dropdown the name of the chart type is passed as the second parameter (argument) to the GenerateSVG() function. A key issue here is that I have designed the application so that the name of each chart type corresponds to the name of a stylesheet in the /style directory of the SVG Charting project.
public void GenerateSVG(String[] args) { //Generate random integer for new Svg chart name. //Create the randomGenerator. Random randomGenerator = new Random(DateTime.Now.Millisecond); //Generate random number that's between 0 and 1 trillion ;D long randomNum = randomGenerator.Next(0, 1000000000); //Create and load the XmlTextWriter. XmlTextWriter writer = new XmlTextWriter( Server.MapPath( "svg/chart" + randomNum + ".svg" ), null ); //Create and load the XPathDocument and XslTransform. XPathDocument myXPathDocument = new XPathDocument ( args[0] ); XslTransform myXslTransform = new XslTransform(); myXslTransform.Load( args[1] ); //Create the XsltArgumentList. XsltArgumentList xslArg = new XsltArgumentList(); //Create a parameter which represents the current date and time. xslArg.AddParam( "width", "", Width.Text ); xslArg.AddParam( "height", "", Height.Text ); xslArg.AddParam( "year", "", DropdownYear.SelectedItem.Value ); //Transform the file. myXslTransform.Transform( myXPathDocument, xslArg, writer ); writer.Close(); }

The function argument array is numbered starting from 0 so the second argument is actually referenced like this, args[1]. Therefore the XML data is loaded into the myXPathDocument like this.
XPathDocument myXPathDocument = new XPathDocument ( args[0] );

Still with us? Just hang in there a little longer and you're sure to get the hang of it. The stylesheet is then loaded into the XslTransform() object that is called myXslTransform.
XslTransform myXslTransform = new XslTransform();

Learn SVG

Chapter 11 Web Development

17

myXslTransform.Load( args[1] );

Also notice in each of the XSLT stylesheets there are three parameters at the top of each document - width, height, and year.
<xsl:param name="width" select="'500'"/> <xsl:param name="height" select="'500'"/> <xsl:param name="year" select="'2002'"/>

Remember that Width, Height, and Year are input options for the user to specify on the SVG Charting Application web page. These parameter values in the XSLT document are updated the C# code. The C# code actually reads the XSLT documents DOM and finds the width, height, and year parameters and then updates their values according to the web users input. This is the C# code that performs this specific task.
//Create the XsltArgumentList. XsltArgumentList xslArg = new XsltArgumentList(); //Update the XSLT stylesheet parameters. xslArg.AddParam( "width", "", Width.Text ); xslArg.AddParam( "height", "", Height.Text ); xslArg.AddParam( "year", "", DropdownYear.SelectedItem.Value ); //Transform the file. myXslTransform.Transform( myXPathDocument, xslArg, writer );

Saving SVG the Chart to a File


After applying the stylesheet the last issue involves saving the XML document to the writer object. This is the relevant code for this process.
//Generate random integer for new Svg chart name. //Create the randomGenerator. Random randomGenerator = new Random(DateTime.Now.Millisecond); //Generate random number that's between 0 and 1 trillion ;D long randomNum = randomGenerator.Next(0, 1000000000); //Create and load the XmlTextWriter. XmlTextWriter writer = new XmlTextWriter( Server.MapPath( "svg/chart" + randomNum + ".svg" ), null ); //Transform the file. myXslTransform.Transform( myXPathDocument, xslArg, writer );

If the template DOM document is still parseable, then the new file is created with a unique file name in the svg directory.

Granting Write Permissions


Next, you will need to set the output directory so the Web server has write access. If you are using Windows 2000, it will look something like this:

Learn SVG

Chapter 11 Web Development

18

Figure 12-3.

Web Server Settings

When you choose the chart type called line for the year 2002 for example the XSLT transformation ends up adding two paths to our SVG chart. This is an example of the resulting SVG image.

Figure 12-4. This is the pond data path that was actually added.

Line Chart in SVG

<svg width="500" height="300" viewBox="0 0 110 90" xml:space="preserve"> SVG chart <g id="ChartData"> <path id="pondLevelData" stroke="darkorange" fill="none" d=" M 29.2 0 L 34.7

16.66 L 31.9 24.990000000000002 L 34.7 33.32 L 32.8 41.65 L 27.6 49.980000000000004 L 34.7 58.31 L 31.9 66.64 L 42.2 74.97"></path> 22.9 0 L 31.5 16.66 L 14.3 24.990000000000002 L 13.5 33.32 L 23.5 41.65 L 11.8 49.980000000000004 L 36.5 58.31 L 14.3 66.64 L 38.9 74.97"></path>
</g> </svg> <path id="pondPrecipData" stroke="blue" fill="none" d=" M

These path elements contain our line data that represents the monthly Pond Wobegon water level and area precipitation. As you can see its all coming together now isnt it! Now we have covered the entire spectrum of the XML -> SVG transformation process so lets quickly move on to something a bit more interesting.

Learn SVG

Chapter 11 Web Development

19

Streaming Live Chart Data


The key to creating streaming charts is figuring out how to dynamically insert new data points from a real-time data source. The only way to do this is by using ECMAScript to manipulate specific shape objects within the SVG DOM. Prior to the creation of the SVG specification, raster image effects needed to be created on the server-side. The advent of SVG gives us the ability to manipulate a wide-range of effects natively on client-side. As we learned earlier in this book ECMAScript could access the SVG DOM from outside of the SVG image as in the case of an HTML page or from inside of the SVG image. First we need to create the streaming line graphs UI.

Figure 12-5.

Template for Streaming Data

<svg width="500" height="300" viewBox="0 0 90 130" xml:space="preserve"> <g id="Chart" font-size="5" transform="translate( 10, 110 ) rotate( -90 )"> <defs> <pattern id="gridPattern" width="10" height="10" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="10" height="10" style="fill:none;stroke:rgb(128,128,128);stroke-width:.1" /> </pattern> </defs> <text x="105" y="15" writing-mode="tb" font-size="7"> <tspan fill="darkred">Streaming Line Graph</tspan> </text> <text x="-4" writing-mode="tb" y="8">1</text> <text x="-4" writing-mode="tb" y="18">2</text> <text x="-4" writing-mode="tb" y="28">3</text> <text x="-4" writing-mode="tb" y="38">4</text> <text x="-4" writing-mode="tb" y="48">5</text> <text x="-4" writing-mode="tb" y="58">6</text> <text x="-4" writing-mode="tb" y="68">7</text> <text x="-4" writing-mode="tb" y="78">8</text> <text x="-4" writing-mode="tb" y="88">9</text> <text x="-4" writing-mode="tb" y="98">10</text> <text x="100" y="-10" writing-mode="tb">100</text> <text x="90" y="-10" writing-mode="tb">90</text> <text x="80" y="-10" writing-mode="tb">80</text> <text x="70" y="-10" writing-mode="tb">70</text> <text x="60" y="-10" writing-mode="tb">60</text>

Learn SVG
<text <text <text <text <text x="50" x="40" x="30" x="20" x="10"

Chapter 11 Web Development


y="-10" y="-10" y="-10" y="-10" y="-10" writing-mode="tb">50</text> writing-mode="tb">40</text> writing-mode="tb">30</text> writing-mode="tb">20</text> writing-mode="tb">10</text>

20

<rect x="0" y="0" width="100" height="100" fill="url(#gridPattern)" /> <line x1="0" y1="0" x2="0" y2="100" style="stroke:black;" /> <line x1="0" y1="0" x2="100" y2="0" style="stroke:black;" /> <g id="grid"></g> <text id="CurrentTime" x="50" y="10" style="fill:black;font-size:20;opacity:0.1" writing-mode="tb">time</text> </g> </svg>

Next we need to add the script to get the data and update the image.
<svg width="500" height="300" viewBox="0 0 90 130" xml:space="preserve" onload="Init(evt); ">

<script> <!-var SVGDoc=null; var count=0; function AddData(x,y) { var Path=SVGDoc.getElementById('pathData'); Path.setAttribute( 'd', Path.getAttribute('d') + ' L ' + x + ' ' + y ); return this } function updateData( obj ) { AddData( ++count, +obj.content ) if ( count < 100 ) setTimeout( 'getData()', 1000 ); } function getData() { getURL( '../randomData.aspx', updateData ) } function Init( evt ) { SVGDoc = evt.getTarget().getOwnerDocument(); var iW = SVGDoc.documentElement.getAttribute( 'width' ); var iH = SVGDoc.documentElement.getAttribute( 'height' ); setTimeout( 'getData()', 1000 ) } --> </script> SVG chart content here </svg> The key function to this whole process is called getURL() that I have placed inside of the getData() function.
getURL( '../randomData.aspx', updateData )

The getURL() is only function allows us to make updates to our SVG data from a source that is outside of our document without having to reload our document. There is no limit on the size of the data source that we transfer using getURL(). This is the syntax for the getURL function.
getURL( url, callback)

Learn SVG

Chapter 11 Web Development

21

The url parameter contains the location source where the data will come from. This source must be on the same server as the SVG documents ECMAScript. The callback parameter is a function that will process the returned data that is returned by the url parameter. The .aspx page that we call with the getURL() function is called randomData.aspx and is located in the root directory of our web application. Here is the code from that page.
<scrispt language="C#" runat="server"> void Page_Load(Object Src, EventArgs E) { //Create the randomGenerator. Random randomGenerator = new Random(DateTime.Now.Millisecond); //Generate random number. float randomNum = randomGenerator.Next(0, 11); //Return random number to client. Response.Write ( randomNum * 10 ); } </script>

When this page is called it merely returns a random number from 0 to 100 and writes the result back to the client. We then take this result and send it to the AddData() function for processing. The second most important lines of code in the streaming data process is found in the AddData() function. var Path=SVGDoc.getElementById('pathData'); Path.setAttribute( 'd', Path.getAttribute('d')

+ ' L ' + x + ' ' + y );


This code updates the SVG DOM with the new data. First we accesses the SVG DOM and get a reference to the element node that has an id that is equal to 'pathData. Then in the next line we actually append a new L command and a new x and y point. This draws a line from the end of the current path to a new point on the chart! This is an example screenshot of the dynamic streaming SVG line chart.

Figure 12-6.

Streaming Data from a live Data Source

Learn SVG

Chapter 11 Web Development

22

So now most of the magic has been revealed. Note that for this simple example, it would be straightforward and quite reasonable to insert random data into the SVG chart using just ECMAScript, without using any backend code! However, use of the getURL() method to grab data from the server opens doors to a much richer set of tools for processing and analysis and allows access to a much wider bevy of data sources, not to mention the potential performance gains, especially for large datasets. The advantage of using internal ECMAScript to handle the update of streaming data is that it will work from within the Adobe SVG Viewer, Batik 1.5b2, and even in Mozilla SVG. The getURL() is a non-standard extension that is only supported by the Adobe SVG Viewer however, there are other ways to obtain live data using XMLHTTP that will work in other SVG Viewers.

Compatibility With Browsers


The SVG Charting Portal will work in IE 5.x, Netscape 4.x, and Netscape 6.2 or higher and Mozilla 1.0 or higher. Also, most of the charts that are produced can be viewed in Batik.

Suggested Enhancements
There are a number of improvements that would make this application more robust including: error logging, improved function structure, and additional XSLT stylesheets for more chart types, recording and displaying different types of pond data, adding a zoom and pan navigation console, and adding a chart legend.

Publishing SVG Web Sites


Prior to going live with any Web site there are a number of things to consider. For one, file optimization, preloaders and adding script to auto-install the SVG Viewer can significantly enhance the user experience and promote stickiness which is vital to the success of most Web sites. For instance, decreased download and page load times as well as smoothing interactions will add a great deal the user experience. Another consideration might be securing SVG content as much as possible. Each of these topics is briefly covered in this section.

File Optimization
There are several ways to minimize or optimize SVG files and one of the most important of these is by means of compression. HTTP/1.1 allows for compressed data to be passed from server to client and the results of using the GZIP file format for compression is quite significant. Below is a table as taken directly from the SVG specification: Uncompressed With gzip Compression SVG compression ratio 12,912 12,164 11,613 18,689 13,024 2,463 2,553 2,617 4,077 2,041 81% 79% 77% 78% 84%

Other considerations are efficient use of CSS styling as covered in Chapter 4 as well as optimizing vector graphic path data. Illustrator 9/10 is able to simplify graphics so that they do not contain an unnecessary number of points thereby significantly reducing path data and consequent SVG file size. For more information on ways to optimize SVG see, http://www.w3.org/TR/SVG/minimize.html and http://www.adobe.com/svg/workflow/optimizing.html .

Learn SVG

Chapter 11 Web Development

23

Securing SVG Content in a Browser


Currently there is no means by which SVG can be totally securely rendered even through means of client-side ActiveX or Java. This is due in part to the way the SVG Viewer plugin handles SVG but most due to the fact that copying any form of digital content is becoming increasingly easy due to widespread use of powerful graphic design environments as well as content ripping utilities and applications.

Disabling View Source in the Adobe SVG Viewer


View Source can be disabled in Version 3 of the Adobe SVG Viewer in two ways. You could add the following tag, which is an XML processing instruction, to the top of your SVG graphic above the <svg> element: <?AdobeSVGViewer save="disable"?> Alternatively, using script you could locate the contextMenu in the XML DOM and either remove it or set the enabled property value equal to no. Both of these methods would help to discourage users from viewing the SVG source but by no means do they suffice to fully secure SVG data. This has caused heated debates about copyright-related issues due to the fact that it is so easy to copy and reuse logos, animations, and even whole SVG Web sites. The result of such debates ends up at the same place that other digital asset debates end and that is with the legal copyright infringement laws. Taking these measures can help protect your code from a legal standpoint. Copyright laws have been set forth and will continue to change to protect digital assets including SVG. Consider just adding a very clear comment at the top of each of your SVG documents that explains your copyright and your copying policy.

Summary
SVG is a hot topic that can only get hotter, and server-side SVG image generation gives us a tremendous amount of possibilities. We created an XHTML + SVG + ECMAScript powered .Net application that transforms an XML data source into SVG charts using XSLT and C#. This article serves as a great stepping-off point into SVG, XHTML and the .Net Framework as we continue into the 3rd millennium. Publishing SVG on the Web is simple, however there is much to consider when implementing SVG in full-scale Web applications. application development, to compressing your SVGs with GZip, to testing for the SVG Viewer plugin, to adding security to your content.

Part II: The Beauty of SVG Fractals


Fractals are beautiful and looking at the elegant way they can be created with SVG they become even more beautiful. Iterated Function Systems (IFS) are a fascinating type of selfsimilar fractals. The theory behind them is not so much complicated. All we need to do is to apply a set of affine transformations to a shape. We see in chapter 6 an example, the Sierpinsky triangle. Another example with Von Koch snow flake.

Von Koch snow flake


Let's start with a line. We reuse this line for times after we scale it down by the factor 1/3 : - one at the begin of the original line - one rotated from 60 degrees and positionned at the end of the previous new line - one rotated from 60 degrees and positionned at the end of the previous - one at the end of the previous.

Learn SVG

Chapter 11 Web Development

24

Figure 12-7.

Von Koch curve step 0 and 1

<svg width="650" height="120"> <defs> <path id="level_0" fill="none" stroke="black" d="M0 0h300" /> <g id="level_1"> <use xlink:href="#level_0" transform="scale(0.333)" /> <use xlink:href="#level_0" transform="translate(100 0) rotate(-60) scale(0.333)"/> <use xlink:href="#level_0" transform="translate(150 -86.6) rotate(60) scale(0.333)"/> <use xlink:href="#level_0" transform="translate(200 0) scale(0.333)"/> </g> </defs> <use xlink:href="#level_0" stroke-width="1" transform="translate(20,100)"/> <use xlink:href="#level_1" stroke-width="3" transform="translate(340,100)"/> </svg>

You can see in this code that to get same stroke-width, we use different values. When we scale a svg object, stroke-width is also scaled. We repeat this transformation in a simple recursive manner and yield .. the Von Koch curve

Figure 12-8. Here is the code for this steps

Steps 2 3 4 and 5 of the IFS Process

<svg width="650" height="220"> <defs> <path id="level_0" fill="none" <g id="level_1"> <use xlink:href="#level_0" <use xlink:href="#level_0" scale(0.333)" /> <use xlink:href="#level_0" scale(0.333)" /> <use xlink:href="#level_0" </g> <g id="level_2"> <use xlink:href="#level_1" <use xlink:href="#level_1" scale(0.333)" /> <use xlink:href="#level_1" scale(0.333)" /> <use xlink:href="#level_1" </g>

stroke="black" d="M0 0h300" /> transform="scale(0.333)" /> transform="translate(100 0) rotate(-60) transform="translate(150 -86.6) rotate(60) transform="translate(200 0) scale(0.333)" />

transform="scale(0.333)" /> transform="translate(100 0) rotate(-60) transform="translate(150 -86.6) rotate(60) transform="translate(200 0) scale(0.333)" />

Learn SVG

Chapter 11 Web Development

25

<g id="level_3"> <use xlink:href="#level_2" transform="scale(0.333)" /> <use xlink:href="#level_2" transform="translate(100 0) rotate(-60) scale(0.333)" /> <use xlink:href="#level_2" transform="translate(150 -86.6) rotate(60) scale(0.333)" /> <use xlink:href="#level_2" transform="translate(200 0) scale(0.333)" /> </g> <g id="level_4"> <use xlink:href="#level_3" transform="scale(0.333)" /> <use xlink:href="#level_3" transform="translate(100 0) rotate(-60) scale(0.333)" /> <use xlink:href="#level_3" transform="translate(150 -86.6) rotate(60) scale(0.333)" /> <use xlink:href="#level_3" transform="translate(200 0) scale(0.333)" /> </g> <g id="level_5"> <use xlink:href="#level_4" transform="scale(0.333)" /> <use xlink:href="#level_4" transform="translate(100 0) rotate(-60) scale(0.333)" /> <use xlink:href="#level_4" transform="translate(150 -86.6) rotate(60) scale(0.333)" /> <use xlink:href="#level_4" transform="translate(200 0) scale(0.333)" /> </g> </defs> <use xlink:href="#level_2" stroke-width="9" transform="translate(20,100)" /> <use xlink:href="#level_3" stroke-width="27" transform="translate(340,100)" /> <use xlink:href="#level_4" stroke-width="81" transform="translate(20,200)" /> <use xlink:href="#level_5" stroke-width="243" transform="translate(340,200)" /> </svg>

And the snow flake ? We use three lines with id="level_5" to build a triangle. With same <defs> part, we have this code :
<use xlink:href="#level_5" stroke-width="243" transform="translate(20,100)" /> <use xlink:href="#level_5" stroke-width="243" transform="translate(320,100) rotate(120)" /> <use xlink:href="#level_5" stroke-width="243" transform="translate(170,360) rotate(-120)" />

Figure 12-9.

The Von Koch snow flake in SVG

You can zoom into the fractal, you can increase the level of iterations (recursions), you can even assign different colors and you can play with other shapes and transformations - rotation, shearing - of course.

Learn SVG

Chapter 11 Web Development

26

Another feature, that is possible with vector graphics, but not with the pixel based fractals (the majority on the web), is to visualize not only the last level, but all levels. It is not very difficult, to get the fractals interactively created by some ecmascript code. The recursive nature of XSLT would also be very useful.

IFS Generator
To explore this IFS and see result without coding, I create a tool where user enter transformations and level_0 object. Transformations must be affine to get some interesting result. They are represented by a matrix. In reality, a square give in this affine transformations a parallelogram, a square if there is only translate, rotate and uniform scale. User define transformations by drawing parallelograms with mouse, each parallelogram is square-ruled square transformed. Fot that, he choose three points and last point is calculated to get a parallelogram. But order for points change parallelogram. User can move this points and test IFS. On this example, we draw again Von Koch curve. For squares give us combination of scale(0.333), rotate and translate. The level_0 object is a line. We choose level and IFS is draw.

Figure 12-10.

Working space for IFS generator

Level_0 object is not very important for deep level in this case. We replace line by triangle and keep same transformations :

Figure 12-11.

High-level View with triangle as level_0 object

Some examples created with this IFS generator

Sierpinski Carpet

Learn SVG

Chapter 11 Web Development

27

Figure 12-12. Sierpinski carpet With the IFS generator, we can create and use gradient to fill primary object. This fractal need eight transformations, they are represented by squares. Only square in center is not a transform. We get Sierpinski carpet, we can make that in 3D space and it's Menger sponge.

Figure 12-13.

Tormented Tree

For this example of tree, we use five transformations and primary object is a rectangle.

Barnsley Fern

Figure 12-14. To draw this fern, only for transformations.

Barnsley Fern attempt

Learn SVG Other Examples

Chapter 11 Web Development

28

Figure 12-15.

Hexagonal Crystal

Figure 12-16. Pentagonal Attempt

If you want to learn more about IFS and fractals, type iterated function systems or simply fractals into your favorite search engine. Enjoy!

Appendix A : sRGB Colors


The SVG specification reads with regard to colours:
All SVG colors are specified in the sRGB color space. At a minimum, SVG user agents shall conform to the color behavior requirements specified in the color units section and the minimal gamma correction rules defined in the CSS2 specification.

Trying to understand the different colour spaces and the transformations between them completely can quickly get complicated. The sRGB standard includes the following definition for color space:
A color space is a model for representing color numerically in terms of three or more coordinates. e.g. The RGB color space represents colors in terms of the Red, Green and Blue coordinates.

The human eye can perceive more colours than any technical device can produce. A corresponding colour spectrum was defined by the comprehensive CIE colour gamut. The CIE system characterizes colours by a luminance parameter and two color coordinates, which specify a point in the chromaticity diagram (Figure A-1).

Figure A-1. CIE Chromaticity Diagram The three primary colours of monitors red, green, blue are represented on the chromaticity diagram by a triangle joining the coordinates for the three colors. Monitors are emitting light and thus work by additive colour blending. The basic colours of additive colour blending are red, green and blue. In contrast to that a printed image uses the CMY (cyan, magenta, yellow) colour model due to reflecting light, which is subtractive colour blending by nature. Obviously we have different device dependent colour models. Now imagine that you are taking a photo with your digital camera, read it into your computer, send it via internet to a

Learn SVG

Appendix A sRGB Colors

friend, who views at it on his monitor and finally sends it to his printer. We expect now a high-degree colour fidelity with this work flow. Exactly this is, what sRGB wants to achieve. As we have seen each colour model RGB and also CMY can be defined as a subset region of the CIE colour gamut. Based on this sRGB Single RGB Standard Color Space was defined as an international standard for device-independent colour control. It was first proposed in 1996 by HP and Microsoft. sRGB itself is again a subset of the RGB colour space and is based on using gamma correction a a major design factor. Gamma is the exponent of a power function used to adapt the non-linear characteristics of different devices to the also non-linear human perception. Using the sRGB standard SVG is conformant to the color behavior requirements specified in the CSS2 specification. Future versions of SVG may conform to CSS3 Color module. With the compatibility to CSS comes a table of named colors the so called X11 colors. These color names are advantagous especially when we do SVG coding by hand and dont have a color selection tool at hand. So we are providing a complete table of named colors for your convenience here (Table A-1). We also added the CSS2 user preference colors that might be supported with future SVG versions (Table A-2). The CSS3 specification reads here: In addition to being able to assign pre-defined color values to text, backgrounds, etc., CSS3, like CSS2, allows authors to specify colors in a manner that integrates them into the user's graphic environment. Style rules that take into account user preferences thus offer the following advantages: 1. They produce pages that fit the user's defined look and feel. 2. They produce pages that may be more accessible as the current user settings may be related to a disability.

Color Name
AliceBlue Aqua Azure Bisque BlanchedAlmond BlueViolet BurlyWood Chartreuse Coral Cornsilk Cyan DarkCyan DarkGray DarkKhaki DarkOliveGreen DarkOrchid

Hex

RGB

Color Name
AntiqueWhite Aquamarine Beige Black Blue Brown CadetBlue Chocolate CornflowerBlue Crimson DarkBlue DarkGoldenrod DarkGreen DarkMagenta DarkOrange DarkRed

Hex

RGB

#f0f8ff 240,248,255 #00ffff 0,255,255 #f0ffff 240,255,255 #ffe4c4 255,228,196 #ffebcd 255,235,205 #8a2be2 138,43,226 #deb887 222,184,135 #7fff00 127,255,0 #ff7f50 255,127,80 #fff8dc 255,248,220 #00ffff 0,255,255 #008b8b 0,139,139 #a9a9a9 169,169,169 #bdb76b 189,183,107 #556b2f 85,107,47 #9932cc 153,50,204

#faebd7 250,235,215 #7fffd4 127,255,212 #f5f5dc 245,245,220 #000000 0,0,0 #0000ff 0,0,255 #a52a2a 165,42,42 #5f9ea0 95,158,160 #d2691e 210,105,30 #6495ed 100,149,237 #dc143c 220,20,60 #00008b 0,0,139 #b8860b 184,134,11 #006400 0,100,0 #8b008b 139,0,139 #ff8c00 255,140,0 #8b0000 139,0,0

Learn SVG
DarkSalmon DarkSlateBlue DarkTurquoise DeepPink DimGray Firebrick ForestGreen Gainsboro Gold Gray GreenYellow HotPink Indigo Khaki LavenderBlush LemonChiffon LightCoral LightGoldenrodYellow LightGreen LightSalmon LightSkyBlue LightSteelBlue Lime Linen Maroon MediumBlue MediumPurple MediumSlateBlue MediumTurquoise MidnightBlue MistyRose NavajoWhite OldLace OliveDrab OrangeRed PaleGoldenrod PaleTurquoise PapayaWhip Peru Plum Purple RosyBrown SaddleBrown SandyBrown SeaShell Silver SlateBlue Snow SteelBlue Teal

Appendix A sRGB Colors


#e9967a 233,150,122 #483d8b 72,61,139 #00ced1 0,206,209 #ff1493 255,20,147 #696969 105,105,105 #b22222 178,34,34 #228b22 34,139,34 #dcdcdc 220,220,220 #ffd700 255,215,0 #808080 128,128,128 #adff2f 173,255,47 #ff69b4 255,105,180 #4b0082 75,0,130 #f0e68c 240,230,140 #fff0f5 255,240,245 #fffacd 255,250,205 #f08080 240,128,128 #fafad2 250,250,210 #90ee90 144,238,144 #ffa07a 255,160,122 #87cefa 135,206,250 #b0c4de 176,196,222 #00ff00 0,255,0 #faf0e6 250,240,230 #800000 128,0,0 #0000cd 0,0,205 #9370db 147,112,219 #7b68ee 123,104,238 #48d1cc 72,209,204 #191970 25,25,112 #ffe4e1 255,228,225 #ffdead 255,222,173 #fdf5e6 253,245,230 #6b8e23 107,142,35 #ff4500 255,69,0 #eee8aa 238,232,170 #afeeee 175,238,238 #ffefd5 255,239,213 #cd853f 205,133,63 #dda0dd 221,160,221 #800080 128,0,128 #bc8f8f 188,143,143 #8b4513 139,69,19 #f4a460 244,164,96 #fff5ee 255,245,238 #c0c0c0 192,192,192 #6a5acd 106,90,205 #fffafa 255,250,250 #4682b4 70,130,180 #008080 0,128,128 DarkSeaGreen DarkSlateGray DarkViolet DeepSkyBlue DodgerBlue FloralWhite Fuchsia GhostWhite Goldenrod Green Honeydew IndianRed Ivory Lavender LawnGreen LightBlue LightCyan LightGray LightPink LightSeaGreen LightSlateGray LightYellow LimeGreen Magenta MediumAquamarine MediumOrchid MediumSeaGreen

3
#8fbc8b 143,188,139 #2f4f4f 47,79,79 #9400d3 148,0,211 #00bfff 0,191,255 #1e90ff 30,144,255 #fffaf0 255,250,240 #ff00ff 255,0,255 #f8f8ff 248,248,255 #daa520 218,165,32 #008000 0,128,0 #f0fff0 240,255,240 #cd5c5c 205,92,92 #fffff0 255,255,240 #e6e6fa 230,230,250 #7cfc00 124,252,0 #add8e6 173,216,230 #e0ffff 224,255,255 #d3d3d3 211,211,211 #ffb6c1 255,182,193 #20b2aa 32,178,170 #778899 119,136,153 #ffffe0 255,255,224 #32cd32 50,205,50 #ff00ff 255,0,255 #66cdaa 102,205,170 #ba55d3 186,85,211 #3cb371 60,179,113 #00fa9a 0,250,154 #c71585 199,21,133 #f5fffa 245,255,250 #ffe4b5 255,228,181 #000080 0,0,128 #808000 128,128,0 #ffa500 255,165,0 #da70d6 218,112,214 #98fb98 152,251,152 #db7093 219,112,147 #ffdab9 255,218,185 #ffc0cb 255,192,203 #b0e0e6 176,224,230 #ff0000 255,0,0 #4169e1 65,105,225 #fa8072 250,128,114 #2e8b57 46,139,87 #a0522d 160,82,45 #87ceeb 135,206,235 #708090 112,128,144 #00ff7f 0,255,127 #d2b48c 210,180,140 #d8bfd8 216,191,216

MediumSpringGreen MediumVioletRed MintCream Moccasin Navy Olive Orange Orchid PaleGreen PaleVioletRed PeachPuff Pink PowderBlue Red RoyalBlue Salmon SeaGreen Sienna SkyBlue SlateGray SpringGreen Tan Thistle

Learn SVG
Tomato Turquoise Wheat WhiteSmoke YellowGreen

Appendix A sRGB Colors


#ff6347 255,99,71 #40e0d0 64,224,208 #f5deb3 245,222,179 #f5f5f5 245,245,245 #9acd32 154,205,50 Transparent Violet White Yellow

4
#ffffff 255,255,255 #ee82ee 238,130,238 #ffffff 255,255,255 #ffff00 255,255,0

Table A-1. Named Colors supported by SVG

Learn SVG

Appendix A sRGB Colors

Color Name
ActiveBorder

Description

Active window border. Active window caption. ActiveCaption Background color of multiple document interface. AppWorkspace Desktop background. Background Face color for three-dimensional display ButtonFace elements. Dark shadow for three-dimensional display elements (for edges facing away from the light ButtonHighlight source). Shadow color for three-dimensional display ButtonShadow elements. Text on push buttons. ButtonText Text in caption, size box, and scrollbar arrow CaptionText box. Grayed (disabled) text. This color is set to #000 if the current display driver does not support a GrayText solid gray color. Item(s) selected in a control. Highlight Text of item(s) selected in a control. HighlightText Inactive window border. InactiveBorder Inactive window caption. InactiveCaption InactiveCaptionText Color of text in an inactive caption. Background color for tooltip controls. InfoBackground Text color for tooltip controls. InfoText Menu background. Menu Text in menus. MenuText Scroll bar gray area. Scrollbar Dark shadow for three-dimensional display ThreeDDarkShadow elements. Face color for three-dimensional display ThreeDFace elements. Highlight color for three-dimensional display ThreeDHighlight elements. Light color for three-dimensional display ThreeDLightShadow elements (for edges facing the light source). Dark shadow for three-dimensional display ThreeDShadow elements. Window background. Window Window frame. WindowFrame Text in windows. WindowText

Table A-2. CSS3 System Colors

Appendix B: Unicode Reference


Overview
This section provides a convenient reference table for the common entity sets that represent Unicode characters. These entities can be found in the XHTML 1.0 specification at http://www.w3.org/TR/2001/WD-xhtml1-20011004/#dtds . The goal of the Unicode standard is to provide character a encoding for characters of all known written languages characters. Viewers that support Unicode character encoding will understand the character codes and translate and render the encoding into characters that are human readable.

Entity Sets
Greek
&Alpha; &Beta; &Gamma; &Delta; &Epsilon; &Zeta; &Eta; &Theta; &Iota; &Kappa; &Lambda; &Nu; &Xi; &Pi; &Rho; &Sigma; &Tau; &Upsilon; &Phi; &Chi; &Psi; &#913; &#914; &#915; &#916; &#917; &#918; &#919; &#920; &#921; &#922; &#923; &#924; &#925; &#926; &#928; &#929; &#931; &#932; &#933; &#934; &#935; &#936; &#x0391; &#x0392; &#x0393; &#x0394; &#x0395; &#x0396; &#x0397; &#x0398; &#x0399; &#x039A; &#x039B; &#x039C; &#x039D; &#x039E; &#x039F; &#x03A0; &#x03A1; &#x03A3; &#x03A4; &#x03A5; &#x03A6; &#x03A7; &#x03A8; greek capital letter alpha greek capital letter beta greek capital letter gamma greek capital letter delta greek capital letter epsilon greek capital letter zeta greek capital letter eta greek capital letter theta greek capital letter iota greek capital letter kappa greek capital letter lambda greek capital letter mu greek capital letter nu greek capital letter xi greek capital letter omicron greek capital letter pi greek capital letter rho greek capital letter sigma greek capital letter tau greek capital letter upsilon greek capital letter phi greek capital letter chi greek capital letter psi

&Mu;

&Omicron; &#927;

Learn SVG &Omega; &alpha; &beta; &gamma; &delta; &epsilon; &zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron; &pi; &rho; &sigmaf; &sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &upsih; &piv; &#937; &#945; &#946; &#947; &#948; &#949; &#950; &#951; &#952; &#953; &#954; &#955; &#956; &#957; &#958; &#959; &#960; &#961; &#962; &#963; &#964; &#965; &#966; &#967; &#968; &#969; &#978; &#982;

Appendix B Unicode Reference &#x03A9; &#x03B1; &#x03B2; &#x03B3; &#x03B4; &#x03B5; &#x03B6; &#x03B7; &#x03B8; &#x03B9; &#x03BA; &#x03BB; &#x03BC; &#x03BD; &#x03BE; &#x03BF; &#x03C0; &#x03C1; &#x03C2; &#x03C3; &#x03C4; &#x03C5; &#x03C6; &#x03C7; &#x03C8; &#x03C9; &#x03D1; &#x03D2; &#x03D6; greek capital letter omega greek small letter alpha greek small letter beta greek small letter gamma greek small letter delta greek small letter epsilon greek small letter zeta greek small letter eta greek small letter theta greek small letter iota greek small letter kappa greek small letter lambda greek small letter mu greek small letter nu greek small letter xi greek small letter omicron greek small letter pi greek small letter rho greek small letter final sigma greek small letter sigma greek small letter tau greek small letter upsilon greek small letter phi greek small letter chi greek small letter psi greek small letter omega greek small letter theta symbol greek upsilon with hook symbol greek pi symbol

&thetasym &#971

Latin Extended-B
&fnof; &#402; &#x0192; latin small f with hook = function = florin

General Punctuation
&bull; &#8226; &#8230; &#x2022; &#x2026; bullet = black small circle horizontal ellipsis = three dot leader &hellip;

Learn SVG &bull; &prime; &Prime; &oline; &frasl; &#8226; &#8242; &#8243; &#8254; &#8260;

Appendix B Unicode Reference &#x2022; &#x2032; &#x2033; &#x203E; &#x2044; bullet = black small circle prime = minutes = feet double prime = seconds = inches overline = spacing overscore fraction slash

Letterlike Symbols
&weierp; &image; &real; &trade; &#8472; &#8465; &#8476; &#8482; &#x2118; &#x2111; &#x211C; &#x2122; &#x2135; script capital P = power set = Weierstrass p blackletter capital I = imaginary part blackletter capital R = real part symbol trade mark sign alef symbol = first transfinite cardinal

&alefsym; &#8501;

Arrows
&larr; &uarr; &darr; &rarr; &harr; &crarr; &lArr; &uArr; &rArr; &dArr; &hArr; &#8592; &#8593; &#8594; &#8595; &#8596; &#8629; &#8656; &#8657; &#8658; &#8659; &#8660; &#x2190; &#x2191; &#x2192; &#x2193; &#x2194; &#x21B5; &#x21D0; &#x21D1; &#x21D2; &#x21D3; &#x21D4; leftwards arrow upwards arrow rightwards arrow downwards arrow left right arrow downwards arrow with corner leftwards = carriage return leftwards double arrow upwards double arrow rightwards double arrow downwards double arrow left right double arrow

Mathematical Operators
&forall; &part; &exist; &empty; &nabla; &#8704; &#8706; &#8707; &#8709; &#8711; &#x2200; &#x2202; &#x2203; &#x2205; &#x2207; for all partial differential there exists empty set = null set = diameter nabla = backward difference

Learn SVG &forall; &isin; &notin; &ni; &prod; &sum; &#8704; &#8712; &#8713; &#8715; &#8719; &#8721;

Appendix B Unicode Reference &#x2200; &#x2208; &#x2209; &#x220B; &#x220F; &#x2211; &#x2212; &#x2217; &#x221A; &#x221D; &#x221E; &#x2220; &#x2227; &#x2228; &#x2229; &#x222A; &#x222B; &#x2234; &#x223C; &#x2245; &#x2248; &#x2260; &#x2261; &#x2264; &#x2265; &#x2282; &#x2283; &#x2284; &#x2286; &#x2287; &#x2295; &#x2297; &#x22A5; &#x22C5; for all element of not an element of contains as member n-ary product = product sign n-ary sumation minus sign asterisk operator square root = radical sign proportional to infinity angle logical and = wedge logical or = vee intersection = cap union = cup integral therefore tilde operator = varies with = similar to approximately equal to almost equal to = asymptotic to not equal to identical to less-than or equal to greater-than or equal to subset of superset of not a subset of subset of or equal to superset of or equal to circled plus = direct sum circled times = vector product

&minus; &#8722; &lowast; &#8727; &radic; &prop; &infin; &ang; &and; &or; &#8730; &#8733; &#8734; &#8736; &#8743; &#8744; &#8745; &#8746; &#8747; &#8756; &#8764; &#8773; &#8800; &#8801; &#8804; &#8805; &#8834; &#8835; &#8836; &#8838; &#8839; &#8853; &#8869; &#8901;

&cap; &cup; &int; &there4; &sim; &cong;

&asymp; &#8776; &ne; &equiv; &le; &ge; &sub; &sup; &nsub; &sube; &supe; &oplus; &perp; &sdot;

&otimes; &#8855;

up tack = orthogonal to = perpendicular dot operator

Learn SVG

Appendix B Unicode Reference

Miscellaneous Technical
&lceil; &rceil; &lfloor; &rfloor; &lang; &rang; &#8968; &#8969; &#8970; &#8971; &#9001; &#9002; &#x2308; &#x2309; &#x230A; &#x230B; &#x2329; &#x232A; left ceiling = apl upstile right ceiling left floor = apl downstile right floor left-pointing angle bracket = bra right-pointing angle bracket = ket

Geometric Shapes
&loz; &#9674; &#x25CA; lozenge

Miscellaneous Symbols
&spades; &clubs; &hearts; &diams; &#9824; &#9827; &#9829; &#9830; &#x2660; &#x2663; &#x2665; &#x2666; black spade suit black club suit = shamrock black heart suit = valentine black diamond suit

C0 Controls and Basic Latin


" & < > &quot; &amp; &lt; &gt; &#34; &#38; &#60; &#62; &#x0022; &#x0026; &#x003C; &#x003E; quotation mark = APL quote ampersand less-than sign greater-than sign

Latin Extended-A
&OElig; &oelig; &#338; &#339; &#x0152; &#x0153; &#x0160; &#x0161; &#x0178; latin capital ligature OE latin small ligature oe latin capital letter S with caron latin small letter s with caron latin capital letter Y with diaeresis

&Scaron; &#352; &scaron; &#353; &Yuml; &#376;

Learn SVG

Appendix B Unicode Reference

Spacing Modifier Letters


&circ; &tilde; &#710; &#732; &#x02C6; modifier letter circumflex accent

&#x02DC ISOdia; small tilde

General Punctuation
&ensp; &emsp; &zwnj; &zwj; &lrm; &rlm; &#8194; &#8195; &#8204; &#8205; &#8206; &#8207; &#x2002; &#x2003; &#x2009; &#x200C; &#x200D; &#x200E; &#x200F; &#x2013; &#x2014; &#x2018; &#x2019; &#x201A; &#201C; &#x201D; &#x201E; &#x2020; &#x2021; &#x2030; &#x2039; &#x203A; &#x20AC; en space em space thin space zero width non-joiner zero width joiner left-to-right mark right-to-left mark en dash em dash left single quotation mark right single quotation mark single low-9 quotation mark left double quotation mark right double quotation mark double low-9 quotation mark dagger double dagger per mille sign single left-pointing angle quotation mark single right-pointing angle quotation mark euro sign

&thinsp; &#8201;

&ndash; &#8211; &lsquo; &rsquo; &sbquo; &ldquo; &rdquo; &#8216; &#8217; &#8218; &#8220; &#8221;

&mdash; &#8212;

&bdquo; &#8222; &dagger; &#8224; &Dagger; &#8225; &lsaquo; &#8249; &rsaquo; &#8250; &euro; &#8364;

&permil; &#8240;

Appendix C: Viewers, Tools, and Authoring Environments


SVG Viewers:
Adobe SVG Viewer (ASV): http://www.adobe.com/svg/ ASV can serve as a browser Plug-in for MS IE 4 or greater, Netscape 4.5 to 4.77, RealPlayer 8 or higher and Opera 5.x. Also an Active-X control for SVG display in (Windows) MS Office and Visual Basic. Has a FAQ. The Adobe SVG Technology Preview site includes examples and a detailed tutorial. Fifteen different localizations are also available. There is a list of currently supported features and release notes for Mac and Windows. Corel SVG Viewer (CSV): http://www.corel.com/svgviewer CSV performs much like the Adobe SVG Viewer but requires Windows 2000 or Windows XP. X-Smiles: http://www.x-smiles.org X-Smiles is a multi-namespace XML browser. It can display SVG, XForms, SMIL Basic and XSL-FO, and contains an XSLT engine for styling of other XML document formats (such as well-formed XHTML ). It also has ECMAscript, XML Events, support for SIP videoconferencing, and multi-skin support (including GTK/KDE skins). Batik SVG Viewer Module: http://xml.apache.org/batik/ Java Based Toolkit that uses Xerces XML parser, Xalan XSLT engine, and Koala CSS parser. There is a list of supported features. Part of the Apache Batik SVG Toolkit. CSIRO SVG Toolkit: http://www.cmis.csiro.au/svg/ Uses Xerces XML parser and Steady State CSS parser. Can print, and convert to raster formats. Feedback by email. There is a list of supported features SVG in Mozilla project: http://www.mozilla.org/projects/svg/ Uses Mozilla XML parser, CSS parser, JavaScript and DOM. Has a newsgroup and several examples Amaya: http://www.w3.org/Amaya/Amaya.html Amaya is a browser/editor for SVG and for mixed namespace XML, XHTML, SVG, and MathML. It also has annotation capabilities.

SVG Authoring Enviroments:


We recommend the following SVG authoring environments. WebDraw: http://www.jasc.com/Webdraw.asp Formerly known as 'Trajectory Pro', WebDraw is a native SVG editor allowing both import and export of SVG, and the SVG source can be inspected and manipulated any time. WYSIWYG visual editing of filter effects, and timeline editing of animations, is notable features. List of new features.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

Corel Graphics Studio Illustrator 10: http://www.adobe.com/products/illustrator/ Illustrator version 9.01 had SVG export capability. Version 10, announced recently, adds SVG import and enhances SVG export, including data-driven graphics.

Text and XML Editors:


Your operating systems basic text editor can create SVG graphics however these glorified text and XML editors will undoubtedly increase your efficiency. UltraEdit http://www.ultraedit.com TextPad - http://www.textpad.com HTML-Kit - http://www.chami.com/html-kit/ XML Spy - http://www.xmlspy.com

SVG in Practice
SVG is already taking off as demonstrated in the computer industries widespread support of SVG in major product lines, third-party tools and Web applications. Products SVG has already been integrated into several major products including: PocketSVG: http://www.pocketsvg.com/ Swift3D: http://www.erain.com/swiftinfo.asp Catwalk: http://www.schemasoft.com/Catwalk/ SVGMapMaker: http://www.dbxgeomatics.com/SVGMapMaker.asp Data Slinger: http://www.savagesoftware.com/products/dataslinger/index.html Perl SVG Server: http://www.roasp.com/ AgileBlox: http://www.elansoft.com/web/inside/products.html SVG Presentation Kit: http://www.schemasoft.com/tools/xmlpresentations/ eSVG: http://www.embedding.net/eSVG/ eMotion: http://www.pcxsoftware.com/svg_studio/draft.htm Radio Weblogs: http://radio.weblogs.com/0101319/categories/svgViaRadio/ SVG-Builder: http://www.svg-builder.com/ SVG Composer: http://www.svgcomposer.com/ Third-party Tools and Converters There are also a host of third party tools, products, converters and plug-ins that are being developed that will serve to integrate SVG into an increasing number of fields. Some of These include: CAD plug-in: http://www.malz-kassner.com/e/info_svg.htm SVG MapGen (ESRI and MapInfo plug-in): http://geographs.com/SVG/SVG.htm MapViewSVG (ARCView plug-in): http://www.mapview.de/eng/ SVG Toolkit: http://www.savagesoftware.com/products/toolkit/index.html JViews: http://www.ilog.com/products/jviews/maps/svg/

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

TinyLine: http://www.geocities.com/tinyline/ Nokia: http://www.forum.nokia.com/main.html Swift3D XSI (plugin for SoftImage): http://www.erain.com/swift3dxsifeatures.asp Swift3D MAX (plugin for 3D Studio Max): http://www.erain.com/swift3dmaxinfo.asp Graphics Connection: http://www.square1.nl/index.htm Beez: http://sourceforge.net/projects/beez/ Web Applications A number of companys are are already taking advantage of SVG for both internal and external Web applications including: BattleBots - http://www.battlebots.com/svg_info.asp MP2KMag - http://www.mp2kmag.com/ USByte - http://www.usbyte.com/SVG/SVG.htm GraPL.Net - http://www.grapl.com/net/index.html Direct Service Center http://directsc.mbsbooks.com

About Some Tools


Viewers Here is the low-down on the viewers that are currently available to work with:
Adobe SVG Viewer

Adobe has been a leader in regard to SVG in many areas. As an SVG working group member Adobe put a lot of work into the development of the SVG specification. Also Adobe has promised full support of SVG in all of their major graphics applications and has already delivered on the promise in Adobe Illustrator 10, Adobe GoLive 5.0 and Adobe Live Motion (hopefully). Most importantly, Adobe Systems led the industry in its support of SVG by releasing the most advanced SVG viewer called the Adobe SVG Viewer www.adobe.com/svg/. The Adobe SVG Viewer is available as a downloadable plugin that allows SVG to be viewed on Windows, Linux and Mac operating systems in all major browsers including Internet Explorer (versions 4.x, 5.x, 6.x), Netscape (versions 4.x, 6.x), and Opera in Internet Explorer and Netscape. In Internet Explorer 5.0 or higher SVG can even be rendered inline with other XML documents by means of an SVG binary behavior that is distributed with the Adobe SVG Viewer. If you have not downloaded Adobes plug-in yet then now is a great time to check it out. This viewer is the most widely deployed SVG viewer and it supports nearly all of the SVG Specification including support for the SVG DOM, animation and scripting. The SVG Viewer plug-in also works as a plug-in for Real Player and allows for SVG to be viewed with video and sound media.
Features of the Adobe SVG Viewer

Click the right mouse button (CTRL-Key + mouse click on the Mac) over your SVG image to gets a context menu. The context menu gives you several options such as step-by-step

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

zooming, finding (searching for text in the SVG image), viewing the SVG source, and saving the SVG.

Figure C-1. The Adobe SVG Viewer context menu

There are also some built in hot-keys that allow you to easily perform the following:
Magnification

Zoom In: Using the CTRL-Key (or Apple-Key) you can drag your mouse to make a rectangle that specifies the cross-section of the area you will zoom to. Zoom Out: This work just like Zoom In except you press the CTRL-Key and the SHIFTKey at the same time.
Panning

Panning: Pressing the ALT-Key and move the mouse cursor while a "hand-icon" appears.
Copy SVG

The purpose of the SVG Viewers Copy SVG options is for users to be able to cut-and-paste graphics and/or source code into other applications. Using Copy SVG developers are able to make a copy of the source code, which can be pasted into any text editor. Also, after selecting Copy SVG and switching to a desktop application such as MS Office users are able to choose either to use the Edit Paste option to produce a snapshot of the SVGs DOMtree code (this contains the current structure of the dynamic SVG image) or users can use the Edit Paste Special option to translate the SVG into a Bitmap image. These options are likely to improve and increase as support for SVG improves in other applications.
View Source

The SVG Viewers View Source menu options allows both compressed and uncompressed SVG source code to instantly be viewed as text in a new browser window. This is a very handy option for designers and developers.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

Save SVG as

This option allows for quickly saving of SVG content to your local computer by popping up a save SVG as form that gives you the option to input the name and location of the file. In version 3 of the Adobe SVG Viewer the option of Saving as GZip compressed SVG (.svgz) was added to the save as dialog box.

Figure C-2. SVG Viewer save options

Take a few minutes and test out some of the SVG Viewer menu options. There is a good chance that it will be time well spent, as these options are powerful and often lead to increased efficiency. Although the Adobe SVG Viewer should meet most people needs for viewing SVG there are several other SVG viewers available.
Batik

The Batik project http://xml.apache.org/batik/ is an open source Java-based toolkit that can be used to view, manipulate, and generate SVG images. Batik can be used as a standalone SVG browser or can be incorporated in to other applications. Batik 1.5 supports all static features of the SVG specification and also includes support for scripting of the SVG DOM. Batik is able to convert fonts and can also export SVG as raster images.
SVGToolkit and PocketSVG

The SVGToolkit sis.cmis.csiro.au/svg is an open source viewer and converter that is. The SVG Toolkit contains an SVG viewer, an implementation of the SVG DOM (conforming to Document Object Model Level 2) and a utility for rendering an SVG document into various image formats. It is written in Java and requires Java 1.2 or higher (we develop using 1.3). PocketSVG www.cmis.csiro.au/PocketSVG/ can be used in the field on Windows CE powered Pocket PC's, including Pocket PC 2000. PocketSVG Version 1.0 supports the proposed W3C SVG Tiny Specification and a subset of the W3C SVG Specification. It contains software components which cover the basic functionality needed when creating SVG-based applications. The PocketSVG Toolkit provides the software components that developers need to quickly and easily create applications for Pocket PC's. Browsers New viewers are being developed that are blowing the major browsers out of the water with respect to their support for W3C standards including X-Smiles, Mozilla and Amaya.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

X-Smiles

X-Smiles www.x-smiles.org is an open source multi-namespace XML browser. It can display SVG, XForms, SMIL Basic, XSL-FO, X3D and XML Signature. X-Smiles also contains an XSLT engine for styling other XML document formats (such as well-formed XHTML). It also has ECMAscript, XML Events, support for SIP videoconferencing, and multi-skin support (including GTK/KDE skins). X-Smiles has moved to the head of the pack in terms of its support for W3C standard applications with the release of X-Smiles v0.6 and higher. I recommend taking a look at it sooner rather than later. X-Smiles provides us with a glimpse of the future of the Web.
Mozilla SVG

The Mozilla SVG project browser already supports SVG inline with other XML namespaces thanks to the work of a few key developers at www.mozilla.org/projects/svg/ . This browser is available for Windows, Macintosh and Linux. Inline SVG means that the browser does not need a plug-in to render SVG images. Other XML namespaces include MathML, XHTML, XForms, CML, XUL, etc. that can be mixed together in the same document. Some examples of the Mozilla SVG project in action can found at croczilla.com/svg/ .
Amaya

Amaya www.w3.org/Amaya/ is a browser/editor for SVG and for mixed namespace XML, XHTML, SVG, and MathML that also has annotation capabilities. The purpose of Amaya is to provide the development community with a proof-of-concept implementation for W3C standard applications. Amaya is a complete web browsing and authoring environment and comes equipped with a WYSIWYG style of interface. Amaya allows you to view and edit multiple-namespace documents and will soon support all of the SVG 1.1 specification. Other Applications As a vector standard, SVG is likely to be adopted in many applications outside the browser. Already it is being used to develop user interfaces in Microsofts peer-to-peer Groove.net collaboration tool and will likely be adopted by vendors making software ranging Geographic Information Systems (GIS) to medical imaging. Sun Microsystems and IBM have also supported SVG since the beginning and have also released some viewers and applications and for SVG. IBMs SVG View www.alphaworks.ibm.com/aw.nsf/FAQs/svgview supports some of the SVG specification and Sun has released both an SVG 2-D Generator and an SVG Slide Toolkit wwws.sun.com/software/xml/developers/svg-slidetoolkit/ . As the major browsers mature in regard to their support for W3C standards, XHTML (www.w3.org/TR/xhtml1/ - a rework of the HTML specification that conforms to the XML

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

specification), SVG, or any other XML language that is created will be able to be interpreted as mixed namespaces and displayed natively by browsers. When this occurs then SVG will be much closer to reaching its full potential. Now is a great time for Web developers and designers to begin harnessing the power of SVG.
SVGMaker

SVGMaker (http://www.svgmaker.com/) - Virtual printer to get svg file from any application using printing capabilities of Windows. SVGMaker run with all versions of Windows.

Figure C-3. Parameters for SVG Maker

You can choose page size, orientation and margins as for any printer device. For text, you can use system fonts, embed fonts in svg or draw text as paths. If your document has many pages, SVGMaker add control for navigation between pages using javascript in svg files or links in HTML files.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

Figure C-4. Parameters for text in SVG Maker

You can choose to position text between basic ( text of same line in a text object without <tspan> tag ), per character with position for each letter or per word. SVGMaker give very good results for equations created in text processor.

With SVGMaker, you get from presentation in PowerPoint SVG slides with navigation between slides.
WebDraw

The most effective method for designing SVG is via graphical authoring environments that are able to save or export as SVG. As of the release of Learn SVG, one of the crme-de-lacrme SVG authoring environment is WebDraw, however, several other SVG authoring environments exist that will be able to output SVG images. Here is a screenshot of the WebDraw authoring environment in Canvas Mode.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

Figure C-5. WebDraw authoring environment in canvas mode

Notice the timeline which is used to easily add animations to SVG images. This is what WebDraw looks like in Source Mode that allows for editing SVG source inside of the authoring environment.

Figure C-6. WebDraw authoring environment in source mode

This is a necessary feature for both SVG design and development, as you will come to understand as you become skilled in the revolutionary capabilities of this language.
The Toolbox

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

10

Lets take a look at some common features of an SVG authoring environment Tool Palette or Toolbox.

Figure C-7. WebDraw Tool Palette Options

Each tool has a set of associated options that will appear in the Tool Options palette. Once we click on a specific tool the options palette automatically updates to provide us with all of the choices we have for a given tool. These are the tool options for the Rectangle Tool .

Figure C-8. WebDraw Property Palette View

Our view of the canvas can be scaled and panned using the Magnify Tool Tool.

and Hand

Figure C-9. WebDraw zooming tool (left) panning tool (right) Colors

The colors section allows us to choose between the various Color options for the stroke and fill of our graphical objects.

Learn SVG

Appendix C Viewers, Tools and Authoring Environments

11

Figure C-10.

WebDraw Color Dialog Box

Some of the options include no stroke, no fill, or solid, gradient or pattern strokes or fills.

Figure C-11.

WebDraw gradient drop down selection box

We will discuss gradients and patterns in depth in Chapter 7. If you have any experience working with vector graphics then you this will find this to be a piece of cake. Creating SVG in authoring environments is very much the same as creating any other type of vector graphic output. However, there are some key differences in authoring vector graphics for output to SVG. Throughout the book we will uncover a plethora of tips and tricks including issues around optimizing SVG output and even integration of EcmoScript functions into the SVG code, but lets take this one step at a time.

Вам также может понравиться