• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Learn svg
 

Learn svg

on

  • 6,708 views

Free SVG ebook from http://learnsvg.com/

Free SVG ebook from http://learnsvg.com/

Statistics

Views

Total Views
6,708
Views on SlideShare
6,707
Embed Views
1

Actions

Likes
2
Downloads
79
Comments
0

1 Embed 1

http://www.slideshare.net 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Learn svg Learn svg Document Transcript

    • 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 notonly 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 devicesfrom palmtops to desktops to printers. They need graphics which can be restyled for differentpurposes. But most of all, they need to be able to handle their graphics the same way as theirtext and business data, which nowadays are in XML. SVG is specifically designed to let themdo that."- Chris Lilley, W3C Graphics Activity Lead.IntroductionThe first thing you need to know is the authors of Learn SVG are experts in the field ofcomputer 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 thatserve to instruct and inspire.Scalable Vector Graphics (SVG) is a revolutionary new graphics format that is unleashingthe true potential of graphical information on the Web. SVG is a language for describing two-dimensional graphics in XML. SVG supports anti-aliased rendering, zooming, panning, filter-effects, pattern and gradient fills, clipping to paths, text, animations and interactivity andmore! SVG is designed to use and to incorporate other W3C specifications and standardssuch 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 forpixel-perfect positioning of SVG graphical objects, which include shapes, text as well asraster graphics such as PNG and JPEG images and supports color accuracy of over 16million colors.SVG is revolutionary in that it can be fully customized on the client at runtime by means ofstyle sheets and script. Users are able to customize colors, fonts, content and even the layoutof 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 objectmodel that extends the DOM in a compatible way called the SVG DOM. By being able to useboth of these object models, SVG is able to be scripted in a open and powerful way.
    • Learn SVG Chapter 1 Introduction 2This book has a special focus on scripting. The scripting content is complete for beginners, asit introduces EcmaScript and the DOM first and shows how to access and manipulate theinternals of a SVG document via programming.Furthermore, the book focuses on the generation of highly interactive graphics and shows indetail how to deal with event handling. Learn SVG will also cover necessary insights into theessential theory of vector and matrix algebra to explain the guts of the efficient rawtransformation matrices that can even be controlled by the client at runtime.Aims and Objectives of the BookAbout Learn SVG / ApproachThe objective of this book is to enable readers who are brand spanking new to SVG to reach asemi-advanced level of SVG design and programming through a progression of "real-world"case studies, examples, and scenarios that programmers, Web developers and graphicdesigners 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. Inthe 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 accompaniedby intriguing examples, real-world scenarios and brilliant user interface designs. By the end ofthis book the reader will be well equipped to ride the SVG wave and integrate SVG into XML-based technologies that are at our doorstep.The challenges of gracefully integrating both the graphic design and programming aspects ofSVG are not insignificant. But with the help of some terrific editors and reviewers we haveproduced an excellent foundational text for your reading pleasure.The workbook-like format of this book lends itself ideally to Web designers and developerswho want both a solid foundation in the main aspects of SVG and who are willing to get theirhands dirty with the fertile soil that SVG has to offer. The full challenge of the book is not forthe faint of heart but Learn SVG has made sure to thoroughly cover all the bases using manyconcrete examples.The purpose of Learn SVG is to inform and inspire readers by covering SVG programmingand design techniques through in-depth examples. This book is for people who are relativelynew to SVG and who want to start fiddling with the guts of SVG right away. This book willjump right in to real-world examples that can serve as both a workbook and a reference. Thelarge pool of current programmers, Web developers, content publishers and graphic designerswill find that this book gives them an invaluable edge in their respective and increasinglyoverlapping fields.
    • Learn SVG Chapter 1 Introduction 3Audience of this BookDue to the fact that SVG is revolutionary, Learn SVG aims to educate a wide-rangingaudience 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-communityThis book is aimed to inspire many types of content-creators to love SVG. This bookprovides a solid foundation for getting started with SVG. We will cover the basics as clearlyand concisely as possible. On the other hand, there is a lot to this new graphicsformat/language and so we have included "SVG Concepts", challenges, and advancedexercises at the end of each chapter that introduce more complex topics for the avid Webdeveloper. If you are here for the full challenge then please fasten your safety belts and hangon tightly lest you be thrown to the wolves.Conventions and TerminologyWe use a number of different styles of text and layout in the book to help differentiatebetween the different kinds of information. Here are examples of the styles we use and anexplanation of what they mean:IndentationIndentation 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 4 fill="red" stroke="black" /> <!-- code for the car goes here --> </svg>Emphasizing of important code and termsWhen you first come across an important term it will be in bold type, then in normal typethereafter.Well 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 CommandsMenu commands are written in the form:Menu > Sub-menu > Sub-menuScriptingThe script language used throughout this book is EcmaScript, which the W3C accepts as anopen scripting standard. The corresponding element is always :<script type="text/ecmascript"><![CDATA[ // script content goes here ..]]></script>SVG ElementsIt is beneficial, to have a common skeleton for introducing a new SVG element or a family ofnew elements throughout the book.The format that will be used will be:
    • Learn SVG Chapter 1 Introduction 5 • Introductory text • Element syntax • Explaining element specific attributes. text or table • Element example(s): picture and codeThe Element Syntax always looks similar to this exampleSyntax: <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 6Chapter 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 SVGIntroductionLearn SVG explores the world of Scalable Vector Graphics. SVG is a graphics format thathas been developed as an open source industry standard graphics format and is maintained bythe W3C. SVG describes graphics using XML grammar. SVG interrogates and conformswith Web standards such as DOM, XML Namespace, Xpath, Xlink and XPointer and manyothers that will addressed in this book. The key to SVG is in fact that each of these robuststandards seamlessly works together with SVG. This allows SVG to be stylized, dynamic,animated, interactive, extensible and an all-around extraordinary graphics format. In SVG wefind the culmination of the next generation of the Web. This is why SVG makes for a trulyastounding and robust presentation layer for the Web.We have a lot to cover so let’s start with some inspiration. You will need a SVG Viewer toview figure 1.1. If you do not have a SVG Viewer Please see Appendix C to help you pickone out. Figure 1-1: Inspirational SVG image
    • Learn SVG Chapter 1 Introduction 7How SVG EmergedThere has been a lot of excitement and generated by this graphics format as it has become avital part of Web development. SVG is a creation of the World Wide Web Consortium(W3C), which is an open–standards international industry consortium that has been formed todevelop open-source standards for the Web.SVG emerged through the work of a The World Wide Web Consortium working group thatwas formed back in 1998. The W3C SVG Working Group continues to improve thecapabilities of SVG. W3C working groups are comprised of representatives from a variety ofindustries across the world. There are over twenty members of the SVG Working Groupincluding some of the top industry leaders such as: Adobe Systems, Sun Microsystems, IBM,Corel, Macromedia, Hewlett–Packard, Microsoft, and AOL/Netscape.With the development of XML the opportunity arose to create an XML-based language todescribe graphics. The W3C gave the SVG working group the goal of developing a XMLgraphic format that could produce top quality graphics. SVG does just that and a great dealmore as we will be discovering throughout this book.In 1998, the W3C was presented with two proposals for new graphics formats. BothPrecision Graphics Markup Language (PGML) and Vector Markup Language (VML)are described using an XML grammar. Adobe proposed PGML based on its experience withPostscript and PDF, PGML is in fact generated from PDF files. Support for Microsoft’ssubmission, VML, has been realized in Internet Explorer, but development stopped in theautumn of 1998.After much consideration the W3C decided to combine the best aspects of both of the PGMLand VML languages into a new language called SVG.On August 2nd and again on November 2nd of 2000 the W3C upgraded SVG to CandidateRecommendation and urged developers to begin implementing SVG. One and half yearsafter the first SVG Working Draft was published, Chris Lilley, the Activity leader and chair ofthe SVG Working Group, announced the release of the SVG 1.0 specification as a W3CRecommendation. 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 isready for full-scale implementation. The SVG Working Group is continuing to expand thecapabilities 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 2003SVG 1.1 and SVG Mobile specifications were released. Work continues on the longanticipated SVG 1.2, SVG 2.0 and SVG Print specifications that will probably support highlydesired features such as text-wrapping.
    • Learn SVG Chapter 1 Introduction 8This is the current SVG Roadmap.Document WD1 WD2 LC Ends CR PR RECSVG 1.0 - - - - - - 5 Sep 2001SVG 1.1 - - - - - 11 Nov 14 Jan 2002 2003SVG Mobile - - - - - 11 Nov 14 JanProfiles 2002 2003SVG 1.2 11 Nov [Jan [May [July [August [Dec [Jan 2002 2003] 2003] 2003] 2003] 2003] 2004]SVG Print [Jan - - - - - -Requirements 2003]SVG Print [Mar - - - - - - 2003]Authoring [Feb - - - - - -Tool 2003]GuidelinesAccessibility [MarTechniques 2003]Legend: WDn = nth working draft; LC = last call for comments (i.e., lastWD); Ends = deadline for LC comments; CR = Candidate Recommendation;PR = Proposed Recommendation; REC = W3C Recommendation.[Feb 02] = expected date.SVG is XMLSVG is based on eXtensible Markup Language (XML) grammar, the standard markup forWeb documents in the 21st century. Other XML-based applications that are in use or underdevelopment include XHTML, MathML, SMIL, X3D, XFORMS, and many others. Rapidadoption and application of these technologies has already occurred and offer a state-of-the-art foundation for documents. As you can see, SVG is built with the future of the Web inmind.SVG being an application of XML benefits from all the advantages XML brings. SVG is text-based and open source web standard.If you are familiar with XML you will see that there really is nothing new about the structureof the SVG language. As you can see in figure 1-1, SVG is composed of content marked–upwithin “tags” which are made up of “elements” and “attributes”.The following diagram examines components of the SVG language using XML grammar andsyntax:
    • Learn SVG Chapter 1 Introduction 9 Figure 1-2: SVG syntax and basic grammarSVG is EfficientSVG 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 areference to one external jpeg image that has been positioned over the letter "G" that is reallymaking the file size huge.) If we use gzip to compress the SVG file then it ends up being lessthan 1 KB. This is tiny!You will find this to be especially astonishing when you discover that this image can beinfinitely 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 ofthe elements and attributes of figure 1.1 can be efficiently accessed and manipulated. If youwanted any of the objects in the graphic to move, you can just add some animation elementsor script at almost no cost to size of the file.SVG is PowerfulFor the past ten or more years programmers have been thinking about how best to introducetwo-dimensional vector graphics to end users. The benefits of using vector graphics includegreater interaction and analysis with the user interface including such functionality aspanning, zooming and best of all programmatic animation. One excellent aspect of SVG isthat once downloaded to the client it can be reused on a page at different sizes or withdifferent features and even different data.A host of technologies can work together to make SVG the ultimate graphics format andXML application. For example, ECMAScript, CSS, XSLT and XSL-FO can be applied toSVG 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 thatSVG 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. Theseinclude:
    • 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 SVGs 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 torender images in browsers. The main bitmap graphic formats that are used on the Web todayare: • 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. Rastergraphics are displayed by a method of filling in a matrix of pixels, which requires storing theinformation for every pixel of the graphic.Vector graphics such as SVG and SWF formats are different beasts altogether belonging toanother 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 11Although bitmap images do work very well in many situations, vector graphics open up awhole new world of possibilities in Web graphics. For example compare the following twoscreenshots 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 inNotice that we have not lost any quality. This is because the vector-based viewers are able torecalculate how the graphic should look based on the textual description of the circle shapethat is found inside of the SVG graphic. This is a key advantage of SVG and raster graphicformats.Because vector graphics are defined programmatically they provide a more efficient meansfor rendering print and animation, as well as adding interaction (including panning andzooming) and analytical capability.One of the limitations of bitmap images is how they describe graphics. Bitmaps do notdescribe graphics as shape elements or objects but instead have to describe each and everypixel in the image. Bitmaps can make use of efficient compression techniques and can bestreamed because its data is stored serially, however as you will see in these screenshots thescalability 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 12The raster image becomes very pixilated when it is scaled while the vector image losesabsolutely no image quality! SVG is a Vector graphic format. Now, you know why SVG iscalled Scalable Vector Graphics.The Building Blocks of SVGScalable Vector Graphics (SVG) is a completely open standard XML language for describingtwo-dimensional graphics using a combination of three types of graphical objects: vectorgraphic shapes, images and text. Let’s take a minute to explain in detail what that lastsentence actually means.SVG is Composed of Graphical ObjectsSVG is made up of three types of graphical objects: shape, image and text objects. Figure 1-8: Graphic Objects in SVGShapes in SVGThe following image can be displayed using HTML via the <image> element, or it can bedisplayed using SVG via the <circle> element. Figure 1-9: Circle in SVGHTML document:<html> <head> <title>Pink Circle</title> </head> <body>
    • 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 excitementsurrounding the SVG graphic format? What are the kinds of benefits and drawbacks of usingSVG 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 usingCubic 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 SVGWorking Group recognized this and provides two more graphic objects to help: Images andText. How to inline and embed SVG images will be exported in many chapters.Images in SVGIn SVG, raster images are actually graphical objects. This gives the developer or end-user theability to, for example, apply client-side animation and filter effects on specific raster imagesas 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 Recommendationstates 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 SVGAfter shapes and images, the third graphical object in SVG is text. As a graphical object, textcan be programmatically controlled and manipulated through script just like shapes andimages!SVG text is composed of font characters that technically are in turn comprised of glyphs. Wewill describe the difference between fonts and glyphs and many other interesting features ofusing text in SVG in greater detail in Chapter 5.SVG in Practice
    • Learn SVG Chapter 1 Introduction 14SVG is already taking off as demonstrated in the computer industries widespread support ofSVG in major product lines, third-party tools and Web applications. Please see Appendix Cfor a listing of Products, third-party tools and Web applications.Viewing SVGBefore we start working with SVG let’s make sure we’re all on the same page. A prerequisitefor this book is that you have the resources in place to at least be able to view SVG. Please seeAppendix C to help you quickly pick out a SVG Viewer.Creating SVGHand-coding SVGSo now that we know what SVG is and what SVG is made of let’s start creating some SVG ofour own. The quickest and easiest way to ease into understanding SVG is by hand-codingyour first few SVG graphics. Hand-coding SVG graphics is actually not too difficult so takeout our magic keyboard, open your favorite text editor and follow along as we journey intothe land of Scalable Vector Graphics.This next example will be very short and simple – black rectangle.One of SVGs greatest assets lies in its ease of use. SVG is quite simple and you can createSVG without the use of a graphical authoring environment. Our first example of SVG showsthe basic structure of a complete SVG graphic/document.Line 1: <?xml version=”1.0” ?>Line 2: <svg>Line 3: <rect x="100" y="50" width="100" height="100" />Line 4: </svg>This code creates this shape: figure 1-10: rectangle with default fillLine 1: The XML Declaration and the XML version of this document.Line 2: Opens the SVG documentLine 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 Chapter 1 Introduction 15Line 4: Closes the SVG documentNotice that the default fill color is black. We will cover styling in detail in Chapter 5.SummaryCongratulations! You have just created an SVG-powered Web page. If you liked thisexercise then just hold tight because we will continue to expand your SVG knowledge. If youfound this exercise to be somewhat boring we will quickly be moving on to bigger and betterthings! Beauty is in the eye of the beholder.Up to this point we have quickly covered the main questions involved in creating, viewingand editing SVG without going into undue depth. In the next section we will continue topartake 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 bedealing with all aspects of using SVG on the Web. Also found in this book are a number ofgreat SVG images with the accompanying source code that should be of great value to bothdesigners and developers.In Chapter 1 we learned what SVG is and began to familiarize ourselves with the tools ofSVG. 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 Yodasays, “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 andpractice. But, in practice, there is."- Jan L.A. van de Snepscheut"Form must follow function."- Le CorbusierChapter 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’ ElementOverviewIf 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 presentationattributes and basic shapes, images and a little about text. We will cover all aspects of textprocessing in depth in Chapter 5. Mastery of these concepts will provide us with the buildingblocks for most everything that we will do with SVG.The SVG HeaderThe code below demonstrates the structure of a complete SVG document. The document iscomposed of the XML declaration, the DOCTYPE declaration, and the SVG DocumentFragment.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 efficientlystates this document conforms to the XML 1.0 specification, uses UTF-8 character encodingand depends on a Document Type Definition (DTD) external to the document to parsecorrectly. Where is this DTD located? The second line holds the secret to this information. Inthe second line, the ‘DOCTYPE’ states where the DTD is located and the name of thedocument element it will be applied to. In this case, the DTD is applied to a documentelement named ‘svg’. The DTD provides the grammar and rules for the document.
    • Learn SVG Chapter 2 Basic Shapes 2Let’s take a look at a sample that uses the complete SVG header and adds some SVGelements: 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, let’s take a closer look at the ‘svg’ element and new SVG elements we added to thecode.The basics of the <svg> elementAfter the doctype declaration is the ‘svg’ element. In our example, the ‘svg’ element containsall 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 widthattributes can also be used on some graphical objects such as rectangle elements. 2
    • Learn SVG Chapter 2 Basic Shapes 3 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 explorethese properties in the next chapter and throughout the book.Now, let’s 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 everyelement can have a title and description. The content of ‘title’ and ‘desc’ will not be displayedto the screen. 3
    • Learn SVG Chapter 2 Basic Shapes 4An interesting note in the SVG recommendation leaves the implementation of these elementsup to the implementers of the SVG processor. This means that some viewers may implementfunctionality for the ‘title’ and ‘desc’ attributes, some will not. For example, A SVG viewermay 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 behavesdifferently then ‘title’ attribute of HTML. But do not worry, using the SVG’s DocumentObject model and scripting we will show you how to create your own “tooltips”.Note to readerFor the rest of the book we will leave out the complete SVG header to help us focus on theSVG elements and attributes and improve the readability of the code. That being said, wehighly recommended that you always use the complete header in your own documents. So forreadability 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.) willbe used. This is due to the fact that the SVG working group is considering better alternativesto CSS units in future SVG versions. The SVG working group recommends avoiding theseunits today and so we will follow that recommendation. Instead we will not specify any unittype so that our SVG graphics will default to what is called user units. We will always referto our coordinates as user “units” rather than any specific CSS unit of measurement.Style PropertiesGraphical objects can be much more useful when they have been stylised. In this section wewill show how to apply a few of the most common style properties to shapes usingpresentation attributes. You can find a complete listing of all of SVG’s presentationattributes in Appendix B.Styling with CSS vs. Presentation AttributesStyle can be applied to SVG in a number of ways. Throughout this book we will be usingpresentation 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 areeasier to read and understand than CSS styles such as style="fill:red". Styling with CSS will becovered in Appendix B. 4
    • Learn SVG Chapter 2 Basic Shapes 5ColorsWe 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 youlearned about CSS color is the same for SVG! There are two main ways to define a color andthey 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 allyou 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 acolor 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 x="50" y="30" width="200" height="100" fill=”#fff” /><rect x="50" y="30" width="200" height="100" fill=”#ffffff” /><rect x="50" y="30" width="200" height="100" fill=”rgb(255,255,255)” /><rect x="50" y="30" width="200" height="100" fill=”rgb(100%,100%,100%)” />We have included a list of SVGs color keyword names and hexadecimal RBG notation in acolor chart in Appendix A.The ‘fill’ and ‘stroke’ propertiesLet’s take a look at how to use the ‘stroke’ and ‘fill’ presentation attributes. All of SVG’sgraphical objects have an outline and an interior space. The outline is called the ‘stroke’ andthe interior is called the ‘fill’.We can set an object’s ‘stroke’ and ‘fill’ property values through presentation attributes.‘fill’ PropertiesWhen 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 tofill graphical elements interior with the specified ‘paint’ value. 5
    • Learn SVG Chapter 2 Basic Shapes 6Fill Property Reference TableThe ‘fill’ properties include:fillfill-opacityfill-ruleEach of these properties is defined in greater detail here.Fill Properties:Property Descriptionfill 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 beingfill-opacity transparent that defines the opacity of a shape or text interior. A value of ‘nonzero’ or ‘evenodd’ that is used to determine interiorfill-rule for intersecting lines.fill-opacityThis is syntax definition for the ‘fill’ property.fill Value: <paint> Initial: black Applies to: Shapes and textual content Inherited: yes Percentages: N/A Media: visual Animatable: yesEach 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"/> 6
    • Learn SVG Chapter 2 Basic Shapes 7 <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: <opacity-value> | inherit Initial: 1 Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesThe ‘fill-opacity’ property sets the amount of opacity the interior of a graphical object willhave.The default opacity value is 1 (opaque) with 0 (transparent) being the lowest possible valuefor 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: nonzero | evenodd | inherit Initial: Nonzero Applies to: shapes and text content elements Inherited: Yes Percentages: N/A Media: Visual Animatable: Yes 7
    • Learn SVG Chapter 2 Basic Shapes 8The ‘fill-rule’ property determines the internal and external portions of a shape. Often this isstraight-forward but this becomes more tricky with complex shapes. This next examplecomes 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" /> 8
    • Learn SVG Chapter 2 Basic Shapes 9 <use xlink:href="#Triangle" transform="translate(950,188) rotate(120)translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) rotate(240)translate(107,0) rotate(90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) rotate(60)translate(49,0) rotate(-90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) rotate(180)translate(49,0) rotate(-90)" overflow="visible" /> <use xlink:href="#Triangle" transform="translate(950,188) rotate(300)translate(49,0) rotate(-90)" overflow="visible" /> </g></svg>Stroke PropertiesWhen 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-miterlimitEach of these properties is defined in greater detail here.Stroke Properties:Property Descriptionstroke A color value that defines the color of a shapes or text stroke. A number or percentage value that defines the width of a shapesstroke-width or text stroke. A number between 1.0 and 0 with 1.0 being opaque and 0 beingstroke-opacity transparent that defines the opacity of a shapes or text stroke. A set of user coordinate numbers that define the repeating dashstroke-dasharray and gap length of a stroke. A value of ‘butt’ (default), ‘round’ or ‘square’ that specifies thestroke-linecap stroke shape at the end of line segments. A value of miter (default), round or bevel that indicates the strokestroke-linejoin shapes of the corners of basic shapes and paths. A number >= less than 1 that defines the limit on the ratio of thestroke-miterlimit miter length to the stroke-linewidth.stroke and stroke-widthHere are the syntax definitions for each of the ‘stroke’ and ‘stroke-width’ properties. 9
    • Learn SVG Chapter 2 Basic Shapes 10stroke Value: <paint> (See Specifying paint) Initial: none Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesstroke-width Value: <length> | inherit Initial: 1 Applies to: shapes and text content elements Inherited: yes Percentages: Yes Media: visual Animatable: yesIn this example we have used presentation attributes to apply stroke color and stroke-widthproperties to the lines. Figure 2-7. Stroke property<svg> <!-- 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 towhich it is applied. 10
    • Learn SVG Chapter 2 Basic Shapes 11stroke-opacity Value: <opacity-value> | inherit Initial: 1 Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesThe stroke is always centered on the outline of the graphic object. This means that half of thestroke is on the inside of the graphic object and the other half of the outline is on the outsideof 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 propertieswe can easily create some interesting effects. We have made what seem to be three differentrectangles. When adding style to graphic object some interesting scenarios can develop. Forexample, what would happen if the ‘stroke-width’ property value were greater than theinterior space of the graphic object? Try it. As you might have guessed, the stroke canconsume the interior space and completely paint over the shapes fill.stroke-dasharraystroke-dasharray Value: none | <dasharray> | inherit Initial: none Applies to: shapes and text content elements 11
    • Learn SVG Chapter 2 Basic Shapes 12 Inherited: yes Percentages: yes (see below) Media: visual Animatable: yes (non-additive)Using just the stroke-dasharray we can create the following types of dot-dash patterns alongthe 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 setthe fill=”none” to prevent a thin line from being displayed along the length of the line.stroke-dashoffset Value: <length> | inherit Initial: 0 Applies to: shapes and text content elements Inherited: yes Percentages: see prose Media: visual 12
    • Learn SVG Chapter 2 Basic Shapes 13 Animatable: yesThe stroke-dashoffset can be used to effectively move the start position of the ‘stroke-dasharray’. The ‘stroke-dasharray’ property also allows the stroke to be segmented as shownin 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 ‘stroke-dashoffset’ property so that they are centered along the length of rectangle’s 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 14The ‘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 designsand animations, as we will see later in this book.stroke-linecap Value: butt | round | square | inherit Initial: butt Applies to: shapes and text content elements Inherited: yes 14
    • Learn SVG Chapter 2 Basic Shapes 15 Percentages: N/A Media: visual Animatable: yesThe default ‘stroke-linecap’ property value is ‘butt’ specifies the shape to be used at the endof open path. Setting the stroke-linecap value to ‘round’ creates a small semi-circle at the endof the line. The last possible value for the stroke-linecap property is ‘square’ and this extendsthe 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: miter | round | bevel | inherit Initial: Miter Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yes 15
    • Learn SVG Chapter 2 Basic Shapes 16The 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 thisexample. 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 let’s move on to SVG BasicShape elements.Basic ShapesWherever 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-madethings like symbols, clothes or computers. SVG allows us to easily model our world using sixpredefined intuitive shape elements.The basic shape elements are:rectcircleellipselinepolylinepolygonEach 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>Lets cover each of the shape objects in detail.LinesThe ‘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 18The first lines start-point begins 30 user units from the left and 80 user units from the top ofthe SVG document. The end-point is 160 user units from the left and 20 user units from thetop.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 automaticallyrendered as if they were equal to zero. Likewise, as you can see in the example above, if thex1, y1 and x2, y2 value pairs are the same or if they are not specified then the line will notdisplay.Line Element DesignsHere 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>CirclesThe 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’ valuespecifies the radius of the circle.For example if you want to create a circle with a diameter of 80 user units then you need toset 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 notappear in the image as shown in this example. Figure 2-20. Circle designs<svg width="350" height="300"> <!-- 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 oreven planets as we’ll see later in this book.Circle Element Designs 21
    • Learn SVG Chapter 2 Basic Shapes 22Here are some useful techniques for creating fascinating designs using only one or two‘circle’ elements. Figure 2-21. Amazing shapes with the circle elementThere 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 concentriccircles each</text></svg>Rectangles 23
    • Learn SVG Chapter 2 Basic Shapes 24Rectangles take four geometric attributes: (x, y, width, height)The ‘x’ (distance from the left) and ‘y’ (distance from the top) attributes define the position ofthe top-left corner of the rectangle while the ‘width’ and ‘height’ attributes define the breadthand 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 elements top left corner aligns with the image areastop left corner. The ‘rx’ and ‘ry’ geometric attributes are optional but they can be used definethe distance that should be "rounded off" from each of the four corner edges of the rectanglein the horizontal (rx) and vertical (ry) directions. For example take a look at this next SVGimage. 24
    • Learn SVG Chapter 2 Basic Shapes 25 Figure 2-23. Rectangle element designs<svg width="500" height="300"> <!-- 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 thenthe 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 userunits. This is demonstrated in the rectangle element that is horizontal in the example above. 25
    • Learn SVG Chapter 2 Basic Shapes 26EllipsesThe ‘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 ofthe ellipse while the ‘rx’ and ‘ry’ values specify the x-axis and y-axis radius of the ellipseelement.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 thevalue of the ‘rx’ attribute equal to 35 as in this next example. Figure 2-25. Ellipse element designs<svg width="350" height="300"> 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 inSVG. However, if either of these values is set equal to 0 then the ellipse and ends up lookinglike 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 collapsingupon itself and therefore renders as if it were a line.Polygons and PolylinesThe polyline and polygon ‘points’ attribute allows for multiple numbers of (x,y) coordinatepairs. 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 Chapter 2 Basic Shapes 28</svg>Note to readerMake sure you specify an even number of coordinate values. That is, for every x that youspecify be sure to define a corresponding y coordinate. Normally your SVG authoringenvironment will handle this for you.PolygonsPolygons 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 DesignsHere 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 triangleeach</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 triangleseach</text></svg> 30
    • Learn SVG Chapter 2 Basic Shapes 31PolylinesTake a look at the grammar used to describe the following polyline shape elements. Figure 2-30. Polyline element designs<svg width="350" height="250"> <!-- 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 shapecoordinates. Also, notice that if you follow the black stroke line it does not automaticallyclose the shape as the ‘polygon’ element automatically does. Polyline shapes are closed onlywhen 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 justthe same coordinate twice in a row? Well, surprisingly the polygon would not even berendered as a dot in the image.Even with this simple example you can begin to see how inefficient it is to hand–code thepoint’s element data. For example, imagine how many of the polyline “points” coordinateswould 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 developedwhich will generate most of the world’s SVG graphics. For the purpose of learning, it is not abad idea to type in the samples. 31
    • Learn SVG Chapter 2 Basic Shapes 32Cool Shapes ChallengePresentation attributes provide us with a tremendous amount of creativity, as you saw in the‘line’, ‘circle’ and ‘polygon’ designs.The ChallengeTry design a set of unique designs using only presentation attributes and three or lesselements from any of SVGs basic shapes. Email your best designs to dev@learnsvg.com andwe will post them on our website. You may even win the trendy Learn SVG T-Shirt!Basic Shape Elements ReferenceHere is a basic reference containing a list of each of the basic shape elements and theirrequired and optional attributes.Shape Element Required Optional Attributes AttributesLine <line> (none) x1, y1, x2, y2Rectangle <rect> width, height x, y, rx, ryCircle <circle> R cx, cyEllipse <ellipse> Rx, ry cx, cyPolyline <polyline> pointsPolygon <polygon> pointsFuture Shapes?A few other shape elements such as arc (open, closed, pie slice), spiral, star and regularpolygons are currently being considered for inclusion in the next version of SVG but we willnot pontificate on them here.This is cool stuff. It’s 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 hasa ‘path’ element that is the most powerful shape element that can be used to render each of theother shapes and even the most complex paths. In actuality, shapes and paths aremathematically equivalent and the reason why the SVG Working Group included all six ofthe shape elements was in part for our ease of understanding and use. We will be coveringthe ‘path’ element in greater detail in Chapter 4. 32
    • Learn SVG Chapter 2 Basic Shapes 33The ‘image’ ElementRaster ImageSVG is a unique type of graphic in that it can contain a variety of file formats. SVGdocuments can contain other SVG documents as well as JPEG and PNG raster graphics. PNGand JPEG images can be transformed, animated or even controlled dynamically andinteractively 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 thetop-left corner of the image. The ‘width’ and ‘height’ attributes define the scale of the imageand 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 HTMLIn order to use images in HTML we use the ‘img’ element with the ‘src’ attribute. SVG ismuch the same. In order to reference images in SVG we use SVG’s ‘image’ element. Justlike in HTML, in SVG the ‘width’ and ‘height’ attributes can be used to set the specific scaleof JPEG and PNG images. The attribute we use to reference the specific path to the imagefile or information is ‘xlink:href’. The “xlink:” is referencing a namespace which we will bediscussing in depth in Chapter 11. For now just think of the ‘xlink:href’ as being the same asHTML’s ‘src’ attribute.Supported Image TypesSVG’s ability to precisely position and rotate and transform images makes SVG ideally suitedfor displaying raster images. Currently, PNG and JPEG images are the only images that theSVG specification requires that SVG viewers support.Web developers will find that the JPEG and PNG raster graphic formats will remainimportant formats due to the fact that JPEG and PNG raster images excel at displaying certain 33
    • Learn SVG Chapter 2 Basic Shapes 34detailed graphics that would be inefficient for SVG to render mathematically. JPEG is stillthe crème-de-la-crème image format for photographic and other high-quality images.Note to readerNot all SVG viewers will necessarily support GIF images. This is not as terrible as it mightsound. PNGs serve as an excellent replacement for GIFs in most regards (except for animatedraster images) and can now be generated or exported from most all graphic designapplications. As of this writing the SVG Viewer plug-in does support the GIF image format.Relative and Absolute Directory PathsIn 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 theSVG Viewer.Relative paths can be tricky to keep track of and maintain. If you ever notice missinggraphics then the path that is specified in the ‘image’ element’s ‘src’ attribute value is the firstthing to check. I have created several folders under my Web site’s root folder so my directorystructure is a follows:root images script stylesheets svgAs you can see the folder structure organizes the style sheets, script, and various types ofmedia 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 logoimage file that is in the img folder we need to specify the following path in our ‘image’element’s ‘src’ attribute value: “../img/logo.jpg”. Just as in HTML the two dots that precedethe “/img” directory path are used to move up one level in our Web site’s directory structurebefore moving down into the “/img” directory where our “logo.jpg” file is stored.<image xlink:href=”../images/logo.jpg”>Dissecting an SVG ImageDesign time! It’s time to stimulate the other side of our cerebral mass. First, put on some ofyour favorite music and get ready to play. Now let’s fire up our favorite SVG authoringenvironment and get started. We’re going to dive into the more practical aspects ofcreating/authoring each of these shapes using SVG authoring environments. So, fire up thoseSVG authoring environments so we can begin to “get down” with the funkiness of SVG!Now we’re ready to take a look at the source code of the SVG image that we saw at thebeginning of Chapter 1. Now that we have a feel for the structure of SVG and we also knowhow 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 howSVG works. 34
    • Learn SVG Chapter 2 Basic Shapes 35 Figure 2-32. Illustration of SVG capabilitiesFull SVG CodeHere 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>That’s it!If you look through the SVG code you will quickly notice some recognizable terms such ascircle, text, line, image, style, stroke, fill and opacity. Undoubtedly there are several otherterms 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 throughoutthis book through a host of brilliant examples, tutorials, scenarios and even advancedapplications.As with life, the beauty is in the details so let’s briefly look at some of the SVG code thatproduced the above SVG graphic.Lines used for vector arrowsLines 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’ elementis used to contain graphical objects that are not intended to be displayed directly but rather arereferenced 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 patternThis 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 scalabilityHere we use the ‘use’ element to demonstrate the ability to scale a ‘circle’ element. <!--SCALABLE--> <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)"/>Once again we are referencing the ‘circle’ element that is located in our ‘defs’ element. Inthis 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 38We will be looking at the powerful transform attribute in depth in Chapter 6.Text ElementWe also made use of the ‘text’ element to display the text “SCALABLE VECTORGRAPHICS”.<!--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 – XMLAt this time we thought it would be appropriate to give some free sponsorship and thanks toour sponsors at eXtensible Markup Language (XML) since they provide the grammar thatprovides 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 ofmarkup-languages, such as custom XML "vocabularies", industry-namespaces, etc. whichwork hand-in-hand with other XML-namespaces including the styling-language XSL, thetransformation-language XSLT, XML Linking Language (Xlink) and many other XMLapplications.Designers are able to output XML grammar from design authoring environments, developerscan write programs to structure, manipulate, and manage the files, and publishers can easilymodify the XML text documents and assign CSS or XSL style-sheets. This is a new systemof 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 vector-animations. We will discuss XML in greater detail throughout this book.Summary 38
    • Learn SVG Chapter 2 Basic Shapes 39In this chapter we introduced several key concepts and terms including basic shape elementsand supported raster image types.In the next chapter we will take an in-depth look at the structure of SVG documents. But, asis the case with all new entities that we encounter, in order to derive the greatest benefits it isnecessity that we digest in portions, so feel free to lay back and rest on your laurels for a bit. 39
    • Chapter 3 : Document StructureBenefits 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 don’t 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 SVG’s structuring elements, which we will alsodesignate as container elements. Let’s start directly into this with an example. Suspend disbelief for amoment, escape the world of design and assume that you are a pallet rack manufacturer, in fact a palletmanufacturer with a penchant for graphical presentations of your products.Below is a pile of your produce. Figure 3-1. The pallet rackNow, 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 2 <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 you’ve 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 doublethe size of the first, an improvement — after all, both render the same graphical output. Rememberthough, that we wanted a more meaningful document, and indeed — the longer you look at the seconddocument’s code, the better we can understand its structure — consisting of racks, upright posts andbeams, it is somehow both self-referential and self-explanatory. I won’t discuss the SVG key featuresused in detail here since we will do this in the rest of this chapter.Quick ChangeJust to demonstrate the increased functionality of our second piece of code, let’s suppose we wanted toinclude the following adjustments: • A rack with stronger beams • A red rack • A rack with one more column 2
    • Learn SVG Chapter 3 Document Structure 3 Figure 3-2. Pallet Rack Adjustements1. 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 isn’t it! So, as a generalization, Structure in documents is the way forward.Another optionSo, now that you are now deeply impressed by the potential power of structured documents, but stillcomplaining about the increased file size, take a look at this third document. It results in the samegraphical 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 don’t want to explain the content in detail, but here are some useful characteristics of thedocument. 3
    • Learn SVG Chapter 3 Document Structure 4 • The file’s 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 — It’s a bluff. As we need the code in the external file, we didn’t actually reducethe total code size.OK. You’re right, to an extent. But the benefit of evacuating SVG elements into external files comes withthe magic of sharing code. As you (the pallet manufacturer remember) have to handle not only one rackimage, but several hundred different ones, all those different SVG documents will refer to that one singlefile. That is real code reduction.Reusing Elements Let’s have a closer look at how SVG’s 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 SVG’s 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" /> 4
    • Learn SVG Chapter 3 Document Structure 5</svg> It works, thanks to SVG’s 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> element’s 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 it’s id, so we need to provide id attributes forall elements we want to refer to by <use>. Bear in mind that the id’s values must be unique across thedocument. Since the id’s value must be an XML URI (uniform resource identifier), we can reference anyelement in any SVG document across the web. Most often you will access elements in your localdocument (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 inxlink:href="http://www.w3.org/TR/2001/REC-SVG-20010904/images/struct/Use01.svg/#xpointer(id(MyRect))" or by a relative URI as inxlink:href="../svglib/Vehicels.svg#xpointer(id(Motorcycle))"Using the x and y attribute, we can position our duplicated element in the drawing, and methods ofinterpreting the attributes values will be discussed later in the chapter, where we examine coordinatesystems and transformations. For now, simply add the x and y values to the coordinates of the referencedobject 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 referencedoriginal.One drawback of utilizing the <use> element is that we are unable to manipulate the original referencedelement’s attributes. While we may make adjustments to the instance we are dealing with, the originalwill remain the same. We can duplicate it and put it at a different place in the document, but that’s 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. 5
    • Learn SVG Chapter 3 Document Structure 6 • 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 NothingLets 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 didn’t change anything so far, and still want to focus on the structure of the beams.Spot the difference Just looking at the image it’s 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" /> 6
    • Learn SVG Chapter 3 Document Structure 7 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, we’ll need to change the beam’s 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 didn’t have to accommodate several hundred beams! OK. So what did we just learn? The advantage, that the change of an element’s attribute is transparent to all referencing <use> elements, became a disadvantage here. It would be best, if we didn’t 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" /> 7
    • Learn SVG Chapter 3 Document Structure 8 </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 SVG’s 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”> <!-- group’s 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" /> 8
    • Learn SVG Chapter 3 Document Structure 9 <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 don’t see any sensational shift. Nevertheless, we will benefit from this structuralimprovement soon. A look at the SVG code shows nothing magical. To build a group, just enclose thegraphic 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 GroupsThe usefulness of the <g> element is largely increased by it’s 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 tocreate a real world pallet rack. Figure 3-8. More elementsHere 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> 9
    • Learn SVG Chapter 3 Document Structure 10As we learned in the section about element reuse, we put the column group into a <defs> section. Now wehave only five elements that create graphical output: One instance of uprightPost and three instances ofcolumn. 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 thereferencing of elements from other local files or even across the World Wide Web via thexlink: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>andRack.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 whereRACK.SVG resides.We have just stepped over the point of no return. No longer will you be able to cope without groups inyour SVG files. And since we are getting used to using them, let’s now have a look at structuring ourdocuments with a number of groups.Nested GroupsRemember that I mentioned that a group, as a container element, can collect other SVG elements. Notonly graphics elements, but also container elements — in particular other groups. With that we havegroups inside of groups or nested groups. You may be quite uncertain now, how to reference nestedgroups or why you should have nested groups at all. Before we discuss this further, let us explore thenesting of groups with our familiar rack example. 10
    • Learn SVG Chapter 3 Document Structure 11Nesting our pallet groupsThe images in the brochure of your company always have a floor-segment drawn under the rack. Tovisualize this floor-segment we use a black line and a grey rectangle. Furthermore the beams are missingsome details — the fasteners.Ok, we’ll 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 isn’t affected if we modify this beam.3. We’ll also define a new group ‘rack’ out of the starting upright post and all columns. We’ll add the floor-segment’s line and rectangle too. Figure 3-9. Rack with floor4. 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, itlooks somewhat unstructured. The rectangle and the line belong logically together. So we feel, we shouldhave a group ‘floor’. 11
    • Learn SVG Chapter 3 Document Structure 125. 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 itbe it better placed inside of the <defs> section? Well, we won’t reference this group, so we do notnecessarily need to add it to the <defs> section. But perhaps we should think more about where this floorsegment 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 rackimages share floor space”. Fine, so the floor group can go into the rack group. It’s 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 you’re wondering why I inserted the floor group at the beginning of the rack members, rather thanappending it at the end, I must say here, it’s 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 groupmembers alternatively. Please also note, that we needed to modify the line’s and rectangle’s coordinates alittle (we subtracted the coordinates of the last <use> element). This will become more transparent inChapter 6, where we will talk about coordinate systems and transformations.After looking at the SVG code, you may question: “Why didn’t we define the beam’s group also inside ofthe column’s 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 13Here we could not simply transfer the beam’s group into the column’s group. We had to create a local<defs> section first. Why? Well, we learned, that everything in a <defs> section will not get rendered, itis for referencing only. So what, if we reference the column’s group without its internal <defs> section?Correct – the internal beam’s 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 didn’t we just leave the beam where it was? The answer is (as you shouldbe 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 rulesHere 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 GroupsThe 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 14Let’s 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 hasn’t? 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 apresentation attribute or via CSS styles. This colour will remain unaffected. Only those elements, thatdon’t 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 definethis style by the group. Moreover, if we have to deal with a lot of elements with common style, we shouldeven consider enclosing these elements in a group just to share that style.4. Just to be sure that this works also with nested groups, we’ll 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 outergroup as expected.Please note, that – for simplicity – I use presentation attributes only here in this chapter. Using CSS stylesinstead, 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 rack8. Let’s 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>We’ve just omitted every occurrence of fill="steelblue" stroke="black" and given those attributes tothe rack’s group instead. It works great and we’ve significantly reduced the size of our document.But what if one of your customers wants the middle column moccasin-coloured? An unusual request, butas a simple pallet supplier, ours is not to reason why! Figure 3-14. Changing color of beamsThis 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 didn’t tell the column group toget moccasin-coloured. We told one instance of the column group to get moccasin-coloured. So how doesthe <use> element influence the group’s 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 presentationattributes from a referencing <use> element to its contained elements, as long as the group itself does nothave that particular presentation attribute defined. In that case the group becomes opaque and blocks thestyle. Therefore the CSS inheritance rules also apply to group instances. 16
    • Learn SVG Chapter 3 Document Structure 17Lets see how this adds to our rapidly expanding structure knowledge. What do we know now? • Group elements inherit the parent group’s style. • Group elements also inherit the parent group’s 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 group’s instances, rather in the group itself.SymbolsSVG provides us with another structuring element, the <symbol> element. It is another container elementlike 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> element’s 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” > <!-- symbols’s 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 symbolThe symbol consists of a circle – the head – and a path element – the arms, body and legs. We reuse thesymbol by the <use> element, that defines a rectangular area 100 units wide and 100 units high. We alsoprovide a true rectangle just to show the borders of this area.The viewBox attribute establishes a new coordinate system, into which the symbol’s graphic elements aredrawn. We will discuss the viewBox attribute in more detail in Chapter 7. Just notice here that theviewBox’s rectangle exactly meets the use’s rectangle here initially.2. Now we want to play a bit with different sizes. So let’s enlarge the use’s 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 rectangleAs we see, the symbols content is scaled non-uniformly so that it fits into the use’s rectangle.To change that behaviour, SVG provides us with a lot of other values for the preserveAspectRatioattribute. Let’s meet one of them3. 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" preserveAspectRatioAny value for the preserveAspectRatio attribute other than "none" will result in a uniform scale of theviewBox’s rectangle.The xMidyMid value instructs the SVG rendering engine to coincide with the midpoints of the viewBox’sand the use’s rectangles. The second value “meet” results in a scaling so that the complete viewBoxrectangle fits into the use’s 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" preserveAspectRatioA second value “slice” causes a scaling so that the viewBox rectangle completely fills out the use’srectangle.I won’t cover the numerous variants of the preserveAspectRatio attribute’s values here. If you areinterested, I suggest, that you look into the SVG specification. There you will find a complete explanationof all variants with an example.All together nowI don’t 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. Afterthat 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 we’ve just discussed here. 19
    • Learn SVG Chapter 3 Document Structure 20Finally, I recommend that whenever you define a symbol element, to put it into a <defs> section. Thisresults in good SVG coding style as everything that is referenced should go into a <defs> section.PatternsLet’s go back to our rack example. Perhaps our theoretical foreman has been complaining about thevisual appearance of the upright posts. The real upright posts don’t 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 let’s try it out and have a quick look at the pattern’s 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” > <!-- pattern’s content here --> </pattern>With the <pattern> element we have yet another container element. It is quite helpful to think of patternsas 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 21One pattern tile consists of a lightgray square with a size of 50 units and a centred blue circle. When wefill the 200 units wide and 150 units high rectangles with these pattern tiles, we are a bit surprised toachieve 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 onlyshine through those shapes, that are using the tiles for filling. Just to test this, we move the rectangles alittle 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 bythe pattern fixed with object to fill, we can use the fact, that every group establish an own coordinatesystem. We will discuss this more detailed in Chapter 7. So all we have to do now, is to enclose onerectangle 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 Chapter 3 Document Structure 22 </svg>The pattern’s 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>MarkersVery delighted about the new look of the upright posts you say: “ And if we finally could add dimensionsto the racks, SVG would be appropriate for our new brochure.” 22
    • Learn SVG Chapter 3 Document Structure 23Ok, so let’s 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” > <!-- pattern’s content here --> </marker>The <marker> element like its companion – the pattern – is a container element. Since we want to attacharrowheads 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 methodhere.Starting to make a marker, we first create a little sketch of it. We mark the origin of our locale markercoordinate system with (0,0). This is also the marker’s point, that will be placed onto the line’s start- ,mid- or endpoint. Then you designate the dimensions of the marker’s bounding box. Given these, you canthen determine the coordinates of the bounding box’s upper left corner with respect to the marker’scoordinate system. 23
    • Learn SVG Chapter 3 Document Structure 24 1. Fill the viewBox attribute with the coordinates of the bounding box’s upper left corner, its width and its height in exactly that order. 2. Give the markerWidth attribute the value of your bounding box’s width. 3. Give the markerHeight attribute the value of your bounding box’s height. 4. Create the <marker>’s contained elements using coordinates with respect to the marker’s locale coordinate system’s 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-endattributes. With the help of these attributes we can assign separate marker symbols to the start-point, theend-point and all mid-points.So let’s 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 alignthemselves to the line’s 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, youmight use markerUnits="strokeWidth" instead.Visibility of GroupsYou may not always want to have all elements of an SVG document visible at every time. To change thevisibility control of certain elements you have to make some changes to your document structure. Thebest 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 elementsthat should become visible/invisible in one group.SVG or exactly CSS2 provides us with two presentation attributes display and visibility to control thevisibility of elements. I recommend, to use the visibility attribute with a group, when you want tocontrol the visibility of the contained elements.. With that we can override the visibility attribute forparticular group members. 25
    • Learn SVG Chapter 3 Document Structure 26Read the Chapter 11.5 of the SVG recommendation, if you want to learn more about the differencesbetween the display and visibility attributes.Now assume, we want to control the visibility of the rack’s 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 don’t 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 : CurvesWhen you are surfing the Web, it is not unlikely that you will come across some interestingSVG graphics. Since you find them interesting you will – as you can always do with a webpage – inspect the graphics source code. Doing this, there will be a high probability, that youwill find an SVG document dominated by <path> elements. This indicates most often, thatthe graphics was generated by a program, as opposed to hand-coded SVG. As with HTMLpages, it is the normal way to use authoring software to create vector graphics. SVG contentwill also be quite often generated by serverside scripts or translated from semanticallyhigherlevel XML documents via XSLT. SVG renderers know of the importance of <path>elements and will usually optimize the processing performance of paths. Given this, SVGexport by programs will often rely on that perfomance advantage of paths and prefer thoseover basic shapes. Since we want to be able to do modifications or finetune these content byhand or simply want to understand it, we therefore need some insights into the <path>element’s internals. That is what we want to explore in this chapter.So what’s 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 doesn’t matter and as longas you find an equivalent basic element at all. For all other cases we get forearmed now by acloser 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 somewhatof pen plotter software functions – and the PostScript language. Yes, we really need to learn aspecial path syntax, because the wise W3C decided to put all information about the pathgeometry into a single attribute. As I told you, they did that in order to allow for minimal filesize and efficient downloads. On the other side comes a drawback with this benefit. SVGparsers need not only to parse XML content, they also have to parse this special complexpath data attribute via some kind of microparser. However, here is the <path> element syntaxat first.
    • Learn SVG Chapter 4 Curves 2Syntax: <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 theoutline of the shape or curve. The pathLength attribute doesn’t change the real length of thepath. It merely helps us, to normalize the path’s length to a value, with which we can processpoints on the path much simpler. With the help of that you can say: “Whatever the exactlength of the path is, I assume it has the length 100. And now I want to do something at thepath 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 apath.Drawing a Path using LinesNow we need to know how to define the path’s outline. For this we have a closer look at thepath data contained in the d (data) attribute’s 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 group’s 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 pointSyntax: lineto L|l x, y x = x-coordinate of new point
    • Learn SVG Chapter 4 Curves 3 y = y-coordinate of new pointSyntax: closepath Z|zSo 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 linesHere 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 InstructionM 40,40 Move the pen to (40,40) and start a new sub-pathL 40,80 Draw a line segment from the current point (40,40) vertically down to the new point(40,80)L 100,80 Draw a line segment from the current point(40,80) horizontally to the new point(100,80)L 100,40 Draw a line segment from the current point(100,80) vertically up to the new point(100,40)M 40,30 Move the pen to (40,30) and start a new sub-pathL 70,10 Draw a line segment from the current point(40,30) to the new point(70,10)L 100,30 Draw a line segment from the current point(70,10) to the new point(100,30) Close the sub-path with a line segmentZ 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 4We 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 theexample 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 path’s 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 wedid 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 efficientdownloads in mind. So we should not be surprised, that the wise W3C provided another set oflineto commands for frequently used special classes of lines – the horizontal and verticallines.Syntax: horizontal lineto H|h x = x-coordinate of new pointSyntax: vertical lineto V|v y = y-coordinate of new pointWith 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 don’t need to specify the x-coordinatewith the vertical lineto command. Given this we can rewrite our example from Figure 4-1 andyield 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 usefulwith it. Fine, so let’s design a car. As lines are the only segment types we know so far we willbase our first car design on lines then.
    • Learn SVG Chapter 4 Curves 5 Figure 4-2. Linear CarSince we want to evolve our car into some more challenging designs, we need its completecode 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 ArcsYou 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: TheSVG 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 acommand.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 6 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 SegmentFigure 4-3 illustrates the arc segment’s data. The arc is part of an ellipse that starts in thecurrent point and ends in the new point with the coordinates x and y, which are the arcsegment’s last two values. Now we position a coordinate axis into the center point of theellipse 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 segmentvalues rx and ry. Since there is no restriction, which of these two values is greater than theother, we call these values x-radius and y-radius instead of semi-major and semi-minor axisradius.The arc segment’s third value x-axis-rotation specifies the angle in degrees between the path’sreference coordinate system’s 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 translate-transformation so, that the ellipse passes through the current point and new point again(Figure 4-4). Figure 4-4. Rotated Elliptical Arc Path SegmentThere are cases, where the ellipse’s measurements specified by rx and ry are too small to fitbetween the path points. Then the radii are scaled up so, that the ellipse will fit and the ratio
    • Learn SVG Chapter 4 Curves 7of rx and ry remains constant. Figure 4-4 shows an ellipse, that fits with a x-axis-rotation ofzero but doesn’t fit any more with a non-zero angle. Figure 4-5. Rotated and Auto-scaled Elliptical Arc Path SegmentThe ellipses in Figure 4-3 to 4-5 were drawn all with a solid and a dotted segment. What, ifwe want to choose the dotted arc as our path segment. For this SVG provides us with thefourth segment value large-arc-flag and the fifth value sweep-flag. In fact we can draw notonly 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 showingthese. Figure 4-6. Four possible elliptical arcsWith this we now have the choice of four elliptical arc segments. Two small ones and twolarge ones, two with positive angular orientation (clockwise) and two with negativeorientation. 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 andfs = 1 : negative.I want to mention also, that for the special case with the end point coordinates (x,y) equal tothe current point’s coordinates the arc will not get rendered. Since this behaviour is not muchintuitive with the large-arc-flag set to 1, this might be changed with SVG 2.0.Let’s practice what we learned about the elliptical arc and create a simple spiral.
    • Learn SVG Chapter 4 Curves 8 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 CarYou will rarely use the elliptical arc with SVG handcoding. For this we usually have thesupport of high sophisticated graphical authoring tools. But there is a very important specialcase of the elliptical arc that is of high practical use. Let’s now have a closer look at thecircular arc.Circular ArcA circular arc is simply a special case of the elliptical arc. Since circular arcs are quitefrequently used in technical drawings, I want to show you a comfortable way to hand-codethese arcs using the path element
    • Learn SVG Chapter 4 Curves 9 Figure 4-9. Four possible circular arcsSyntax: 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 pointNeedless to say that you don’t have two radii with the circular arc. So the first two values ofarc command are always identical – the arc’s radius. Also you do not need to rotate a circleas you might want to do with the ellipse. Consequently we can always set the third value tozero.As with the elliptical arc we also have four possible circular arcs shown in Figure 4-9. Figure 4-10. Circular Arc using Center ParameterizationConsistent to its current point policy for defining paths, SVG is using the so called endpointparameterization for describing arcs. That simply means that a circular arc – as well as itselliptical brother – is defined by its endpoints plus some more additional values.For single arcs this technique is not very convenient. Using the center parameterization hereis 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. Aswe much likely will have an arc element in SVG 2.0 we should be not surprised, if it weresimilar to our <circularArc> element.What we need now is a simple way to emulate the circular arc via the <path> element, i.e. touse the <circularArc>’s attributes without intensive conversion calculations with the pathelement. 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 withonly minimal math. These are the conversion steps: 1. use the center coordinates as the arguments of the path’s 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 alsoarc 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 11 Figure 4-11. Circular Arcs<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 don’t want to finish this chapter about circular arcs without having designed a car from thosealso. Figure 4-12. Circular CarSplinesThe term spline comes from drafting, where a spline is a flexible strip guided by points on apaper, used to draw a smooth curve through those points.Today we associate this term with a convenient mathematical method for drawing curves orsurfaces in two or three dimensional space.Approximating vs. Interpolating Splines
    • Learn SVG Chapter 4 Curves 12Any spline is based upon a set of control points. The lines connecting these control points inorder are called the control polygon (characteristic polygon) or control graph.The various methods of spline drawing can be divided into interpolating splines, where thecurve is forced to pass through all control points, and approximating splines, where thecurve not necessarily needs to do so.The SVG work group decided for version 1.0 to confine to a special but very common type ofapproximating splines – the Bézier splines. But we can expect to get general splines withSVG language version 2.0.Bézier SplinesThe mechanical engineer Pierre Bézier was working for the Renault car company. By 1960 hehad to solve the problem of describing a best fit curve that would be easy to use and exactenough to meet the tolerance demands of manufacturingthe car body. He accomplished this with the help of cubic polynomials.Bézier curves, in their two-dimensional form, are now the basis of almost all commongraphics programs (such as Adobe Illustrator and Corel Draw), following their adoption as thestandard curve of the PostScript language. Most outline fonts, including TrueType are storedas Bézier curves. In order to create a Bézier spline we need at least 3 points. To be exact, it isalso 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 ofinteractive computer graphics quadratic Bézier splines (three control points) and cubic Béziersplines (four control points) interspersed with the time. Since curves usually have more thanthree points, these curves are then composed by sequential quadratic or cubic Bézier splinepatches or segments. We will use the term polybézier for a curve with sequential Bézierspline segments. This concept of a polybezier comes with the high desirable benefit, that achange of any control point in one spline segment does not influence the other segments’curves.Quadratic Bézier Spline Figure 4-13. Quadratic Bézier Spline SegmentTo better understand the concept of the quadratic Bézier spline segment, we start with asimple line from point P1 to P2 and add a third point C12 not on this line forming a triangle.The Bézier curve passes through the control points P1 and P2, but will only approximate thecontrol point C12. Here the imagination is of some help, that C12 acts with a certain
    • Learn SVG Chapter 4 Curves 13gravitational force onto the originally straight line and deforms it elastically into a smoothcurve.I want to show you an illustrative geometric approach to create a quadratic Bézier splinesegment. We start again with the triangle P1,C12,P2. Figure 4-14. Quadratic Bézier Spline CreationWe mark a point A1 at 30% along the line from P1 to C12. Then we find another point A2 at30% along the line from C12 to P2. Connecting these points with a new line we set again apoint B at 30% along this line from A1 to A2. This point B is now a point on our quadraticBézier 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 simpleparabola. 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 Bézier spline works, we still need to know, howSVG is helping us to create it via the <path> element.For this we introduce here the absolute and relative quadratic Bézier curveto Q and qcommand.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 pointThe Q command specifier is followed by two pairs of x-/y-coordinates. The first onedetermines the control point and the second one is the end point of the Bézier segment. Let’sapply this path command to generate a smooth curved vase.
    • Learn SVG Chapter 4 Curves 14 Figure 4-15. Vase using quadratic Bézier 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 Mcommand. Then we add a quadratic bézier curveto Q segment with the control point (50,120)ending in (80,60). From here we continue with another Q command approximating the controlpoint in (90,40) to the point (80,20).Please note, that we wanted to preserve the smoothness of the curve, when going over fromthe first spline segment (body?) to the second one (neck?). To accomplish this we need tohave the tangent at the first spline’s endpoint equal to the second spline’s startpoint. And forthis a curve point’s preceding control point, the curve point itself and the succeeding controlpoint 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 directionSince a smooth junction between two spline segments is a very common demand, SVGprovides us with a special simplifying smooth quadratic bézier 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 pointsThe T command specifier is simply followed by a pair of x/y-coordinates setting the end pointof the Bézier segment. The ommitted control point is automatically created from the previouscontrol point by reflection relative to the path’s current point.
    • Learn SVG Chapter 4 Curves 16Let’s now apply the quadratic Bézier spline to our car. Figure 4-18. Quadratic CarCubic Bézier Spline Figure 4-19. Cubic Bézier Spline SegmentThe cubic Bézier spline segment comes with one additional control point compared to its littlequadratic sister. With this extra burden – we have to specify one more point even if we use agraphics editor – comes the benefit of a more versatile curve.The Bézier curve starts in point P1 heading straight for C1. But it is only approximating C1with a direction towards C2 and after having approximated C2 it is finally arriving in P2coming from the direction of C2. Here again the imagination helps, that C1 and C2 are actingwith a certain gravitational force onto the originally straight line P1,P2 deforming it into asmooth curve.Analogical to the quadratic Bézier spline we want to have an illustrative geometric approachto create a cubic Bézier spline. Here we start now with a quadrangle P1,C1,C2,P2.
    • Learn SVG Chapter 4 Curves 17 Figure 4-20. Cubic Bézier Spline CreationWe start again marking a point A1 at 30% along the line P1,C1. We repeat this for the linesC1,C2 and C2,P2 and yield the new points A12 and A2. We draw now two new lines A1,A12 andA12,A2. We set again a point at 30% along each of these lines resulting in another two pointsD1 and D2. Performing the same procedure for these points, i.e. connecting them and creatinga new point at 30% along this last line we finally yield the Bézier spline point B.The second quadrangle in Figure 4-20 only contains the points constructed at10%,20%,…,90% according to the above steps and the appropriate last lines, which aretangents to the curve. The cubic Bézier spline segment is finally outlined in the thirdquadrangle 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 thespline can change the sign of curvature? Let’s look at the letter C, it is either drawn clockwiseor counterclockwise. According to this we can say: “Its curvature is either positive ornegative”. This is how the quadratic Bézier spline behaves. In contrast to that the letter S hasone part of it drawn clockwise and the other drawn counterclockwise – we say: “the curvaturechanged its sign from positive to negative or otherwise”. That is one of the competitivestrength of the cubic spline over her quadratic sister.Since the behaviour of the cubic Bézier spline segment is quite clear to us now, let’s look atthe cubic Bézier 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 18The C command is followed by three pairs of x-/y-coordinates. The first and second pairspecify the control points C1 and C2 (Figure 4-20) and the last pair are the coordinates of thesegments end point P1. The start point P1 is as always the current point. Figure 4-21. Different Cubic Bézier Spline SegmentsFigure 4-21 shows different combinations of control points. Please note, if the control pointsare symmetric to any axis then so is the curve itself. We can also coincide control points toachieve special effects. The cubic spline segment can be closed, intersect itself or degenerateto a line.The next step is to concatenate several segments for a polybezier curve.
    • Learn SVG Chapter 4 Curves 19 Figure 4-22. Cubic Polybézier SplinesAnalogical to the quadratic Bézier T command we are allowed to omit the first control pointwith the cubic Bézier S command. Here too the ommitted control point is automaticallycreated from the last control point of the previous cubic Bézier segment by reflection relativeto the path’s current point. The previous command specifier must be C or S to worksmoothly. Here is the shamrock of Figure 4-23 as an example. Figure 4-23. Usage of cubic Bézier 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 20Let’s finally apply the cubic Bézier spline to our car. Figure 4-24. Cubic CarRelative Path CommandsNow that you are introduced to all types of path segments, you may also have noticed thatevery upper case path command letter, say A, in addition has a lower case pendant a. Uptohere we only used upper case commands for consistency. The notational difference is quiteimportant and designates the location of the reference coordinate system within which wedefine path point coordinates.Upper case command letters use absolute coordinates with respect to the path element’scoordinate system. Lower case command letters use a relative coordinate system with itsorigin always located in the path’s current point and the same orientation as the element’scoordinate system. Figure 4-25. Relative Path CommandsWe will refer to these commands with absolute and relative commands respectively. The pathin Figure 4-25 is defined twice. On the left we used absolute commands, on the right wedescibed the same contour using relative commands this time.
    • Learn SVG Chapter 4 Curves 21All coordinates on the left are defined with respect to the origin of the element’s coordinatesystem on the grid’s 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 viarelative commands. We start here with a relative moveto m. Since the path’s current pointisn’t explicitly set by a previous segment, it initially coincides with the element coordinatesystem’s origin (0,0), located here in the middle of the grid’s upper edge. With this startingsituation there is in fact no difference to the absolute moveto command M. But hereafter wehave moved the current point to (40,80) and simultanously established here a temporarycoordinate system for the subsequent command. With respect to this coordinate system wethen move the current point by a relative lineto command to the point (0,-20). Again we alsomoved the temporary path coordinate system vertically to this point (40,60) absolute. InFigure 4-x we can see all subsequent locations of the current path coordinate system alwayscoinciding 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 don’t move the path’s 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 system’s 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 ShortcutsNow that we are quite used to the curve describing path data notation, we still remember thatthe choice for this – from XML view - eccentric format was solely driven by the effort forcompact path data. Due to the importance of this criterion we are not surprised that there aresome 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 thesingle characters comma, blank and newline. These separators – also referred to as whitespacecharacters – 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 number’s 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 usuallyresult in more compact code than absolute commands.Closing PathsSometimes we have to close a path with an arc or spline segment. As we learned, we cannotuse the closepath command Z here, since it is simply drawing a straight line back to thebeginning of the sub-path. So we must close the path with that particular arc or splinesegment. But even if you close the path explicitly, I strongly recommend to always use anadditional Z command nevertheless. Only that way you ensure to have the sub-path’s start andend point joined regularly. Figure 4-26. Explicit closing pathFilling a PathFilling 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 rendererwith the help of an invisible closepath segment (Figure 4-27).
    • Learn SVG Chapter 4 Curves 23 Figure 4-27. Filling closed and non-closed pathesSince paths can intersect themselfes or can have subpaths, that may overlap or contain eachother completely, SVG provides certain rules to deal with these filling cases. The basis ofthese 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 canhave one of three possible values, evenodd, nonzero and inherit. With the next SVG version2.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 path’s 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 won’t 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 valuesA notable characteristic of these fill rules is the ability to create holes in seemingly solidobjects. Let’s apply this effect to our car now and cut a window in it. Then looking throughthat window we want to see another object, which is partially hidden by the car. With that wecan achieve a special clipping effect. Figure 4-30. Clipping CarsHere 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 PathWe discussed the marker element intensively in Chapter 3, where we finally created arrowheads for our dimension line. We want to revisit these markers now, since there are somespecial interesting aspects of markers in combination with paths.First of all, we can place markers only at distinct path points – the path’s verticies. In order todo this, we may use at least three different types of markers with a path. One marker on thepath’s start vertex using the marker-start attribute, another marker on the path’s end vertexwith the marker-end attribute and yet another marker on all path’s middle verticies by themarker-mid attribute. For the common case where we want a single marker on all pathverticies inclusive start and end vertex, we may use the marker attribute as a shortcut. Thespecification doesn’t define the exact behaviour for treating start and end vertex with closedpaths. That means, it is dependent on the implementation if there are two markers on the startvertex or only one, even if we close the path explicitely with a closepath segment. Figure 4-31. Path with MarkersPlease note, that marker-start and marker-end only apply to the path’s very first and lastvertex and not to start and end verticies of sub-paths.Moreover SVG allows us to adjust the markers orientation. To accomplish this we mayspecify a fixed angular value with the marker’s orient attribute. This results in all markersbeing rotated by the same amount (see orient=”30” in Figure 4-31). But frequently we want
    • Learn SVG Chapter 4 Curves 26to 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 marker’scoordinate system coincides with the path vertex’ tangent. However there might be a conflictwith the incoming segment’s end tangent being not equal to the following segment’s outgoingstart tangent. SVG deals with that cases by simply calculating the average tangent from thosetwo tangents and then align the marker’s 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 thepath’s stroke width. We discussed this feature in Chapter 3 already. All we have to do forachieving this effect is using the markerUnits=”strokeWidth” attribute.Maybe you find it somewhat inconvenient that we cannot affect the marker locations. There isa 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.Let’s assume we want to walk jovially along a path and whenever a certain time has passedwe drop a marker. When we finally arrive, the path has been marked equidistantly. Figure 4-32. Path with equidistant MarkersHere 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>Don’t panic, if you are new to scripting. We will talk about this powerful stuff later in chapter11. 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 path’s 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 SVG’s DOM (s. Chapter 11). Unfortunately wedon’t get tangent information at the path points, so there is no easy way to have the useelements tangentially aligned to the path at current.Markers onlyNeedless 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 butvery common demand I want to show you a trick with the path element where we even don’tneed the marker element. For this we • Set the path’s 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 DotsThis way we can have round path markers – without the path of course - in a very compactmanner.Path Command Reference Commands & Parameters Instruction Move from current point to new pointM,m x, y (x, y).L,l x, y Draw line from current point to new point (x, y).H,h x Draw line from current point to new point (x, current-point-y). Draw a line from current point to new point (current-point-x,V,v y 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 rx, ry, rotation with respect to the positive x-axis of x-axis-roation (in x-axis-rotation, deg). If large-arc-flag is 0 (zero), the small arc (less than 180A,a large-arc-flag, deg) is drawn, a value of 1 results in the large arc (greater than sweep-flag, x, y 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. Draw a quadratic Bézier spline segment from the current point x1, y1Q,q to new point (x,y) while approximating the control point x, y (x1,y1). Draw a smooth quadratic Bézier spline segment from the current point to new point (x,y). The previous segment must beT,t x, y of type (smooth) quadratic Bézier spline also and that’s control point is reused then via reflection relative to the current point. x1, y1 Draw a cubic Bézier spline segment from the current point toC,c x2, y2 new point (x,y) while approximating the control points (x1,y1) x, y and (x2,y2) in that order. Draw a smooth cubic Bézier spline segment from the current point to new point (x,y). The previous segment must be of type x2, y2 (smooth) cubic Bézier spline also and that’s second controlS,s x, y 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 5Text Processing"When ideas fail, words come in very handy."- Goethe (1749-1832)"Only two things are infinite, the universe and humanstupidity, and Im 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 HandlingOverviewSVGs text capabilities allow us to add titles, labels, button text and even whole paragraphs toour SVG images. Working with text can be challenging but after completing this chapter youwill have solid grasp of the main aspects of text processing in SVG. Also, an array of tips andtricks will be revealed that deal with text in SVG from both design and programmingperspectives.There are many issues that are specific to positioning and styling SVG’s text element that wewill be discovering and putting into practice in this chapter. We will also cover text-on-a-path, referencing internal and external text content, fonts, line wrapping, text selection andeven anticipated changes in the SVG 2.0 specification.The <text> and <tspan> ElementsThe ‘text’ and ‘tspan elements are the primary elements used for rendering text in SVG.Using the <text> ElementText elements in SVG take an “x” and “y” attribute that specifies the start position of our textcontent. Here is the classic “Hello world” example redesigned for SVG.
    • Learn SVG Chapter 5 Text Processing 2 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 thetext 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.Let’s 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 3 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’ thenthe text will render at the 0,0 coordinate of your SVG image. This means that you willprobably 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 willassume that these values are equal to zero. The Batik viewer however will not render the textelement at all.Using the <tspan> ElementThe ‘tspan’ element is a lot like the ‘text’ element except for a few key differences. First, theexample makes use of a <text> element that contains a <tspan> element. The tspan elementmust be contained within a ‘text’ element.As we shown in this example, multiple values can be used to position individual characterswithin 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"> Dont <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’ element’s positioningproperties, ‘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 individualcharacters in the words ‘WORRY’ and ‘HAPPY’.
    • Learn SVG Chapter 5 Text Processing 4Let’s 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 alist of lengths, coordinates or numbers.Text Wrapping and Text SelectionCurrently 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 bedisplayed.The SVG 1.2 and SVG 2.0 specifications will probably support text wrapping. For now ifyou want to display multiple lines of text then you will have to vertically position your stringsof text using two or more ‘tspan’ or ‘text’ elements.The user can select the textual content of ‘text’ elements but the ‘text’ element only allowsone line to be selected at a time. The ‘tspan’ element however can be used to allow the userto select multiple lines of text at once. The textual content of multiple ‘tspan’ elements withinone ‘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">Ill 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 Chapter 5 Text Processing 5</svg>Since the entirety of the poem in Figure 5-4 is contained within a single ‘text’ element yourusers will be able to select and copy all of the lines of the text at once. By the way, the poemused 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 onour website, FundamentalSVG.com.Text Presentation PropertiesSVG 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 PropertiesThe 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 Chapter 5 Text Processing 6 </text></svg>We encourage you to tweak and play with these properties yourself. Notice how easy it is tocreate unique designs with your text. These are just a few of the many standard CSS andSVG specific properties and can be used to stylize <text> elements. As you will soon realizewe can do much more with text in SVG.The key attributes are font-weight, font-style and text-decoration. The font-weight and font-style 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: Yesfont-style Value: normal | italic | oblique | inherit Initial: normal Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yestext-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: yesAs 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 sameproperties that you would use to do these decorations in HTML. However, SVG allows us touse presentation attributes as this example demonstrates. Figure 5-6 demonstrates some text-specific style properties.
    • Learn SVG Chapter 5 Text Processing 7 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-renderingThe text-rendering property can dramatically affect legibility as the next exampledemonstrates. 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;text-anchor:middle">text-rendering</text>
    • Learn SVG Chapter 5 Text Processing 8<g transform="translate(0,-70)"> <text text-rendering="auto" x="300" y="350" style="font-size:15;text-anchor:middle">filled</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;text-anchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="font-size:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="font-size:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="font-size: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;text-anchor:middle">stroked and filled</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;text-anchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="font-size:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="font-size:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="font-size: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;text-anchor:middle">stoked</text> <text text-rendering="auto" x="30" y="370" style="font-size:20;text-anchor:middle">auto</text> <text text-rendering="optimizeSpeed" x="140" y="370" style="font-size:20;text-anchor:middle">optimizeSpeed</text> <text text-rendering="optimizeLegibility" x="300" y="370" style="font-size:20;text-anchor:middle">optimizeLegibility</text> <text text-rendering="geometricPrecision" x="490" y="370" style="font-size:20;text-anchor:middle">geometricPrecision</text></g></svg>So far so good, let’s keep going while we’re on a roll.Text Layout and Alignment PropertiesThere are a number of specific style properties that provide us with a means of positioningand styling every aspect of textual content in our SVG images.text-anchor and baseline-shiftThe ‘text-anchor’ property can be used to left, center or right align text with respect to theinitial text position. The ‘text-anchor’ property is useful for aligning both text and tspantextual content. The default value for this property is ‘start’. Setting the text-anchor valueequal to middle will center the text chunk on the current text position that is specified by thetext or tspan x and y property values.
    • Learn SVG Chapter 5 Text Processing 9 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 alonga vertical axis located at the position specified by the text elements x attribute. This helps tocenter 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 text’s length. Thismakes positioning a lot easier because we will only have to tweak and maintain the onecoordinate 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">Mens 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 containinformation about where to position subscripts and superscripts along the text baseline inregard to normal character data for the font. In this example the character ‘1’ has a baseline-shift 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’ startcoordinate for the textual content of the ‘tspan’ element. We will discuss the font-relatedattributes a little later in this chapter.letter-spacing, word-spacing and kerningThe default value for the ‘letter-spacing’ and ‘word-spacing’ properties is ‘normal’. Byspecifying 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 wordsrespectively.
    • 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: yesword-spacing Value: normal | <length> | inherit Initial: normal
    • Learn SVG Chapter 5 Text Processing 12 Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesSVG provides the kerning property in order to allow you to alter the spacing between lettersfor specific fonts. The same letter in 10 different fonts might have 10 different widths. Thewidth 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 ofthe 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-pairtable and instead evenly space the letters by the numbers specified in ‘kerning’ value.kerning Value: auto | <length> | inherit Initial: auto Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesBy specifying a kern value you are in effect turning auto-kerning off for the font and tellingthe font to only use the value that you specify for the spacing of each letter of your text.TextLength and LengthAdjustIn this example the phrase "The average person thinks he isnt." by Father Larry Lorenzoni isused to demonstrate the workings of the ‘textLength’ and ‘lengthAdjust’ properties. You canuse these two properties on the ‘text’ element to tweak your text to precisely fit your needs. Figure 5-11. textLength and lengthAdjust attributesI used the Batik viewer to demonstrate these two properties because version 3 of the AdobeSVG 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 heisn&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 heisn&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 thevalue to ‘spacingAndGlyphs’ both the spaces between characters and words and the glyphs orletters 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.RotateThe ‘rotate’ property can be used to position individual text characters or whole strings oftext.Using a comma- or space-separated list of number value in the rotate attribute we are able torotate 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 14This image was produced by Batik. The Adobe SVG Viewer does not support rotating entirestrings of text with just one number. In figure 5-10 notice that if two numbers are specifiedthen only the first two characters will be rotated. Also notice that if fewer numbers arespecified 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 we’ll be discussing transformations indepth in the next chapter.writing-modeThe writing-mode attribute is used to set the direction or “inline-progression-direction” of textcontent. 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 designelements. This is the writing-mode property syntax.writing-mode Value: lr-tb | rl-tb | tb-rl | lr | rl | tb | inherit Initial: lr-tb Applies to: text elements Inherited: yes Percentages: N/A Media: visual Animatable: no
    • Learn SVG Chapter 5 Text Processing 15The values lr, rl and tb are merely shortcuts for specifying the values lr-tb, rl-tb and tb-rlrespectively.glyph-orientationThe glyph-orientation properties allow you to rotate the angle of your text along thehorizontal and vertical axis. If you text is running top-to-bottom you could set the glyph-orientation-vertical property value to zero. This will rotate every character in your text stringso that each letter is aligned with the vertical axis.Here are the definitions for these properties.glyph-orientation-vertical Value: auto | <angle> | inherit Initial: auto Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: noglyph-orientation-horizontal Value: <angle> | inherit Initial: 0deg Applies to: text content elements Inherited: yes Percentages: N/A Media: visual Animatable: noDirection and Unicode-bidi propertiesLanguages such as Han, Arabic, Hebrew, Kanji and Chinese can be written in directions otherthan 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 needto use the direction and bi-directionality (bidi) properties.This is the definition for these properties.direction Value: ltr | rtl | inherit Initial: ltr Applies to: text content elements Inherited: yes Percentages: N/A
    • Learn SVG Chapter 5 Text Processing 16 Media: visual Animatable: nounicode-bidi Value: normal | embed | bidi-override | inherit Initial: normal Applies to: text content elements Inherited: No Percentages: N/A Media: Visual Animatable: NoWe have assembled several examples of these two properties on our website –www.fundamentalsvg.comInheritanceInheritance is an extremely useful feature of SVG and more generally many XML-basedlanguages. In fact inheritance of style properties in SVG works just like the inheritance rulesin 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 andfill</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 onthe <tspan> element. By adding the attribute stroke=”none" to the group the entire groupinherits the stroke=”none” property value. If however, one of the contained elements have astroke=”2” for example then this local attribute will override the inherited stroke attributevalue and the contained element will render a stroke as demonstrated in this SVG image. Ifany of these attributes are declared on children elements then the local attribute will overrideany attribute that is specified on parent or ancestor elements.
    • Learn SVG Chapter 5 Text Processing 17This is also true for the ‘rotate’ property. Remember that the text elements x, y, dx, dy androtate attributes can take a list of values. The x, y, dx, dy and rotate attributes on text andtspan elements apply to any contained character content, not just character content withinimmediate children.Text on a PathThe ‘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 usan 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 pathsusing 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 ec 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 le</textPath> <textPath xlink:href="#textPath05" font-size="9" fill="black">This textspans multiple lines. Word-wrapping needs more intelligence.</textPath> <textPath xlink:href="#textPath06">Now you know that I will love youforever 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 goloop-de-li.</textPath> </text></svg>Remember that SVG uses XML grammar; this ability to reference content in other XMLelements is a part of the extensibility aspect of XML. Using “xlink:href” attribute we are ableto 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’ equalto “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 yourpath elements with a ‘defs’ element. Remember that all content within a ‘defs’ element willnever be directly displayed.Recall from Chapter 3 that in SVG the ‘path’ commands stand for relative coordinate values ifthey are lower-case and are absolute coordinates if they are capitalized. In the followinggraphic each point specifies a coordinate that is absolute and is therefore positioned withrespect 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 Chapter 5 Text Processing 20 </g> </g></svg>First of all, this phrase is from the song “Heartbreak Town” by the Dixie Chicks whose songshave a way of making my eyes watery. Second, one of the interesting features that you maynotice 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 pathcalled “textPath01”.startOffsetThe startOffset attribute is a ‘length’ value that can be used on the textPath element toposition the textual content along the referenced path. A positive startOffset will move thetext further along the path while a negative startOffset value will pull the text in the oppositedirection along the path. If using a percentage to specify the length then 0% would equal thestart 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 that’sround.” This moves the text around the circular path whose ‘id’ equals ”textPath03” so thatthe 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 midsentence. This can be prevented using script to set the “textLength” property value equal tothe “path.length” value.Fonts and Font PropertiesThis is an interesting topic because there are so many options and possibilities. This sectioncould even be in its own book if we delved into some of the fascinating typography issues thatconcern 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 let’s cover afew basic font properties like font-size and font-family.font-sizeWe have used the font-size property many times already in examples in this book. Thisexample 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 aunit 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 Chapter 5 Text Processing 22 Value: <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 elements font size Media: visual Animatable: yesGlyphs and FontsThere are some key differences between fonts, letters and glyphs. For most people this is anew concept that is worth exploring.Marks that make up letters are technically called glyphs. Glyphs can be defines as any markthat conveys meaning whether by itself or in sequence with other glyphs. Therefore glyphsare 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 arevector-based font formats. The fonts called Verdana and Arial were created by the Monotypecompany 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 tocomprise one letter. The letter can then be included in a group of other letters tocomprise a font.font-familyThis 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: yesSystem FontsUsing system fonts just means that you are relying on the client to have the specified fontinstalled on their system. There really are very few fonts that can generally be assumed to beon most peoples systems but some common fonts include: san-serif, Arial, Times NewRoman, Helvetica, Verdana, and Tahoma.Font TablesA font is not actually considered a font unless it also comes with information that defines howto present its characters. This accompanying information is commonly known as a font tableand can be used to display fonts uniquely on different medium.SVG FontsIf you want to use a more custom font that is not commonly found on other computers orplatforms then SVG gives us the option of sending along the actual font in our graphic. Fontsthat 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. SVGFonthas also been incorporated into the Batik SVG Toolkit.Another great option for creating SVG Fonts is Illustrator 9 and 10 that is capable ofautomatically to embedding the fonts into your SVG images.
    • Learn SVG Chapter 5 Text Processing 24Embedded SVG FontsWhen we generate inline fonts from a program such as Illustrator 10 the glyph data and fonttable 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 FontsReferenced 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 SVGfile 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 TextThis may come as a surprise but text content does not need to be contained within your SVGimage. 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 thancopying text multiple times within your SVG images. For one, any changes to the textcontent will only have to occur once and the changes will automatically be updated in everyplace that the text is used. Second, referencing text can significantly decrease the size of theSVG image since the information is used more efficiently.Referenced Text
    • Learn SVG Chapter 5 Text Processing 25Like paths, textual content can also be referenced using the xlink:href attribute as shown inthe 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 overrideinherited properties. In this case the text is ‘darkslategrey’ because the on the actual <tref>element’s ‘fill’ value is defined to be ‘darkslategrey’ which overrides the ‘text’ element’s‘orange’ fill value.We will continue to cover style concepts progressively throughout the book and Appendix Bcovers both CSS and XSL styling in detail.InternationalizationSVG has some great features that support internationalization of your SVG images includingfull support for Unicode character encoding and support for multiple languages via the‘switch’ element.Character encodingUnicode 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 ofUnicode is to provide character encodings for every character of every known writtenlanguage. The Unicode standard already defines sets of characters that represent charactersfrom hundreds of languages from across our planet.
    • Learn SVG Chapter 5 Text Processing 26SVG provides full support for Unicode as well as other character encoding methods. For yourconvenience we have provided a reference table of Unicode characters from the HTMLspecification in Appendix E.switchThe switch element provides a means of allowing the users systems settings to determine thelanguage of the SVG images text content. This example demonstrates how to include supportfor 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">Lamour va</tspan> <tspan x="40" dy="20">par lestomac.</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 firstscreenshot and if the users system language is English then the content of the secondscreenshot will be displayed. This shows the true power of SVG in how it can produce avariety 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 thesewebsites.RFC document: http://www.ietf.org/rfc/rfc3066.txtSystem language country codes:http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/index.htmlWhitespace HandlingWhitespace is defined as any blanks, tabs and newline characters within a ‘text’ elementscharacter data. The property that we can use to affect how whitespace characters are dealtwith 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 ishow 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 viewersshould 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 28However, if the xml:space property value is set to ‘preserve’ then SVG viewers will merelyreplace all newline and tab characters with spaces characters. This will all you to leave largergaps between characters if you so desire.Adding blocks of textAs stated earlier in this Chapter, working with blocks of text in SVG can be overly tediousdue to the fact that neither textboxes nor any other means of implementing automatic wordwrapping 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 accomplishedthrough mixed namespaces and is currently partially supported by the X-Smiles browser, theMozilla browser or with the SVG Viewer in IE 5.5/6.0 using a binary behavior. We’ll go intothis in greater depth in Chapter 11.SummaryNow that we have covered many key SVG basics like shapes, document structure, curves, andtext we will move on to even more interesting topics like gradients, filters, animation andscripting.Then we’ll 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 InteractivityReview of Key StrengthsLet’s review some of SVG’s 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 SVGs 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 TransformationsCoordinate system, can’t live without itIn the course of the previous chapters we used coordinates intensively. What exactly do we know aboutthem? The SVG document provides us with a default coordinate system – the initial User CoordinateSystem. Figure 6-1. User coordinate SystemWith this user coordinate system comes along a plane 2D-space. This canvas is theoretically infinite inboth dimensions. To specify a point on the canvas, we also need to have a unit measure affiliated to eachcoordinate axis. SVG provides us with initial User Units. Initially one user unit is equal to the size of onepixel. 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 resolutiondependent.The canvas is infinite, however your computer screen is finite in both dimensions. So the SVGspecification 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 2You can define the width and the height of the initial viewport by the SVG root element <svg> via itswidth and height attributes. The grid in the above picture has a line spacing of 10 user units. Theviewport’s upper left corner coincides with the initial user coordinate system’s origin. The positive x-axisis pointing towards the right, the positive y-axis is pointing downward. Now with that all defined, we canexactly predict, where a circle is drawn, when cx and cy is specified. Please note, that the coordinatesystem’s origin is not for ever fixed to the upper left corner. A simple zoom or pan operation can move itto somewhere else.The mathematicians and CAD users among you will feel that coordinate axis alignment somewhatunusual, since they are accustomed to a Cartesian coordinate system, with the y-axis up. Though we needto get used to this coordinate system with the y-axis down, since it is common in the field of computergraphics.Again, the <svg> root element automatically defines a viewport with dimensions specified by it’s widthand 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 viewport’s window are clipped, i.e. only those partsof the elements inside of the viewport are rendered. Elements, that are completely outside are simplyinvisible.Multiple ViewportsNow, as we are familiarized with the root element’s viewport characteristic, we are not astonished tolearn, that SVG allows the definition of multiple viewports. As any other element every additionalviewport also has to be defined as a descendant element of the root element.
    • Learn SVG Chapter 6 Coordinate system and Transformations 3 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 document’s viewport. It’s upper left corneris located at (125,25) and it is 50 units wide and 70 units high, expressed in coordinates and units of itsparent’s – the root element’s – viewport.The positioning of a viewport via x- and y-attribute is supported for all <svg> elements except theoutermost <svg> element. This new viewport establishes its own new coordinate system with the originagain in the upper left corner and initial user units by default. So all its elements are using that coordinatesystem. 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 identicalradius are rendered to the same size. What, if we want another scale? To achieve this, we can use <svg>’sviewBox 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 4The viewBox attribute’s value consists of four numbers xmin, ymin, width, height. With these you canspecify a rectangular user space that will be mapped to the bounds of the affiliated viewport.Syntax: viewBox=”xmin, ymin, width, height” xmin minimal x-coordinate corresponding to the viewports upper left corner ymin minimal y-coordinate corresponding to the viewports upper left corner width width of the viewport height height of the viewportLocale Coordinate SystemWhen we discussed the <g> and <use> elements in a previous chapter, we didn’t pay extra attention tothe choice of the coordinate system. Now we need to recover that. We refer again to the rack examplefrom chapter 3 and start defining a pallet consisting of four rectangles. Figure 6-6. A pallet for the rackThis part should be provided for the purpose of multiple reuse. So we design it as a group in thedocument’s <defs> section. Now, when we need to define the pallet’s <rect> elements, we wonder whatcoordinate values to choose. Since the object’s dimensions are predefined, we have not much choice. Wecan arbitrarily define at least one point’s coordinates, the others result more or less uniquely from thedimensions given. So we define the pallet’s upper left corner to have the coordinates (0,0). By havingfixed this, we implicitly refer to a coordinate system with it’s 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. Withthis all other coordinates could be calculated. As the pallet is made out of wood, tan seems to be anappropriate colour for the rectangles.
    • Learn SVG Chapter 6 Coordinate system and Transformations 5You might ask now: “Where did I define a coordinate system in this code?”. Indeed we didn’t, at least notexplicitly. But as I mentioned above, we do refer to a implicit coordinate system’s origin, when we writex="58" and y="3". Now that we finished our pallet’s definition, we can imagine the coordinate system tobe rigidly coupled to the pallet. With this in mind, we will use the term “local coordinate system of thegroup”. Corresponding to that term we will also refer to a “reference coordinate system”. The referencecoordinate system is defined by the innermost container element (usually the parent group) or theinnermost viewport.Now we need some criteria to qualify the arbitrary choice of our local coordinate system as advantageousor disadvantageous. For this we want a scene, in which we can insert some instances of the pallet. Figure 6-8. Rack for palletsWe decide to use a rack similar to that we defined in the previous chapter ??. With regard to the redreference coordinate system there are three positions defined. These positions are the destined midpointof each load. Since your boss has told you, to store three empty pallets at those locations, you startimmediately 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 ourpallet 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_palletThis should work now.
    • Learn SVG Chapter 6 Coordinate system and Transformations 6 <use xlink:href="#pallet" x="5" y="285" /> Figure 6-10. Its betterFine, but you do not appear very happy, as there are a lot of different sized pallets in this storage and youare 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 palletWith the help of this illustrative example we realize, that the local origin is of great importance forhandling group instances. We can imagine it as a grip point, with which we clutch the pallet and move itto the location we want it to be. It is now easy to place the other pallets as well – provided that you aretall 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 7 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 rack’s 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 8 <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 TransformationsWe have learned now how to displace <use> elements by their x and y attributes and how to design thecorresponding groups in order to do that quite comfortable. But a simple element displacement from onelocation to another can’t 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 specificationgives us a very common powerful feature – the transform attribute. That transform attribute can beapplied to most graphics elements, i.e. elements, that cause graphics to be drawn onto the canvas. It canbe applied as well to the <g> element. Here is the transform attribute’s 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 illustratethe transformations with a more complex element, i.e. an <use> element referring to a group. But we dobear 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 screw’sgeometry regarding its red local coordinate system. Figure 6-13. The screw and its coordinate systemHere 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 9 <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 screw’s group via <use xlink:href="#screw" />the screw’s local coordinate system will coincide with the blue reference coordinate system. With thisstarting 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 systemincluding the affiliated 2D-space – with the screw here accidentally in it – than simple graphics elements.TranslateThe translation is an elementary displacement transformation.Syntax: translate(tx, ty) tx x-coordinate of displacement ty y-coordinate of displacementHere we apply the translate transformation to the screw group’s instance, exactly to the local origin of thisgroup. <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 elementEasy, isn’t it? So you might ask now what the difference of the translate transformation to the use of thex- 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 patientand 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 translatetransformation. <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 elementThe effect we have now, is that the screw is translated first to the coordinates (100,130) andsubsequently displaced by (130,-160) to the end location (230,-30). To yield the end position of theelements local coordinate system formally we can simply add the coordinates as in Xlocal = tx + x ylocal = ty + yIn this formulas we can exchange the addends without harm, i.e. Xlocal =x + tx ylocal =y + tywill 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 thatthe following elements produce identical output. <use xlink:href="#screw" transform="translate(130,-160) translate(100,130)" /> <use xlink:href="#screw" transform="translate(100,130) translate(130,-160)" /> <use xlink:href="#screw" transform="translate(230,-30)" /> <use xlink:href="#screw" x="230" y="-30" />It is quite simple but also somewhat confusing to use both the x- and y- attributes and the translatetransformation. So it is best to avoid this generally, but there may be situations to use this effectdeliberately as a benefit.Although the sequence of these both displacements is of no importance here, the SVG specificationstates: 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 ofperform the translate transformation.apply the x- and y- attributes.This was also taken into account with the examples above.RotateThe rotate transformation is used to rotate an element by a certain angle.Syntax: rotate(angle [, cx, cy])
    • Learn SVG Chapter 6 Coordinate system and Transformations 13 angle rotation angle in degrees, can be positive and negative cx x-center of rotation, optional cy y- center of rotation, optionalWe apply that rotate transformation to our screw in its simplest form. <use xlink:href="#screw" transform="rotate(25)" /> Figure 6-17. Rotate the screwThis results in a rotation around the blue origin – yes it is the origin of the reference coordinate systemthe screw is rotated about, as we’ll see later. The angle‘s value 25 is given in degrees. The rotation occursclockwise since we have a positive angle‘s value. The mathematicians among you may cry out loud,because this is the mathematical negative direction. They are right when referring to a Cartesiancoordinate system with the y-axis up. Since we have a coordinate system with its y-axis down, thepositive 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. Thecoordinates 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 system’s origin by defaultif an additional pivot point (cx,cy) is given in reference system’s coordinates, the rotation occurs aboutthat point.the rotation angle’s 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 thetransformation centre.a rotation angle of zero results in the identity transformation, i.e. the transformation, that leaves theelement unaffected.The inverse rotation transformation to rotate(angle) is rotate(-angle),i.e. these transformationsapplied subsequently to an element leaves the element unaffected (identity transformation).ScaleThe scale transformation is used to change the size of an element.Syntax: scale(sx [,sy]) sx x-scale factor sy y-scale factor, optionalIf 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 alsochanged its position. Instead of wondering about this effect any longer let us look at the screw’s local
    • Learn SVG Chapter 6 Coordinate system and Transformations 15coordinate system. We see now that the underlying grid as well as the coordinate axes are scaled also by afactor of 2. And with the recognition of the fact, that obviously every local coordinate’s value has beendoubled we do understand now that the scaled screw also must seem to be translated. It isn’t, it is simplyscaled with respect to the origin – the blue one. Figure 6-19. Scale(2) the screwOf 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 thescale factor, so that those get smaller values.If we make the scale value smaller and smaller the screw willvanish into thin air, exactly into the world’s origin. Finally a scale factor of zero will reduce the screw toa single, dimensionless point. Thus preventing it from being rendered. Figure 6-20. Scale(0.5) the screwUntil 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 shouldconsequently 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 screwWith this we reduced the screw’s 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 screwby shrinking the screw in x-direction only. As we understood this so far, you may ask what aboutnegative 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 17With that we mirrored our screw at the y-axis. Or to explain it geometrically, we changed the sign ofevery x-coordinate by multiplying it by –1, so that we now have negative x-values for the screw. Ofcourse 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 x-axis 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 twoarguments 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 doesn’t.the centre of the scale transformation is exclusively the reference coordinate system’s 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. scalingwith inverse scaling factors.SkewingThe skewing transformation – frequently called shearing – consists of two elementary transformationsskewX and skewY.Syntax: skewX(angle]) angle angular displacement of y-axis skewY(angle]) angle angular displacement of x-axisWe 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 screwWe can interpret the skewY transformation as a rotation of the x-axis towards the positive y-axis, whileleaving the y-axis’ direction as it is. It is also obvious now, that a skewing angle of 90° and greater is notallowed. The results for doing so are not defined. A negative angle results in a rotation in the oppositedirection. Here also the angle must be greater than –90°. The only line of the plane that remainsunaffected by that transformation is the x-axis.The skewX transformation behaves similar with regard to the y-axis. Figure 6-25. SkewX(25) the screwHere 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 somewhatmisleading, since the resulting effect is a true shearing or skewing. As you can easily see abovethe 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 inthe x-direction.
    • Learn SVG Chapter 6 Coordinate system and Transformations 19This displacement depends on the y-coordinate, i.e. points with greater y-values are displaced more thanpoints with smaller y-values. To describe that mathematically, we can define the ratio ∆x ∆y kx = ;ky = y xFinally there is a relation between those ratios and the angles tan α x = k x ; tan α y = k yAs we also remember, that the tangent of 90° is infinite, we now understand, that a skew angle of 90° isnot 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 angle’s 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 transformation’s centre is the x-axis.the skewY transformation’s 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 forskewY).Concatenation of TransformsNow that you know how the elementary transformations work you want to start transforming yourelements. Translating, scaling, rotating and skewing them to your heart’s content. You can do this quitecomfortably, 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 N’th elementary transformFine, but we have to be cautious, because the sequence of the elementary transformations is of greatimportance. 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 libraryBeside our screw we also have a nut group now. Both parts are geometrically described with respect totheir red local coordinate systems. We must use these parts right now to bolt two plates together. Figure 6-27. Two plates to bolt togetherHere is the library’s 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 thefirst 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 screwWithout a transformation the screw is positioned so, that its red local coordinate system coincides withthe 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 22It works. Despite the fact, that it seems to be so easy, we should have a look under the transformation’shood. Here is a stop motion picture of the transforming procedure. Figure 6-30. Transformations to put in place the screwThe first transformation process was to rotate the screw by 90°. Hereafter we translated the screw’s localorigin onto the point (100,100).As I told you, that the transformations order is important, let’s simply interchange that order as anexperiment. Now we translate first and rotate the screw subsequently. <use xlink:href="#screw" transform="rotate(90) translate(100,100)" /> Figure 6-31. Steps for transformationWith this we miss the hole. Maybe we implied a rotation about the screw’s local red origin, but therotation definitely occurred about the reference coordinate system’s blue origin. That wrong presumptionis in fact a popular beginners fault, so I need to stress here again: The default centre of an element’s rotate transformation is the origin of the parent element’s reference coordinate system.
    • Learn SVG Chapter 6 Coordinate system and Transformations 23You might remember, that there were two more default arguments with the rotate transformation. We canuse these to set the pivot point of the rotation explicitly. Then we can leave the transformations order as itis. <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 hole’sdiameter is half as wide as the previous one’s. After looking quite helplessly at our screw and nut groupsfor 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 screwswith different sizes each – thanks to SVG’s powerful scale transformation.So how should we start? To make a screw of half the size simply means to scale it down uniformly viascale(0.5). But we still have to rotate and translate also. So what transformation order should we applyhere – 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 scalingtransformation is the reference coordinate system’s origin. Since the screw’s local origin coincides with
    • Learn SVG Chapter 6 Coordinate system and Transformations 24the reference system’s initially, we can start blindly with the scale transformation followed by the nowfamiliar 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 placeIt obviously works as expected. With this success you decide lionhearted to permute the order of scalingand rotation with the nut.<use xlink:href="#nut" transform="translate(300,142) scale(0.5) rotate(-90) " /> Figure 6-34. The two screws in placeWell, this way also works fine. Though it is no surprise, as both the scale and the rotate transformationhave 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 25Just to show you the correctness of the last sentence regarding the non-uniform scale, we will simplyproof 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 transformationsStill heavily impressed by the enormous number of different screw sizes available, you are meditating, ifit would be possible to have two screws of the same size but different thread lengths. Here I must tell youthat we can’t do this with SVG 1.0 based on a single group. But the wise W3C is busy all the time andI’m quite sure we get a basketfull of surprises with SVG 2.0.I don’t 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 TransformationsUntil here we discussed the application of multiple transforms to a single element. So we now need toanalyse, how the transformation of container elements influence the contained elements. Furthermore wewill 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 centrepoint 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 isalso then translated so that its centre point coincides with the origin. Then it is rotated about the origin by45°. 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 thedocument (300,200).We will focus on the sequence of these different transforms and analyse, how we can create the sameimage with a simple flat element structure, i.e. not using.<defs>, <g> and <use> elements. We startwith the tomato coloured circle. To pull it out of its parent group, we simply have to apply the group’stransformation 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 circleThat 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 group’s transformation also to therectangle. And we have to apply the group’s transformation after the element’s 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 squareWith 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 asfollows<element transform="t3 t2 t1 t0" />We’ll compose the parent groups’ transformations from inside out. That is, these are applied after(appended from the left to) the element’s 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 element’s transform.
    • Learn SVG Chapter 6 Coordinate system and Transformations 28Now let’s consider the seagreen square finally. In a first step we want to eliminate the <use> element.In order to preserve the <rect> element’s visual appearance (overall transformation), we need to applythe <use> element’s 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> element’s transformation after the element’stransformation. Now we need to extract the seagreen square from its enclosing group. We are quitefamiliar 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 objectsWith 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 use’s transformation is applied after (appended left to) the reused element’s 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 element’s 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 Chapter 6 Coordinate system and Transformations 29</svg>Now you might be surprised that we can use this quite theoretically stuff elegantly for a refreshing pieceof 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 triangleNow we reuse this triangle three times, while we scale it down by the factor 0.5 and position it at the corners of the – nowunused – 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 stepWe 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 stepsWith these boring transformations we have created a well known fractal – the Sierpinski Triangle. If youwant to learn more about these beautiful self-similar fractals, you can surf the web and type “iteratedfunction systems”, “IFS” or simply “fractals” in your favourite search engine.Transformation MatricesBefore you start reading this chapter, you should know that you not necessarily need to use this kind oftransform. But if you want to use the matrix transform with scripting for performance reasons or simplywant 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 numbersLet’s 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 rectangulararray of real numbers. The matrices here in SVG context are 3x3 matrices suited to transform coordinates. ⎛ x ⎞ ⎛ a c e ⎞ ⎛x⎞ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ y ⎟ = ⎜ b d f ⎟⋅⎜ y⎟ ⎜ 1 ⎟ ⎜0 0 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 rowsof the matrix are the components of the matrix transform. Since the last row is always (0 0 1), we canomit it. Before discussing these components and compare them to the elementary transformations wealready 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 thecoordinates. Transformations that have this linear characteristic are called affine transformations.Translation Matrix
    • Learn SVG Chapter 6 Coordinate system and Transformations 33The 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 supplyto the translate(tx,ty) transform.Rotation MatrixThe rotation matrix needs some trigonometric functions ⎛ cos α − sin α 0⎞ ⎜ ⎟ Trotate = ⎜ sin α cos α 0⎟ ⎜ 0 1⎟ ⎝ 0 ⎠where alfa is the rotation angle. Please note, that the angle’s value must be supplied in radians here. Thisis contrary to the rotate transform, where we need the angle in degrees. We can simply convert an anglefrom degrees into radians via πα = angle ⋅ 180Scaling Matrix ⎛ sx 0 0⎞ ⎜ ⎟ Tscale =⎜0 sy 0⎟ ⎜0 1⎟ ⎝ 0 ⎠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⎞ ⎜ ⎟ ⎜ ⎟ TskewX = ⎜0 1 0 ⎟; TskewY = ⎜ tan α 1 0⎟ ⎜0 1⎟ ⎜ 0 0 1⎟ ⎝ 0 ⎠ ⎝ ⎠The skew factor tan(alfa) for the transformation matrices must be calculated from the skewing angle ofthe skewX(angle) and skewY(angle) transform via the tangent function.Concatenate Transform MatricesTransformations can be concatenated by multiplying their matrices. Since matrix multiplication is notcommutative, i.e. the matrices cannot be interchanged, it is important that the matrices be composed inthe correct order. The matrix multiplication has to be performed as follows. ⎛ a1 c1 e1 ⎞ ⎛ a 2 c2 e2 ⎞ ⎛ a1 ⋅ a 2 + c1 ⋅ b2 a1 ⋅ c2 + c1 ⋅ d 2 a1 ⋅ e2 + c1 ⋅ f 2 + e1 ⎞ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟ T = ⎜ b1 d1 f1 ⎟ ⋅ ⎜ b2 d2 f 2 ⎟ = ⎜ b1 ⋅ a 2 + d 1 ⋅ b2 b1 ⋅ c2 + d 1 ⋅ d 2 b1 ⋅ e2 + d 1 ⋅ f 2 + f1 ⎟ ⎜0 1⎟ ⎜0 1⎟ ⎜ ⎟ ⎝ 0 ⎠ ⎝ 0 ⎠ ⎝ 0 0 1 ⎠
    • Learn SVG Chapter 6 Coordinate system and Transformations 34Multiplying a vector with multiple matrices must be performed from right to left. ⎛ x ⎞ ⎛ a1 c1 e1 ⎞ ⎛ a 2 c2 e2 ⎞ ⎛ x ⎞ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ y ⎟ = ⎜ b1 d1 f1 ⎟ ⋅ ⎜ b2 d2 f2 ⎟ ⋅ ⎜ y ⎟ ⎜1⎟ ⎜0 1⎟ ⎜0 1 ⎟ ⎜1⎟ ⎝ ⎠ ⎝ 0 ⎠ ⎝ 0 ⎠ ⎝ ⎠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 theright-to-left evaluation of the elementary transformations of the transform attribute. That means also, ifwe want to transform an element that still has some transformations applied to it, we must post-multiplythe new transformation matrix, that is append it to the left of the previously applied transformationmatrices.Matrix ExampleNow let’s practice that theoretical stuff with the small screw of our screw example. Figure 6-44. Using matrix to put screw in placeWe 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 1⎟ ⎜ 0 0 1⎟ ⎝ ⎠ ⎝ 0 ⎠ ⎝ ⎠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 35Now we can start to multiply the matrices. You might be astonished, that I tell you that it doesn’t matter,if we start from left or from right. So please note, only the order of the matrices is important, not theevaluation order. We choose to start from the left, leaving the multiplication from the right for yourexercise ☺. 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 1 ⎟ ⎝ 0 ⎠and get the resulting matrix. We remember SVG’s matrix notation ⎛a c e⎞ ⎜ ⎟T = ⎜b d f⎟ ⎜0 0 1⎟ ⎝ ⎠in combination with the transform attributematrix(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 isn’t 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 svgdocuments (server-side or client-side) or manipulate the transform attribute by SMIL animation.
    • Chapter 7 : Filling the pictureOpacityExtract 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 intermediaterendering operations. Object/group opacity can be thought of conceptually as apostprocessing operation. Conceptually, after the object/group is rendered into an RGBAoffscreen image, the object/group opacity setting specifies how to blend the offscreenimage into the current background."Any values outside the range 0.0 (fully transparent) to 1.0 (fully opaque) will be clampedto this range.Fill opacity and stroke opacityWe can affect opacity for filling or stroking any element as shape, text ....fill-opacity Value: <opacity-value> | inherit Initial: 1 Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yesstroke-opacity Value: <opacity-value> | inherit Initial: 1 Applies to: shapes and text content elements Inherited: yes Percentages: N/A Media: visual Animatable: yes
    • Learn SVG Chapter 7 Filling the Shape 1We 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 arectangle 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 stripsGradient stop opacity
    • Learn SVG Chapter 7 Filling the Shape 2See below about gradientsObject/group opacityopacity Value: <alphavalue> | inherit Initial: 1 Applies to: container elements and graphics elements Inherited: no Percentages: N/A Media: visual Animatable: yesFigure 7-2 show that if opacity of 0.5 apply to group, yellow circle cover red circle andthen 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 3GradientsGradients are used to fill or stroke basic shapes, paths or text elements, using many colorswith color transitions from one to other.Colors in gradients or gradients stop elementsThis 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 syntaxValues for offset are from 0% to 100% or from 0 to 1. For each stop element, offset mustbe equal to or greater than the previous stops offset value.Gradient offset values less than 0 (or less than 0%) are rounded up to 0%. Gradient offsetvalues 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 stopelements.<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 Chapter 7 Filling the Shape 4</defs>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 theoutermost/largest circle.We can see result in Figure 7-3. Figure 7-3. How work offset for stop elementIn linear gradient, to fill shape, red is used from begin to 30% of total length, yellow isused 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 gradientvector 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 seeafter )To fill shape, red is used for circle with radius of 30% of areas radius , yellow is usedfrom 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 isfilled with continuously smooth color transitions from red to yellow. For 50 and 50, weget 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 5 <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 elementWe get this effects with radial gradient in Figure 7-5 for different values of offsetattributes.Source of svg file ( Example 7-5 ) :
    • Learn SVG Chapter 7 Filling the Shape 6<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 7Other attributesWith stop-color we choose color used ( name, RGB or hexadecimal value ). Its notpossible 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: yesWith stop-opacity we choose opacity for color from 0 to 1.stop-opacity property Value: <alphavalue> | inherit Initial: 1 Applies to: stop elements Inherited: no Percentages: N/A Media: visual Animatable: yesRendering propertiesFor gradients, one property is important : color-interpolation.By default, color-interpolation has value sRGBcolor-interpolation property Value: auto | sRGB | linearRGB | inherit Initial: sRGB Applies to: container elements, graphics elements and animateColor Inherited: yes Percentages: N/A
    • Learn SVG Chapter 7 Filling the Shape 8 Media: visual Animatable: yesauto means that author doesnt require that color interpolation occur in a particular colorspace .We can see on this example ( Figure 7-6 ) that to go from red to yellow, repartition ofcolors is not the same with sRGB and linearRGB. Figure 7-6. color-interpolation property valueCommon attributes for linear and radial gradientsgradientUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it definesthe coordinate system for attributes x1 y1 x2 y2 for linearGradient and cx cy r fx fy forradialGradient.With "userSpaceOnUse", values are defined in current user coordinate system.With "objectBoundingBox", default value, values are defined in coordinate system usingthe bounding box of the element to which the gradient is applied. In this case, its moreeasy to use percentages for attributes.You can see after for linearGradient that this choice give different results on a square anda rectangle by example.gradientTransform allow to add transform to coordinate system. We can usetranslate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a bc d e f).
    • Learn SVG Chapter 7 Filling the Shape 9Figure 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 elementspreadMethod attribute can be pad, reflect or repeat. This attribute indicates whathappens 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 endof gradient.
    • Learn SVG Chapter 7 Filling the Shape10With reflect, gradient is used start to end, then end to start , start to end ... to fill therectangle.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 isused from 0% to 20% and yellow from 50% to 100%. With reflect and repeat, we can seehow 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 Chapter 7 Filling the Shape11 Figure 7-8. Different values for spreadMethod attributeHow apply gradient to shape ?We define gradient in <defs> section and give id, here "MyGradient" to linearGradientelement. <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=200style=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 Chapter 7 Filling the Shape12 <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 gradientLinear GradientsThis 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 Chapter 7 Filling the Shape13 Diagram 7-2. Chart for linearGradient syntaxFigure 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 Chapter 7 Filling the Shape14x1 y1 x2 y2 attributes define vector for linear gradient. This vector provides starting andending points onto which the gradient stops are mapped. Colored strips are perpendicularto 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 resultdiagonally strips with 0 0 100 100 from upper left corner to lower right cornerdiagonally strips with 0 100 100 0 from lower left corner to upper right cornerhorizontal 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 Chapter 7 Filling the Shape15 Figure 7-11. Different values for x1 y1 x2 y2Effect of x1, y1, x2 and y2 with gradientUnits="objectBoundingBox" depend of filledobject. Result is not the same on a square and a rectangle.For a rectangle, coordinate system is not orthogonal and strips of color are perpendicularto gradient vector in calculus in this system, but not in common sense. Figure 7-12. gradientUnits and shapesBy 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 Chapter 7 Filling the Shape16Figure 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 Chapter 7 Filling the Shape17We 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 coveronly a part of rectangle.gradientTransform="rotate(-45,-450,150)" apply to 0 100 100 100 and 0 100 100 0 aredifferent for same reason, and here we can not use percentages to give center of rotation.We cannot define such gradient for many objects.Radial GradientsThis 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 Chapter 7 Filling the Shape18 Figure 7-14. Attributes for radialGradient elementcx, 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 thatthe 0% gradient stop is mapped to (fx, fy). If values are not specified for fx and fy, focalpoint is in cx,cy.Figure 7-14 show example with cx="50%" cy="50%" r="50%" fx="20%" fy="20%" andoffset="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 repeatvalues 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 Chapter 7 Filling the Shape19 <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 pointGradients and filtersWe 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 Chapter 7 Filling the Shape20<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 Chapter 7 Filling the Shape21How create gradients ?In design tools, we can choose gradient, but you cannot try all parameters, so you canfind online ( at pilat.free.fr ) or on companion cd a tool to create gradient, test allparameters and get code for gradient ( using PHP )Figure 7-17 is screenshot of tool to create radial gradient. This tool exist also as reusablecomponent that you can add at your application. Figure 7-17. Tool to create radial gradient
    • Learn SVG Chapter 7 Filling the Shape22Patternspattern element"A pattern is used to fill or stroke an object using a pre-defined graphic object which canbe 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 Chapter 7 Filling the Shape23In 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 bydefault ), width ( 0 by default ) and height ( 0 by default ).patternUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines thecoordinate 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 usingthe bounding box of the element to which the pattern is applied. In this case, its moreeasy 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", itdefines 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 usetranslate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a bc 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 Chapter 7 Filling the Shape24 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 attributePattern 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 Chapter 7 Filling the Shape25We 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=200style=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 patternFigure 7-20 show classical examples of pattern used in statistical charts or maps.
    • Learn SVG Chapter 7 Filling the Shape26 Figure 7-20. Some classical examples of patternHow create patterns ?In design tools, we can choose pattern, but you cannot create our own pattern, so you canfind 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 cancreate your gradient with previous tool as reusable component.
    • Learn SVG Chapter 7 Filling the Shape27 Figure 7-21. Screenshot of tool to create pattern contentUse filter on patternWe can add filter to create effect on patternFigure 7-22 show two effects on very simple pattern. We use lighting filter on pattern andcomposite 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 Chapter 7 Filling the Shape28 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 filtersWith figure 7-23, we have Europa map as lego pieces using pattern with filters. Onlycolor of lighting change for the two patterns.
    • Learn SVG Chapter 7 Filling the Shape29 Figure 7-23. Using pattern and filters for Europa mapTo go further with patternsPattern create tile to fill shape or other element, but tiling use only translation of sametile. 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 basicshapes.Figure 7-24 show example of tiling of plane create with some Bezier curves and lightingeffect
    • Learn SVG Chapter 7 Filling the Shape30 Figure 7-24. Example of tiling of plane and lighting effect
    • Learn SVG Chapter 7 Filling the Shape31Clipping paths"The clipping path restricts the region to which paint can be applied. Conceptually, anyparts of the drawing that lie outside of the region bounded by the currently active clippingpath 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 syntaxclipPathUnits 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 usingthe 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 forclip-rule attribute, nonzero or evenodd.
    • Learn SVG Chapter 7 Filling the Shape32clip-rule Value: nonzero | evenodd | inherit Initial: nonzero Applies to: graphics elements within a clipPath element Inherited: yes Percentages: N/A Media: visual Animatable: yesnonzero 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: <uri> | none | inherit Initial: none Applies to: container elements and graphics elements Inherited: no Percentages: N/A Media: visual Animatable: yesFigure 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 circleWe draw black rectangle, white text and use element with circle as clip-path and blacktext 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 Chapter 7 Filling the Shape33<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 textWe can use clipPath element for drop-down list with scrolling. Figure 7-26. Drop-down selection list with scrollingFigure 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 Chapter 7 Filling the Shape34 <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 Chapter 7 Filling the Shape35 <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=200style=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 Chapter 7 Filling the Shape36 <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 banditUsing clipping path for puzzleWe can create puzzle game with some scripts. In this example, user can change pictureused 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 Chapter 7 Filling the Shape37 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 andnb_pieces.// Call create_pieces to create pieces and distribution to arrange piecesbefore // 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 useelements 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 Chapter 7 Filling the Shape38 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 andinitialise // 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 Chapter 7 Filling the Shape39// 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 Chapter 7 Filling the Shape40 }; 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("Its 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 Chapter 7 Filling the Shape41 <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 Chapter 7 Filling the Shape42 Figure 7-28. Sceenshot of puzzle game
    • Learn SVG Chapter 7 Filling the Shape43Masks"A pattern is used to fill or stroke an object using a pre-defined graphic object which canbe 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 syntaxmaskUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines thecoordinate system for attributes x y width and height for largest possible offscreenbuffer.With "userSpaceOnUse", values are defined in current user coordinate system.
    • Learn SVG Chapter 7 Filling the Shape44With "objectBoundingBox", default value, values are defined in coordinate system usingthe bounding box of the element to which the mask is applied. In this case, its moreeasy 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", itdefines 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: <uri> | none | inherit Initial: none Applies to: container elements and graphics elements Inherited: no Percentages: N/A Media: visual Animatable: yesWe 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" fill-opacity="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 Chapter 7 Filling the Shape45What 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 alphamask 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 filtersSVG specifications allow using filters on vector and raster pictures.Filters can create object, light existing object, modify object or composite objects.Filter elementSyntax for filter elementThis 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 syntaxYou can put filter element in "defs" section :
    • Learn SVG Chapter 8 Effective Filters 2<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 elementfilterUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines thecoordinate 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 usingthe bounding box of the element to which the filter is applied. In this case, its more easyto 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 3x 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 primitivesRendering propertiesFilter primitives use rendering properties of other elements, but there is a single propertycolor-interpolation-filters property Value: auto | sRGB | linearRGB | inherit Initial: linearRGB Applies to: filter primitives Inherited: yes Percentages: N/A Media: visual Animatable: yesauto : the user agent can choose either the sRGB or linearRGB spaces for filtereffects color operations.sRGB : filter effects color operations should occur in the sRGB color space.linearRGB : filter effects color operations should occur in the linearized RGBcolor space. Figure 8-2. color-interpolation-filters values
    • Learn SVG Chapter 8 Effective Filters 4Note that color-interpolation-filters has a different initial value than color-interpolation.color-interpolation-filters has an initial value of linearRGB, whereas color-interpolationhas an initial value of sRGB. Thus, in the default case, filter effects operations occur inthe linearRGB color space, whereas all other color interpolations occur by default in thesRGB color space.Common attributesx y width height defines a rectangular subregion which restricts calculation andrendering of the given filter primitive. This value can be percentages or values. Bydefault, 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 bereferenced by an in attribute on a subsequent filter primitive within the same filterelement.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 thesame filter elementIf no value is provided for in attribute and this is the first filter primitive, then this filterprimitive will use SourceGraphic as its input. If no value is provided and this is asubsequent filter primitive, then this filter primitive will use the result from the previousfilter primitive as its input. Figure 8-3. SourceGraphic and SourceAlpha
    • Learn SVG Chapter 8 Effective Filters 5Figure 8-3 show examples of SourceGraphic and SourceAlpha for some svg objects andfor bitmap.How use filters elementsWe use filter property to apply filter to any graphic element or containerfilter Value: <uri> | none | inherit Initial: none Applies to: container elements and graphics elements Inherited: no Percentages: N/A Media: visual Animatable: yesIf 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 andfeComponentTransferfeColorMatrix primitive
    • Learn SVG Chapter 8 Effective Filters 6feColorMatrix : apply matrix transformation for calculate new values for RGB and alphafor each pixel :| R | | a00 a01 a02 a03 a04 | |R|| G | | a10 a11 a12 a13 a14 | |G|| B | = | a20 a21 a22 a23 a24 | * | B || A | | a30 a31 a32 a33 a34 | |A||1 | | 0 0 0 0 1 | |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 syntaxattribute 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 7-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 dont change, 0 give black and white picture )matrix is| 0.213+0.787s 0.715-0.715s 0.072-0.072s 0 0|| 0.213-0.213s 0.715+0.285s 0.072-0.072s 0 0|| 0.213-0.213s 0.715-0.715s 0.072+0.928s 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 0 0|| 0.2125 0.7154 0.0721 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 8<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 feColorMatrixfeComponentTransfer primitivefeComponentTransfer apply function for each RGBA channel using feFuncR, feFuncG,feFuncB and feFuncA elements.It allows operations like brightness adjustment, contrast adjustment, color balance orthresholding.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 9 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 syntaxattribute type can be:identity : C=Clinear : C=slope*C+interceptneed values for slope ( 1 by default ) and intercept ( 0 by default )gamma : C=amplitude*pow(C,exponent)+offset
    • Learn SVG Chapter 8 Effective Filters 10need values for amplitude ( 1 by default ) exponent ( 1 by default) and offset ( 0 bydefault )table : linear interpolation between values givendiscrete : step function define by given valuesThese 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 feComponentTransferFigure 8-5 show some effects on svg picture, by example, we can adjust brightness usingtype="linear" on RGB channels, with slope greater than 1, we increase brightness.
    • Learn SVG Chapter 8 Effective Filters 11Filter primitives to create lighting on objectsWe can use feSpecularLighting or feDiffuseLighting and choose light sourcefeSpotLight, fePointLight or feDistantLight. This light source is child of primitive.Lighting source : feSpotLight elementThis 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 syntaxFor 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 12specularExponent = Exponent value controlling the focus for the light source. ( 1 bydefault )limitingConeAngle = A limiting cone which restricts the region where the light isprojected. Angle in degrees. ( no limiting cone by default )Lighting source : fePointLight elementThis is syntax for fePointLight element :<fePointLight id="name" x="number" y="number" z="number"/> Diagram 8-5. Chart for fePointLight syntaxFor 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 elementThis 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 syntaxFor 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 propertyThe lighting-color property defines the color of the light source for filter primitivesfeDiffuseLighting 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: yesfeSpecularLighting primitiveThis filter primitive feSpecularLighting lights a source graphic using the alpha channel asa 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 syntaxFor feSpecularLighting, attributes are in, result andsurfaceScale : height of surface when Ain = 1. ( 1 by default )specularConstant : ks in Phong lighting model. In SVG, this can be any non-negativenumber. ( 1 by default )specularExponent : Exponent for specular term, larger is more "shiny". Range 1.0 to128.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 primitiveThis filter primitive feDiffuseLighting lights a source graphic using the alpha channel asa bump map.The resulting image is an RGBA opaque image based on the light color withalpha = 1.0 everywhere, its 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 andsurfaceScale : 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 syntaxHere example of code :<filter id="MyFilter" filterUnits=objectBoundingBox x=0% y=0% width=100% height=100%> <feColorMatrix in=SourceGraphic result=pict0type=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 onfeTurbulence.
    • Learn SVG Chapter 8 Effective Filters 17 Figure 8-6. Different values for surfaceScale attributeFigure 8-7 show some nice effects on raster. We use feColorMatrix withtype="luminanceToAlpha" to get new picture, we light this picture and compositelighting with original picture. Figure 8-7. Some effects using feColorMatrix and feDiffuseLighting
    • Learn SVG Chapter 8 Effective Filters 18Filter primitives to composite objectsWe can use feBlend, feComposite or feMerge.feBlend primitiveThis 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 syntaxFor feBlend attributes are in in2 andmode : values are normal multiply screen darken lightenExample 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. Formode="lighten" and mode="screen" also. Figure 8-8. Values for attribute modefeComposite primitiveThis 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 20 <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"/> Diagram 8-10. Chart for feComposite syntaxFor feComposite attributes are in in2 andoperator : 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 foreach 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 operatorfeMerge primitiveThis 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 syntaxFor 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 opacitiesFilter primitives to create objectsfeFlood primitiveWith 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 primitivesubregion.flood-color Value: currentColor |<color> [icc-color(<name>[,<icccolorvalue>]*)] | inherit Initial: black Applies to: feFlood elements Inherited: no Percentages: N/A Media: visual Animatable: yesThe flood-opacity property defines the opacity value to use across the entire filterprimitive subregion.flood-opacity Value: <alphavalue> | inherit Initial: 1 Applies to: feFlood elements Inherited: no Percentages: N/A Media: visual Animatable: yesThis is syntax for feFlood element :
    • Learn SVG Chapter 8 Effective Filters 24<feFlood id="name" result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" flood-color="property" flood-opacity="property"/> Diagram 8-12. Chart for feFlood syntaxAttributes are result andflood-color : color name to fill rectangleflood-opacity : opacity for filling between 0 and 1Example 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 primitivePrimitive 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 25 height="NumberOrPercentage" xlink:href="URI"/> Diagram 8-13. Chart for feImage syntaxAttributes are result andxlink:href :URL of external graphic or defined elementExamples 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 primitiveWith feTile, we create tiling with given pictureThis is syntax for feTile element :
    • Learn SVG Chapter 8 Effective Filters 26<feTile id="name" in="SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>"/> result="<filter-primitive-reference>" x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage"/> Diagram 8-14. Chart for feTile syntaxAttributes for feTile are only x y width and height to define rectangular subregion wherecreate 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 nextprimitives in the same filter element.feTurbulence primitiveWith feTurbulence, we create texture.This is syntax for feTurbulence element :<feTurbulence id="name" result="<filter-primitive-reference>"
    • Learn SVG Chapter 8 Effective Filters 27 x="NumberOrPercentage" y="NumberOrPercentage" width="NumberOrPercentage" height="NumberOrPercentage" type="fractalNoise|turbulence" baseFrequency="NumberOptionalNumber" numOctaves="Integer" seed="Number" stitchTiles="stitch|noStitch"/> Diagram 8-15. Chart for feTurbulence syntaxAttributes aretype: fractalNoise or turbulencefor 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 borderExample 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.4k2=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 examplesFilter primitives to modify objectsfeGaussianBlur primitivefeGaussianBlur 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 syntaxfeGaussianBlur 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 32feMorphology primitivefeMorphology performs "fattening" or "thinning" of artwork. It is particularly useful forfattening 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 syntaxfeMorphology 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 33Figure 8-16 show effect of feMorphology primitive on svg objects and bitmap ( witherode and dilate for attribute operator. Figure 8-16. feMorphology on SVG objects and raster.feDisplacementMap primitivefeDisplacementMap uses the pixels values from the image from in2 to spatially displacethe 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 34 width="NumberOrPercentage" height="NumberOrPercentage" scale="Number" xChannelSelector="R|G|B|A" yChannelSelector="R|G|B|A"/> Diagram 8-18. Chart for feDisplacementMap syntaxfeDisplacementMap attributes are in in2 result andscale : number ( 0 by default give no effect )xChannelSelector : R G B or AyChannelSelector : R G B or AIn this code, we create pattern, fill rectangle (MyGrid), this rectangle is used as grid totransform 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 gridsWith feDisplacementMap, we can animate attribute "scale" and get fade-in out with fineeffects.feOffset primitivefeOffset offsets the input image relative to its current position in the image space by thespecified 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 36 dy="Number"/> Diagram 8-19. Chart for feOffset syntaxfeOffset primitive offsets the input image.feOffset attributes are in result anddx : offset for x ( 0 by default )dy : offset for y ( 0 by default )feConvolveMatrix primitivefeConvolveMatrix combines pixels in the input image with neighboring pixels to producea 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 37 divisor="Integer" edgeMode="duplicate|wrap|none"/> Diagram 8-20. Chart for feConvolveMatrix syntaxfeConvolveMatrix 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 39Filter primitives combinationWe see some combination of primitives, as feTurbulence, feColorMatrix andfeDiffuseLighting to create texture.How create 3D lighting effect ?We can usefeGaussianBlur to create shadow of objectfeOffset to offset this shadowfeSpecularLighting on picturefeComposite to composite original picture with shadow and lightingYou can find online ( pilat.free.fr ) tools to test some predefined combination ofprimitives.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 Chapter 8 Effective Filters 40How create filters ?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 chooseyour primitives, your pictures, modify values for all attributes, see final and all partialresults. 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 reusablesvg 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 41Filters and animationAll attributes of primitives can be animated.First example :focussing on a picture using feMorphology, values for attribute radius go from 8,8 to 0,0Figure 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=5sfill=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 42Second example :Simulate volcano eruption using feComponentTransfer and in feFuncR, slope go from 0.2to 2.2Code 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 thefollowing 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 specificationsLinkingLinking out of the svg contentSVG provides an a element, analogous to HTMLs a element, to indicate links.The destination for the link is defined by a URI specified by the xlink:href attribute onthe a element. The remote resource may be any Web resource (e.g., an image, a videoclip, a sound bite, a program, another SVG document, an HTML document, an elementwithin the current document, an element within a different document, etc.). By activatingthese 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 2Example 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 openin same window.Linking into svg contentWe can link into any element using id of element, but because SVG content oftenrepresents a picture or drawing of something, a common need is to link into a particularview 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 3Source 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 4Supported eventsEvents can be used in script or in attributes as begin or end for animation elements.First DOM2 category : UIEvent Event attribute Event name Description DOM2 name name Occurs when an element receives focus, such as when a text focusin DOMFocusIn onfocusin becomes selected. Occurs when an element loses focus, such as when a text focusout DOMFocusOut onfocusout becomes unselected. Occurs when an element is activated, for instance, thru a mouse click or a keypress. A numerical argument is provided activate to give an indication of the type of activation that occurs: 1 DOMActivate onactivate for a simple activation (e.g. a simple click or Enter), 2 for hyperactivation (for instance a double click or Shift Enter).
    • Learn SVG Chapter 9 Interactivity and Animation 5Second DOM2 category : MouseEvent Event attribute Event name Description DOM2 name 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 (same) onclick 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 (same) onmousedown element. Occurs when the pointing device button is released over an mouseup (same) onmouseup element. mouseover Occurs when the pointing device is moved onto an element. (same) onmouseover Occurs when the pointing device is moved while it is over an mousemove (same) onmousemove element. Occurs when the pointing device is moved away from an mouseout (same) onmouseout element.An event set designed for use with keyboard input devices will be included in a laterversion 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 6Third DOM2 category : MutationEvent Event attribute Event name Description DOM2 name name This is a general event for notification of all changes toDOMSubtree the document. It can be used instead of the more specific (same) none 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 (same) none 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 (same) none 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 aRemovedFrom subtree in which it is contained. (The normative (same) none 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 (same) none 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 (same) none Modified DOM2 specification.) Fired after CharacterData within a node has been DOM modified but the node itself has not been inserted orCharacterData (same) none deleted. (The normative definition of this event is the Modified description in the DOM2 specification.)
    • Learn SVG Chapter 9 Interactivity and Animation 7Events on document Event attribute Event name Description DOM2 name 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 (same) onload 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 (same) onunload document from a window or frame. The abort event occurs when page loading is stopped SVGAbort (same) onabort before an element has been allowed to load completely. The error event occurs when an element does not load SVGError (same) onerror properly or when an error occurs during script execution. The resize event occurs when a document view is resized. SVGResize (same) onresize (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 (same) onscroll 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 none onzoom elements.)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 inviewport 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 inwindow 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 8If 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.yto 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 9Events about animations Event attribute Event name Description DOM2 name name Occurs when an animation element begins. For details, beginEvent see the description of Interface TimeEvent in the SMIL none onbegin Animation specification. Occurs when an animation element ends. For details, see endEvent the description of Interface TimeEvent in the SMIL none onend Animation specification. Occurs when an animation element repeats. It is raised each time the element repeats, after the first iteration. For repeatEvent none onrepeat details, see the description of Interface TimeEvent in the SMIL Animation specification.Pointer-events propertyThe pointer-events property specifies under what circumstances a given graphicselement 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: yesThe given element can be the target element for pointer eventsvisiblePainted 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 equivalentThe values fill, stroke and all are equivalentFor raster images, hit detection is either performed on a whole-image basis (i.e., therectangular area for the image is one of the determinants for whether the image receivesthe event) or on a per-pixel basic (i.e., the alpha values for pixels under the pointer helpdetermine 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 elementCursor Propertycursor Value: [ [<uri> ,]* [ auto | crosshair | default | pointer | move | e-resize | ne- resize | 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: yesThis property specifies the type of cursor to be displayed for the pointing device. Valueshave 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 11default 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 markor a balloon.<uri> The user agent retrieves the cursor from the resource designated by the URI. If theuser agent cannot handle the first cursor of a list of cursors, it shall attempt to handle thesecond, etc. If the user agent cannot handle any user-defined cursor, it must use thegeneric cursor at the end of the list.Cursor elementThe cursor element can be used to define a platform-independent custom cursor. Arecommended approach for defining a platform-independent custom cursor is to create aPNG image and define a cursor element that references the PNG image and identifies theexact 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 arex : The x-coordinate of the position in the cursors coordinate system which represents theprecise position that is being pointed to.y : The y-coordinate of the position in the cursors coordinate system which represents theprecise position that is being pointed to.xlink:href : URI reference to the file or element which provides the image of the cursorAnimationCommon attributesTarget element for animationWe use xlink:href attribute as URI reference to the target of the animation.
    • Learn SVG Chapter 9 Interactivity and Animation 12If the xlink:href attribute is not provided, then the target element will be the immediateparent element of the current animation element.Target attribute or propertyWe use attributeName and attributeType attributes to specify the name of the targetattribute to be modified in animation.Values for attributes :attributeName="AttributeName"attributeType="CSS|XML|auto"CSS for a CSS propertyXML for XML attributeauto : The implementation must first search through the list of CSS properties for amatching property name, and if none is found, search the default XML namespace for theelement.Controling the timingThis attributes are common to all animation elements :To define when animation begin :begin= begin-value-listbegin-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 thedocument begin.With begin="10" animation start 10 seconds after loading SVG.syncbase-value : relative to begin or end of another animationWith begin="MyAnim.end+5" animation start 5 seconds after end of MyAnimanimation.event-value : begin on eventWith begin="MyRect.click+3" animation start 3 seconds after click on MyRect objectrepeat-value : begin after the repeat event is raisedWith begin="MyAnim.repeat(2)" animation start when MyAnim is repeated 2 times.accessKey-value : begin after key pressedWith begin="accessKey(g)" animation start when user press g key
    • Learn SVG Chapter 9 Interactivity and Animation 13wall-clock-sync-value : begin at a real-world clock time"indefinite" : begin is determined by beginElement() method call or hyperlink targetedto the element.To define duration of animationSpecifies the simple durationdur = Clock-value|"media"|"indefinite"Clock-value : specifies the duration in seconds"media" is ignored for SVG animation elements"indefinite" can be usefull for set elementTo define end of animationDefines an end value for the animation that can constrain the active duration.end = end-value-listend-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 callTo define minimum and maximum values for duration of animationmin = Clock-value|"media"Value by default is 0max = Clock-value|"media"To define when animation can restartrestart = "always"|"whenNotActive"|"never""always" : animation can restart at any time. Its 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 animationWe determine iterations of animation by number or duration :repeatCount = Integer|"indefinite"
    • Learn SVG Chapter 9 Interactivity and Animation 14repeatDur = Clock-value|"indefinite"With "indefinite", animation repeat indefinitely ( until th document ends )To define effect when animation stopfill = "freeze"|"remove"With fill="freeze", the animation effect is frozen for the document duration or untilanimation restart.With fill="remove", the animation no longer affects the target. It is the default value.Animation values over timeThis attributes have no effect for set element except to attribute.To define interpolation mode for the animationcalcMode = "discrete | linear | paced | spline"discrete : Animation function will jump from one value to the next without anyinterpolation.linear : Simple linear interpolation between values is used to calculate the animationfunction. 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 somenotion 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 timefunction defined by a cubic Bézier spline. The points of the spline are defined in thekeyTimes attribute, and the control points for each interval are defined in the keySplinesattribute.To define values to useWe 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, viewBoxwill 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 fromred to yellow and then to green.from = "value"
    • Learn SVG Chapter 9 Interactivity and Animation 15We give value to start animation. In our example for viewBox, we can writefrom="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 animationKeyTimeskeyTimes = "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 animationelement.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 of10 seconds ( dur="10" ), and that values are for width attribute of a rectangle, we get thisanimation :From 0 to 1.95s, width of rectangle increase from 0 to 400from 1.95s to 4.05s width of rectangle decrease from 400 to 47.5from 4.05s to 7s width of rectangle increase from 47.5 to 450andfrom 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 Chapter 9 Interactivity and Animation 16KeySplineskeySplines = "list of list of 4 numbers between 0 and 1"A set of Bézier control points associated with the keyTimes list, defining a cubic Bézierfunction that controls interval pacing.If there is no value for keyTimes, we can use a cubic Bezier function that controls pacingfor 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" andcalcMode="spline"we get same four steps in animation, but we have speed which increase on steps 1 3 4and decrease on step 2 Figure 9-4. KeySplines and speed Figure 9-5. KeySplines and speed
    • Learn SVG Chapter 9 Interactivity and Animation 17Figures 9-4 and 9-5 show how is speed with two examples of values for keySplinesWe can use keyPoints for animateMotion ( see below )To control if animations effects are additiveValues given for attribute can be added to existing value or replace it :additive = "replace|sum"replace : animation values replace existing value. Its default value.sum : animation values added to existing valueWhen 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. Its default value.Data types used with additive and accumulate can be :<angle>, <color>, <coordinate>, <integer>, <length>, <number>, <paint>, <percentage>,<uri> and <transform-list>.Set elementThe set element provides a simple means of just setting the value of an attribute for aspecified 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 18All 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 syntaxTo show utility of this element, we create a drop down list to select a color to fill arectangle or other element.When user click on ∇ , list of colors is writed, when pointer is on color, there is a grayrectangle on it to show that this color is selected. If user click on it, color is choosed, listof 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 colorAnimate elementThe 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 syntaxFor 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 shapeSome attributes give very interesting effect, by example stroke-dashoffset allowprogressive 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 22As length of line is 400, with "stroke-dasharray:400 400;stroke-dashoffset:400" the line isnot drawed.If we change value for stroke-dashoffset, we see that if we go from 400 to 800, we getprogressive 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-dashoffsetTo get progressive drawing of line we can write :<path d="M20 20l400 0" style="stroke-dasharray:400 400;stroke-dashoffset: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, pathelement.We use fill="freeze" to keep drawing of line at the end of animation.Morphing with animate on d attribute of pathIf we give values over animation for d attribute of a path, we can obtain morphing insome cases, by example :- we have only lineto commands and there is same number in all values- we have Bezier cubics or quadraticsFirst example with only lineto commands in paths :The square become a star, Figure 9-8 show some steps of morphingSource 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 starSecond example with quadratic Bezier curves and text on path :We get morphing for text on pathFigure 9-9 show some steps for animationSource 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 Beziers 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 25Moving text on path with startOffsetWe 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 Beziers curveSource 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 Beziers 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 elementThe animateColor element specifies a color transformation over time. Diagram 9-3. Chart for animateColor syntaxThis 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 27 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.For values, from,to and by attributes, data types can be only <color>.AnimateTransform elementThe 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 syntaxAll this attributes are explained above except type .Attribute type Indicates the type of transformation which is to have its values changeover 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 29Figure 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 skewYWe can use animateTransform element to create effect on letters of word SVG, eachletter turn around vertical axis. We add animateColor element to change color for fillingletters 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 axisAs we use scale transformation, center is at origin, so we define letters with y="0" andput 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 elementThe 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 foreignObjectThis is the syntax of this element :<animateMotion id = "name" xlink:href = "URI" attributeName = "AttributeName"
    • Learn SVG Chapter 9 Interactivity and Animation 31 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>All this attributes are explained above except :path : The motion path, expressed in the same format and interpreted the same way as thed attribute on path element.keyPoints : a semicolon-separated list of floating point values between 0 and 1 andindicates how far along the motion path the object shall move at the moment in timespecified 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 syntaxTo 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 havekeyTimes = "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 seconds2) Object go back to quarter of trajectory in 2.5 seconds3) Object go ahead to three quarters of trajectory in 2 seconds4) Object go to end of trajectory in 3 seconds
    • Learn SVG Chapter 9 Interactivity and Animation 33Figure 9-14 show this example. Figure 9-14. keyPoints and keyTimesWe 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 34Animation and scriptingWe can create animations by script or use script to create animated elements.Script to create animated elementsWith example of each letter of word SVG turning around vertical axis, we can by scriptobtain 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 andtranslate to put letter in place.We must use additive=sum to only modify values for scale and keep same translatetransform.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 easiercode for svg elements.Script to create animationWe 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 38 translate(+x_letter[i]+,+y_letter[i]+ ) matrix(+taille+ 0 0 1 0 0));// 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 DOMWhat we’ll 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 skillsThe 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, we’ll 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 don’t 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 won’t 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 2 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 Manufacturers’Association’ (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. Netscape’s Javascript and Microsoft’s 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 won’t cover the whole of the ECMAScript language. Instead we’ll 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 doesn’t 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. Let’s have a closer look at the data types in detail ECMAScript can deal with.
    • Learn SVG Chapter 10 Scripting the DOM 3Number 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 // negative and positive integers .. -6.28, 0.25, 66.666667 // negative and positive fractional numbers .. 0.001, .001, 1.0e-3, 1E-3 // variations of one per thousandString 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 you’ve opened with a single quote and closed with a double. ”a short text”, ’another text’ // the text delimiters .. ”mike’s bike”, ’he said: ”hello”’ // inverse delimiter usage .. ’c’, ’C’, ”4”, ’”’, ” ” // different single characters .. ””, ’’ // the empty string .. ”””, ”n”, ’’’, ’’ // special characters, escape via backslashBoolean There is also a logical data type. This Boolean type can have one of two values. true, false // the two Boolean values .. In ECMAScript the values ‘true’ and ‘false’ conform to ‘1’ and ‘0’.Object 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. We’ll 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 program’s 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 4 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 variable’s name. Since ECMAScript is a loosely typed language, a variable can hold a value of any data type. During the variable’s lifetime that data type can even change. var pi = 3.14, radius = 100; // define two variables .. var circumference = 0, area = 0; // .. and another two .. circumference = 2*pi*radius; // assign a value .. area = pi*radius*radius; // .. to each variable pi = ’hello’; // change pi’s 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. • ECMAScript’s 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”; // defining some .. var color = ”green”; // .. variables 2+3/2 // 3.5 (2+3)/2 // 2.5 radius*2/10 // 20 2*pi*radius; // 628 radius == 100 // true str == ”blue” // false str + ” Mary” // ”hello Mary”
    • Learn SVG Chapter 10 Scripting the DOM 5 str.length // 5 Math.sin(Math.PI/2) // 1 color == ”red” || color == ”blue” // false An expression can consist of • Numbers, Strings, Boolean literals • Operators (+, -, *, /, …) • Variables • Function calls • Object properties or object method calls An expression’s 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 Means Example Equals Arithmetic operators + Addition 1+2 3 - Subtraction 8-6 2 * Multiplication 2*3 6 / Division 10/3 3.3333333333 % Modulus 10%3 1 ++ Increment x = 3; x++ x=4 -- Decrement x = 5; x-- x=4 - Negation -2 negative 2 Assignment += Addition x += y x=x+y operators -= Subtraction x -= y x=x-y *= Multiplication x *= y x=x*y /= Division x /= y x=x/y % Modulus x %= y x=x%y String operators + Concatenation "hello "+"world" "hello world" += Concatenation a += b a=a+b Comparison == is equal to 2 == 3 false operators != does not equal 2 != 3 true > is greater than 5>3 true is greater than or >= 5 >= 3 true equal to < is less than 5<3 false is less than or <= 5 <= 3 false equal to Logical operators && AND (3 <= 5) && (5 < 8) true || OR (5 > 3) || (3 > 5) true ! NOT 5 != 3 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 6Statements 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 if…else The if..else statement adds the ability to specify alternate lines of code for a case when the if- condition 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 Chapter 10 Scripting the DOM 7Iteration Statements The repetitive while-statement works in a similar fashion to the if statement, with the difference that the affiliated statements aren’t 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 we’d 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 I’ll introduce you to ECMAScript’s important for statement. Let’s 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 loop’s 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 8 for (;;) // ’forever’ .. all sections are empty .. { if (hour >= 22) break; action = ”working”; } There are more conditional and iteration statements in ECMAScript, but we won’t cover them here. Those of you wishing to discover the joys of switch…case, do…while and for…in will have to hunt elsewhere.ECMAScript Functions As I’ve 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, wouldn’t 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 Let’s 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 9 Let’s 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 LengthOfLine3. 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 function’s body.4. That function body is always enclosed in curly braces {..} immediately following the function’s 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 line’s length lenSqr, according to Pythagoras Theorem (c2 = a2 + b2). lenSqr = dx*dx + dy*dy6. To get the actual length len of the line, we use an ECMAScript object’s 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 lenCalling 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 definition’s 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 function’s 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 function’s 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 it’s 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 Object’s members. If a member is a variable, we call it an Object’s property. If a member is a function, it is called an Object’s method. In order to access an object’s 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 // Object’s properties .. document.write(”hello”) // Object’s method call .. var group = null; // variable with no value .. But where do we meet objects? • ECMAScript comes with a few intrinsic objects. • The W3C’s 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 won’t 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 Chapter 10 Scripting the DOM 11 • Array • Boolean • Date • Function • Global • Math • Number • Object • RegExp • Error • String If you are experienced with other object oriented languages, you might ask, why we don’t 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. Let’s 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. Let’s 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>"); // "mon" .. first element of days .. document.write(days[7] + "<br>"); // undefined .. document.write(days.length + "<br>"); // 7 .. months[1] = "feb"; // set months 2nd value to "feb" .. document.write(months + "<br>"); // ,feb,,,,,,,,,,, </script> </body> </html> 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(); create empty Array (no argument) new Array(n); create Array of length n (one number argument) new Array(x1,x2,..,xn); 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 it’s 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) the absolute value of a number n. o Math.sin(n) the sine of a number n. o Math.cos(n) the cosine of a number n. o Math.atan2(y,x) the angle in radians of a vector (x,y) with respect to the positive x-axis. o Math.sqrt(n) 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 W3C’s 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 won’t use them all, nor will we use and thus learn them completely.The ones we’ll cover here are: • Node Common interface for elements, attributes and text nodes • Document Interface for the document object. • Element Interface for element objects. • Text Interface for text node objects. • Event Interface for event objects.The DOM tree It’s 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 let’s have a look what these are.Climbing our Tree As we’ve 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 DescriptionElement documentElement the document object belonging to this node.
    • Learn SVG Chapter 10 Scripting the DOM 14Node informational properties:Value Property DescriptionString 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. ELEMENT_NODE = 1; ATTRIBUTE_NODE = 2; TEXT_NODE = 3; CDATA_SECTION_NODE = 4; ENTITY_REFERENCE_NODE = 5; ENTITY_NODE = 6;Number nodeType PROCESSING_INSTRUCTION_NODE = 7; COMMENT_NODE = 8; DOCUMENT_NODE = 9; DOCUMENT_TYPE_NODE = 10; DOCUMENT_FRAGMENT_NODE = 11; NOTATION_NODE = 12;Node navigational properties:Value Property DescriptionNode ownerDocument the document object belonging to this node.Node ParentNode the parent node of this node.Array ChildNodes an array of the child nodes of this node.Node FirstChild the first child node of his node.Node LastChild the last child node of his node.Node previousSibling the node preceding this node.Node nextSibling 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" stroke- linecap="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 don’t 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 boxMoving 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, let’s 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 16wagon1. ownerDocument<svg> <svg>|_ <defs> |_ <defs>| |_ <g id="carriage"> | |_ <g id="carriage">| ||_ <g id="train"> |_ <g id="train"> | | |_ <g id="engine"> |_ <g id="engine"> | |_ <use href="carriage"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <polyline> // cabin | |_ <rect> // green box | |_ <rect> // green box | | |_ <g id="wagon1"> |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // red coil | |_ <circle> // blue coil | |_ <circle> // blue coil | | |_ <g id="wagon2"> |_ <g id="wagon2"> |_ <use href="carriage"> |_ <use href="carriage"> |_ <text> // big letter |_ <text> // big letter |_ <rect> // blue box |_ <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. previousSibling<svg> <svg>: :|_ <g id="train"> |_ <g id="train"> | | |_ <g id="engine"> |_ <g id="engine"> | |_ <use href="carriage"> | |_ <use href="carriage"> | |_ <polyline> // cabin | |_ <polyline> // cabin | |_ <rect> // green box | |_ <rect> // green box | | |_ <g id="wagon1"> |_ <g id="wagon1"> | |_ <use href="carriage"> | |_ <use href="carriage"> | |_ <circle> // red coil | |_ <circle> // red coil | |_ <circle> // blue 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. nextSibling. nextSibling<svg> <svg> <svg>: : :|_<g id="train"> |_<g id="train"> |_<g id="train"> | | | |_<g id="engine"> |_<g id="engine"> |_<g id="engine">
    • Learn SVG Chapter 10 Scripting the DOM 17 | |_<use | |_<use | |_<usehref="carriage"> href="carriage"> href="carriage"> | |_<polyline> // cabin | |_<polyline> // cabin | |_<polyline> // cabin | |_<rect> // green box | |_<rect> // green box | |_<rect> // green box | | | |_<g id="wagon1"> |_<g id="wagon1"> |_<g id="wagon1"> | |_<use | |_<use | |_<usehref="carriage"> href="carriage"> href="carriage"> | |_<circle> // red coil | |_<circle> // red coil | |_<circle> // red coil | |_<circle> // blue | |_<circle> // blue | |_<circle> // bluecoil coil coil | | | |_<g id="wagon2"> |_<g id="wagon2"> |_<g id="wagon2"> |_<use |_<use |_<usehref="carriage"> href="carriage"> href="carriage"> |_<text> // big letter |_<text> // big letter |_<text> // big letter |_<rect> // blue box |_<rect> // blue box |_<rect> // blue box You see that previousSibling and nextSibling are a comfortable way to step along the nodes of a certain tree level. Now let’s 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 nextSibling. nextSibling<svg> <svg> <svg>: : :|_<g id="train"> |_<g id="train"> |_<g id="train"> : : : |_<g id="wagon2"> |_<g id="wagon2"> |_<g id="wagon2"> |_<use |_<use |_<usehref="carriage"> href="carriage"> href="carriage"> |_<text> // big letter |_<text> // big letter |_<text> // big letter |_<rect> // blue box |_<rect> // blue box |_<rect> // blue boxor alternatively var blueBox = wagon2.lastChild;wagon2. lastChild<svg> <svg>: :|_<g id="train"> |_<g id="train"> : : |_<g id="wagon2"> |_<g id="wagon2"> |_<use href="carriage"> |_<use href="carriage"> |_<text> // big letter |_<text> // big letter |_<rect> // blue box |_<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 list’s 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 engine’s cabin.
    • Learn SVG Chapter 10 Scripting the DOM 185. For this we’ll need to go up one level, stepping back onto the engine. From there we can step down to the engine’s child nodes then shimmy along until we reach the cabin, as shown below. var cabin =blueBox.parentNode.previousSibling.previousSibling.firstChild.nextSibling; previousSibling.previousSiblinblueBox.parentNode. firstChild.nextSibling g.<svg>: <svg>|_<g id="train"> : | <svg> |_<g id="train"> |_<g id="engine"> : | | |_<use |_<g id="train"> |_<g id="engine">href="carriage"> | | |_<use | |_<polyline> // cabin |_<g id="engine"> href="carriage"> | |_<rect> // green box | |_<use href="carriage"> | |_<polyline> // cabin | | |_<polyline> // cabin | |_<rect> // green box |_<g id="wagon1"> | |_<rect> // green box | | |_<use | |_<g id="wagon1">href="carriage"> |_<g id="wagon1"> | |_<use | |_<circle> // red | |_<use href="carriage"> href="carriage">coil | |_<circle> // red coil | |_<circle> // red coil | |_<circle> // blue | |_<circle> // blue coil | |_<circle> // bluecoil | coil | |_<g id="wagon2"> | |_<g id="wagon2"> |_<use href="carriage"> |_<g id="wagon2"> |_<use |_<text> // big letter |_<usehref="carriage"> |_<rect> // blue box href="carriage"> |_<text> // big |_<text> // big letterletter |_<rect> // blue box |_<rect> // blue box Remember that we can always go up one level with parentNode — we don’t 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 train’s 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 I’d 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 ExampleNow let’s build a complete working SVG document with scripting here. For this we first have toresolve 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 whitespacenodes.No problem with the event handling here. We will just use it, I will explain it to you later. Dealingwith 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 thattext may consist purely of spaces (·) or newlines (¶). Such a series of spaces and newlines will beinterpreted 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. Theproblem arises, if we want to get the next node of the line element. nextSibling won’t provide uswith 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 toget 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 20function 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 willsimply use it. Since we will reuse this function in several SVG documents, we decide to put it intoan 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 object’s 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" stroke- linecap="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 SearchingThe 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 Let’s 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 Array getElementsByTagName(tagName) An array of element nodes with this name. Element getElementsById(elementId) The element with an Id that has this string value.1. Now, as an example, let’s 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> <!-- trains geometry goes here --> </svg> With this we will receive the following output: Element 0 of type: g Element 1 of type: g Element 2 of type: g Element 3 of type: g Element 4 of type: 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 object’s 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 element’s attributes. This is not very mysterious. There are two different methods of the Element object to help with attribute access.Element’s attribute access methods:Return Value Method Description The value of the attribute with the name attrName as aString getAttribute(attrName) string. setAttribute(attrName, set the attribute with the name attrName value tovoid newValue) newValue. Firstly I’d like to focus on the getAttribute method in particular. Let’s 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> element’s 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 engine = evt.target.ownerDocument.getElementById("engine"); var groups = engine.ownerDocument.getElementsByTagName("g"); var wagon = null; // null as long as you didnt find it .. var 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> <!-- trains 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, it’s about time we learned how to modify the attributes we find along the way. The Element’s 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 it’s colour isn’t 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 trains geometry goes here --> </svg>2. Still sitting in the engine’s 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! Let’s 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 don’t 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 rect’s 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 it’s 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. It’s 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"; // whose value we need to change. } else // oops window.alert("I lost a letter on the way - or got some more!"); } ]]> </script> <!-- the trains geometry goes here --> </svg> It’s a bit strenuous to look around the big golden box just to see the result. Figure 10-3. Changing letterNow we have learned how to change attributes and textual content of SVG elements, and with thisarmoury are able to put right any potential faults in our document.Removing Elements and Attributes We’ll kick off here with removal, as with the DOM, as in real life, it is always easier to destroy something than to build it. I’d like to introduce you to two methods.Node’s remove method: Node removeChild(node) remove this node from the tree.Element’s attribute removal method: Node removeAttribute(attr) remove the element’s 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 we’ll understand this best by example. Remember that you are still sitting in the engine’s 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. Let’s 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 28 | |__ <circle> // red coil | 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, here’s a handy bit of code designed to remove all child elements of any parent from beginning to end while (parent.firstChild != null) parent.removeChild(parent.firstChild);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 I’ll present you with some useful methods that we’ll 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.Document’s creation method:Return Value Method DescriptionElement createElement(tagName) Creates a new element of type tagName.Node’s creation method:Return Value Method DescriptionNode cloneNode(deep) Create a clone of itself.Node’s inserting methods:Return Value Method DescriptionNode insertBefore(node, child) Insert node node before child node child into the children list.Node appendChild(node) Append node node at the end of the children list.Node 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 DOM’s 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 object’s createElement method.2. Add the new node to the tree using one of the Node object’s 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 object’s 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 let’s 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, you’ll 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 didn’t 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 objects2. 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 won’t 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 I’ll 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, it’s pretty hard to beat!Finally, I want to present you the total source of the track example, with the individual actionsorganized 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 didnt 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 33 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); } ]]> </script> <defs> <g id="carriage"> <line x2="150" y2="0" stroke="gray" stroke-width="10" stroke- linecap="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. You’ve had to learn a lot so far, but nothing we’ve achieved has really fitted either of these categories. “You’ve misled us” I hear some of you cry. Well, to those people I’ll simply say “Let’s 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 we’ll 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. Here’s 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 property’s 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 you’ll 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 eventsevent Descriptiononload the load event occurs, when the SVG rendering engine has completely loaded the element.User interface related eventsevent Descriptiononzoom the zoom event occurs, when the zoom level of the SVG document changes.Mouse eventsevent Descriptiononclick the user presses and releases the mouse button.onmousedown the user presses the mouse button.onmouseup the user releases the mouse button.onmouseover the user moves the mouse pointer over an element.onmouseout the user moves the mouse pointer away from the element.onmousemove 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 aren’t 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 you’ll find the ones relevant to the rest of this book.Event’s properties:Value Property DescriptionString type the event type as a string.Element currentTarget the registered event listener element for this event.Element target the initiating element for this event. Usually an event listeners child.Event’s method:Return Value Method Descriptionvoid stopPropagation() prevent further propagation during event flow. I need to introduce you also to the more specialised MouseEvent object.MouseEvent’s properties:Value Property DescriptionString type the event type as a string.Element currentTarget the registered event listener element for this event.Element target the initiating element for this event. Usually an event listeners child.Number clientX the x-coordinate of the mouse pointers location in SVG world coordinates.Number clientY the y-coordinate of the mouse pointers location in SVG world coordinates.
    • Learn SVG Chapter 10 Scripting the DOM 36Number button information about the mouse button pressed (0,1,2 for left/middle/right).Number detail count of mouse clicks (onclick only).Element target the initiating element for this event. Usually an event listeners child. A particular Event object is not only passed to a single element’s 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 element’s 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 event’s 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 let’s 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 object’s 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 We’ll 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 we’ll 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 Chapter 10 Scripting the DOM 40Mutating Elements 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 element’s 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 we’ll want to differentiate between single and double mouse clicks. If you’ve read the MouseEvent’s properties, you’ll 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 we’ll 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. We’ll 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 didn’t 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 mouse1. 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 document’s upper right corner and a moccasin coloured rectangle. The last two text elements only display the coordinates of the rectangle’s 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 rectangle’s 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 doesn’t 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 event’s originator.
    • Learn SVG Chapter 10 Scripting the DOM 453. Try giving this SVG engine what it demands: A rectangle as big as the width and height of the document. <rect x="5" y="5" width="390" height="290" stroke="black" fill="none" /> This doesn’t 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 element’s 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. Eyes2. As we discovered in the last exercise, we’ll need a filled rectangle as an event generating background. This is the document’s 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 eye’s centre to the affiliated pupil’s 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 476. Calculate angle of the line from the eye’s centre to the mouse pointer coordinates relative to the positive x-axis. Rotate the pupil about the eye’s centre with this angle. We use rotate(angle, cx, cy) here. Draw the ray from the eye’s 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")), // 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. } 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 48 Figure 10-19. Magic eyes for another position 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.