Go Shopping with SVG: A Hands-on Graphics Tutorial

Go Shopping with SVG: A Hands-on Graphics Tutorial

f you look through the help-wanted ads, chances are you won’t see many advertisements for SVG gurus?not yet. No one is making next generation animation with it, it’s not a buzzword in entertainment circles, and even among those to whom the letters XML have real meaning, SVG doesn’t generate much interest. But it will.

Sometimes, it’s wise to pay special attention technologies that catch on despite not having massive advertising budgets behind them. Apple promotes Quicktime extensively, through cross-licensing deals with artists and movie houses. Macromedia’s Flash is their bread and butter, and the vector animation format is pushed for just about everything, again with budgets in the hundreds of thousands?if not millions?of dollars. Compared to that, Scalable Vector Graphics gets very little promotion and is spoken of in hushed tones by XML-oriented techies. At first glance, SVG appears to be missing in action. This is because it is an open standard being promoted by the World Wide Web Consortium, an organization with a total budget probably smaller than that of some of those Flash movies.

Despite this, SVG is showing up in some very surprising places. If you have Adobe Acrobat on your system, you probably have the SVG core in place. The Real One player, still the dominant music and video player in the field, runs interactive SVG players. Adobe Illustrator and Corel Draw both support SVG input and output. If you have a Nokia phone, you might be surprised to find that it supports a very full-featured interactive SVG engine.

On the Linux side, KDE 3.1 supports SVG icons, with the deep secret being that the utility that generates these icons is one small piece of an SVG engine to be released with KDE 3.2. This small piece will turn the entire desktop into an interactive SVG shell, something that will radically shape the nature of Linux and will be explored more in this article. Microsoft is getting into the vector game as well, through Microsoft Longhorn, which will likely include interfaces for supporting SVG as an (admittedly non-native) format in their own desktop environment.

Within the next two to three years, graphical user interfaces on just about every major platform are poised to “go vector.” Because of this, you could do a lot worse in this rough and tumble economy than to become conversant with what will likely become the dominant graphics environment on both the Web and the desktop by 2007.

In July 2003, Adobe released the SVG 6.0 viewer as a beta. This preview supports the full 1.0 and 1.1 SVG specifications as well as acting as a test-bed for a number of the more intriguing 1.2 proposals currently on the table. For desktop use, it is arguably one of the best SVG viewers for Windows systems (there is also a version for Linux, though it is not as feature rich, and may ultimately be supplanted by KSVG). This beta version is available here. Please note that this version is still very much in beta, and while it’s generally quite functional, it may be changed as the SVG 1.2 spec becomes more solid.

What Makes a Good SVG Application?
SVG’s whirling letters, animated shapes, and intrinsic vector nature can trick you into viewing it as the XML version of Macromedia Flash. This is unfortunate, since while creating real-time animation is achievable in SVG, takes a great deal of work to do even remotely well.

Consequently, in order to best understand where SVG may have application in your projects, I’ve outlined a few applications where SVG works especially well, as well as a few where other technologies may be more appropriate.

Maps. This is perhaps SVG’s greatest strength. Even without SMIL animation, SVG maps can still have links associated with individual map elements such as rooms, streets, or cities?something which is much harder to accomplish with HTML image maps. The Geographical Information Services sector (or GIS) was one of the earliest adopters of SVG, and it is rapidly replacing older graphical formats as a means of storing information. This task is facilitated by SVG’s ability to simultaneously work with multiple coordinate systems and to work with libraries of external SVG.

The principle advantages of SVG comes in those situations where the metadata of the content?the data structure implicit in graphs and charts, the meaning behind various map symbols, the ability to indicate multi-state transitions, and so forth?is as important as the graphic itself.

Intelligent Charts and Graphs. SVG is XML-based, but it also includes a Web services aware DOM. This makes it a remarkably useful tool for developing charts and graphs, especially those that are time dependent. What’s more, because of the inherent intelligence of such charts, they can initiate certain actions (playing warning sounds, for instance, or launching separate processes) when the right conditions exist. However, SVG charts, maps, and graphs?even static ones?can incorporate a high amount of metadata that other formats generally can’t equal.

Process Monitoring. The same capability that makes SVG useful for live charts also makes it useful for monitoring (or setting) processes. Everything from showing available seating on aircraft or theaters to keeping track of lights in the theater to showing critical systems schematics on the aircraft, highlighted to show critical usage. This kind of application may grow in importance as automated wireless sensors become more ubiquitous.

Slide Shows. Business slide shows?PowerPoint presentations being most obvious example? incorporate multilayered, structured data, transitions from page to page, and a high amount of metadata. In short, they are almost ideal vehicles for SVG, especially with the rich content implicit in SVG 1.2.

“Traditional” User Interfaces. This area is beginning to get more interest, especially as vector graphics moves in via foundation libraries (such as KSVG). Here, the interface elements?windows, buttons, scroll-bars, etc.?are built using SVG. SVG 1.1 is not yet robust enough to handle this particular use without a lot of work, but the upcoming SVG 1.2 will likely take it a long way towards reaching this goal.

Multimedia “Kiosks”. SVG (especially 1.2) can handle video and audio, pull in external links and use them as a library, and integrate scripting support. This makes them a fairly decent choice for kiosks, children’s games, and similar applications?with a decent editor capable of producing SVG.

Animation. SVG can be used for animation work, a la Flash. However, a growing consensus of SVG developers feel this functionality is well into SVG’s future, principally because this field is already heavily dominated by a few commercial players and the XML advantage is not as strong here as it is elsewhere.

Generally, the principle advantages of SVG comes in those situations where the metadata of the content?the data structure implicit in graphs and charts, the meaning behind various map symbols, the ability to indicate multi-state transitions, and so forth?is as important as the graphic itself. Where the content has less “external meaning”?a sequential animation, for instance&#151the advantages of SVG begin to wane compared to existing commercial solutions.

Designing the Sophisticated Mall
This article’s sample application is a kiosk application for a “Sophisticated Mall,” which lets the user see information about each store in a visually accessible manner.

There are two different ways that such an application can be written. The first, and simplest, is to create a specific mall graphic with assignable stores, moving the metacontent about each store (a name, description, perhaps an image or other content) into a separate XML file. The thinking behind this is that while the occupants of the stores may change (or, more importantly, relevant information about these stores such as what items are on sale) will likely change daily, the specific layout of the mall is fixed.

The second approach would be to actually incorporate the specific shapes and positions of each store within the external file. For objects that change regularly (such as the layout of smaller vendor stands) this may actually provide more flexibility. On the other hand, it makes the code harder to understand.

Figure 1. The Sophisticated Mall: Users mouse over each store and click for more information.

The application for Sophisticated Mall uses the first approach. Figure 1 shows a single story mall with thirty-two stores, as well as assorted service areas like information kiosks and bathrooms. Each store has a number of useful pieces of metadata?the name and description of the store, a list of categories that indicate the kind of products or services the store sells, a graphic image that appears when the user mouses over a store with the mouse, and a movie that plays when the user clicks on the store. Additionally, beneath the mall graphic itself is a set of buttons for each category, letting the user highlight only the restaurants, or children’s clothing outlets, or mall services.

The application combines multimedia layers with an external dataset; if you change any piece of data and refresh the map, the page will change accordingly. This means that you could modify this application such that, rather than (or in addition to) containing categories, the data source document contained featured sales, activities of the day, and so forth.

This data file (shown in Listing 1) comes in two parts. In the first part, a series of category terms are defined. Each term maps a category key with a particular title (and could also link this same title to a description element, though this isn’t demonstrated here). By listing these terms up front, it also establishes the order in which the buttons for selecting stores that match these categories are shown. For instance, a category term for “Cards and Gifts” may look something like:

Once these items are defined, each store entry is defined, providing a name, description ,and associated list of categories (a store can fall into more than one). For instance, the “Destruction Channel” store is in the cards_and_gifts, toys_and_games and cds_video_and_dvds categories:

			The Destruction Channel		Learn Science by Watching Things Go Boom!		cards_and_gifts		toys_and_games		cds_videos_and_dvds	

Additionally, a store has an optional image and video attribute. Whenever a store with an associated image is rolled over, the image ends up appearing on the right hand side. Clicking on the store with a video attribute will start a video of the store running at that same location.

Building the Mall
SVG is an XML document, and as such, prior to establishing the document element of the SVG, you can specify a stylesheet. The Mall.svg (Listing 2) file does so declaring a (more or less) standard CSS stylesheet. Though these are principally used for defining CSS classes rather than setting individual element appearances directly:

This mall.css (Listing 3) file contains a series of class definitions, which in general look like the following:

	.str0 {stroke:#1F1A17;stroke-width:28}	.background {fill:url(#kioskBackground)}	.mall {fill:url(#mallBackground);stroke:#1F1A17;stroke-width:28}	.store {fill:url(#store);stroke:#1F1A17;stroke-width:28}	.storeCategory {fill:url(#storeCategory);stroke:#1F1A17;stroke-width:28}

Note that you can reference certain paint servers, such as gradients, within a CSS style using the fill:url() notation and placing a reference to an external item.

The mall graphic itself contains a mix of explicitly stated content and content generated from Javascript (shown in Listing 4). The SVG document declares the two relevant SVG namespaces, the default SVG namespace and the XLink namespace used for linking internal content.

The element then specifies the width and height of the container and creates a ViewBox (a graphics context) with the origin at the upper left corner, and 1000 user units per inch of height. It’s worth remembering here that the user coordinate system only provides an abstract coordinate layer?the SVG processor will map this abstract coordinate system into the physical pixel coordinates used by the operating system.

The SVG block is used to define static graphics primitives. Some of the more useful of these are custom gradients that can be used here to signify certain states for the stores and for the category buttons. The semantics of the gradients id make it possible to define “colors” that have specific relevance?such as the “store” and “storeHighlight” colors, defining the neutral and highlighted (rolled over) state of any store (or store-like region, such as a bathroom or information kiosk).


In addition to the gradients, the defs section also defines the standard “button” used for selecting a given category:


The element bundles both the rectangle and the associated text box together into a single unit, setting up a format in which the word “template” will get replaced with the appropriate category ID. For instance, the code for “restaurants” would use the template to generate a button which looks like this:


The mall itself is outlined with a thicker border, and can be selected as a separate entity on a mouseover, which handles displaying “default” information using the displayInfo() function. This is defined later in the scripts.


Each store’s shape is defined using one or more graphical primitives (usually, but not always, paths), contained in a single element that acts as the aggregator for events:


Each store’s id ties it to the XML document defined previously, while the class attribute applies the appropriate CSS class to each shape. Note that again the displayInfo() function is invoked on a mouseover, overriding the invocation on the previous shapes. The showVideo() function is called upon a mouseclick to begin a video.

The use of the evt object here can seem to be a little confusing. Within SVG, every time an event handler invokes a function, the SVG processor passes an event object in after all declared parameters. This object can be queried for information about which object the event occurred to, what event was invoked, and in mouse-centric activities, where the mouse was relative to the client window. The evt parameter used here is undefined and is for placeholder value only; the more salient evt parameter on the function declaration wil contain an instance of the event.

The next layer is strictly an SVG 1.2 feature?the use of the tag to embed HTML content that can later be referenced. In this case, the tag displays the description and title of each shop in the upper-left hand area:


Sophisticated Mall

Sophisticated Stores for the Discriminating Shopper.

Significantly, even though this information is in a “foreign” namespace, the SVG DOM can in fact manipulate it. Thus both storeName and storeDesc can be populated with new content through DOM calls. This gives you at least a subset of Dynamic HTML within the SVG environment. The HTML is displayed relative to its internal viewBox coordinate system.When a store is moused over, a picture is displayed in the upper-right hand side. When the store is clicked, this initiates a video (SVG 1.2 only). These need to be placed within the environment, even if they inititally do not point to anything useful.


The video element in particular illustrates some of the power of the declarative paradigm. The link (xlink:href) points to the video resource, with the specific formats dictated by the given SVG viewer. For instance, the Adobe SVG viewer beta currently works with Microsoft AVI, MPEG, Quicktime, Shockwave, and other formats. The begin attribute indicates that whenever the storeLayer (or any item within the story layer) is clicked, the movie should start, while the restart attribute indicates that whenever the event is invoked, the video should start over. The specific resource is set using the xlink:href attribute.

The final two lines in the SVG (before it’s closed out with the tag) define the location where the legend is drawn, and point to the location of the scripts respectively. Note that the syntax for the


It is worth noting in general that the principal purpose of the SVG is to either define the resources or establish the location in the local coordinate system where particular pieces end up appearing. In this role, SVG acts more like an application such as Visual Basic, placing the components in place then letting the code layer handle the otherwise undefined state management of these components.

Enabling the Mall
With SVG 1.0/1.1, a significant amount of the work involved in creating an application resides within the scripting layer, manipulating the DOM. This will likely change somewhat in the face of Rendered Custom Content (RCC), which is a technology for formatting elements using XML (and probably XSLT). For now, though, DOM is likely be the tool of choice for manipulating SVG for quite some time.

The file mallScripts.js contains a number of functions that handle significant amounts of the automation in the mall. The key to working with them is to understand the use of the mallData variable, which holds the contents of the stores.xml file. This file is retrieved through the retrieveData() and retrieveDataCallBack() functions.

The first launches an asynchronous request using the getURL() function, which both specifies the file to retrieve (stores.xml) and passes a pointer to the callback function that will be invoked when the data is fully retrieved.

var mallData=nulle var imageBase="";function retrieveData(evt){	window.getURL("Stores.xml",retrieveDataCallBack);	return "";	}

The second function,retrieveDataCallBack() takes as an argument resultObject, which contains an object constructed by the viewer. This function may be called many times at different stages of the download, so you should use the resultObject.success property to determine whether you have retrieved all of the contents. SVG 1.2 (and the Adobe SVG 1.0 and 1.1) browser also contain a function called parseXML() which takes text content (here resultObject.content) and converts into an internal parsed format, associated with the window and placed here within the variable mallData.

function retrieveDataCallBack(resultObject){ if (resultObject.success){  mallData = window.parseXML(resultObject.content);  imageBase = mallData.documentElement.getAttribute("imageBase")+"\";  showCategories(3);  } else {  alert("stores.xml could not be found");  } return ""; }

The showCategories function, invoked once everything is loaded, draws that category buttons from the stores.xml file and sets up the request command handlers. Additionally, for each button, the handlers are customized for each particular category key. Finally, using the categoryBox template defined earlier, the category buttons are customized to handle labelling for each respective category.

function showCategories(depth){	if (depth == null) depth=3;	var categoryTerms = mallData.getElementsByTagName("categoryTerm");	var legend=document.getElementById("legend");	for (var catIndex=0;catIndex != categoryTerms.length;catIndex++){		var categoryTerm=categoryTerms.item(catIndex);		var categoryKey=categoryTerm.getAttribute("key");		var categoryTitle=categoryTerm.getAttribute("title");		var categoryNode = document.getElementById("categoryTemplate").cloneNode(true);		categoryNode.setAttribute("id",categoryKey);		categoryNode.setAttribute("onclick","showStoresByCategory('"+categoryKey+"')");		var x=Math.floor(catIndex / depth) * 1600;		var y=(catIndex % depth) * 300;		categoryNode.setAttribute("transform","translate("+x+","+y+")");		var rect=categoryNode.getElementsByTagName("rect").item(0)		rect.setAttribute("id",categoryKey+"_box");		var text=categoryNode.getElementsByTagName("text").item(0)		text.setAttribute("id",categoryKey+"_text");		text.childNodes.item(0).setData(categoryTitle);		legend.appendChild(categoryNode);				}	}

The displayInfo() function displays text content in the upper-left-hand portion of the page (pulled from the local stores repository, and if an image attribute is specified, also sets the storeImage defined in the previous section to point to that image.) The function also turns the highlight of the store on (regardless of whether it has been selected as being in a category or not. Note of course that the SVG DOM uses almost exclusively XML DOM commmands. The restore() function simply turns the store's highlight off.

function displayInfo(evt){	var;	//alert(elt.getAttribute("id"));	if (elt.getAttribute("class") == "storeCategoryHighlight"){		elt.setAttribute("class","storeCategory");		}	var storeNode=mallData.getElementById(elt.getAttribute("id"));	setStoreData("name","storeName",storeNode,elt.getAttribute("id"));	setStoreData("description","storeDesc",storeNode);	if (storeNode != null){	var storeImageData=storeNode.getAttribute("image");	var storeImage = document.getElementById("storeImage");	if (storeImageData !=""){		storeImage.setAttribute("xlink:href",imageBase + storeImageData);		}	else {		storeImage.setAttribute("xlink:href","");		}	if (elt.getAttribute("class")=="store"){		elt.setAttribute("class","storeHighlight");		}	if (elt.getAttribute("class")=="storeCategory"){		elt.setAttribute("class","storeCategoryHighlight");		}	if (elt.getAttribute("class")=="service"){		elt.setAttribute("class","serviceHighlight");		}		}	return "";	}function restore(evt){	var;	if (elt.getAttribute("class")=="storeHighlight"){		elt.setAttribute("class","store");		}	if (elt.getAttribute("class")=="storeCategoryHighlight"){		elt.setAttribute("class","storeCategory");		}	if (elt.getAttribute("class")=="serviceHighlight"){		elt.setAttribute("class","service");		}	return "";	}

Enabling the Mall (cont.)
The setStoreData() function is a helper function for updating text content within SVG. An element in XML contains a text node, which in turn contains text. This means that in order to retrieve the text of a given element, you would use an expression such as this one:

eltData = elt.item(0).childNodes.item(0).getData();

The corresponding setData method sets the text data itself, and is used to update both elements and attributes. These routines are not called directly by the user, but rather are called indirectly by other routines.

function setStoreData(field,target,storeNode,message){		if (storeNode != null){			elt = storeNode.getElementsByTagName(field);			eltData = elt.item(0).childNodes.item(0).getData();			}		else {			if (message!=null){				eltData = message;				}			else {				eltData = "Not Yet Occupied";				}			}		eltText=document.getElementById(target);		eltText.childNodes.item(0).setData(eltData);	}

The showStoresByCategory takes a category name and compares it against the category list of each store in the store XML. Those that match are added into an array to have their categories changed.

function showStoresByCategory(categoryName){	var stores=mallData.getElementsByTagName("store");	var catStoresArr =new Array();	var storeCatIndex = 0;		var categoryTerms = mallData.getElementsByTagName("categoryTerm");		for (var ctIndex = 0;ctIndex != categoryTerms.length;ctIndex++){			var categoryTerm=categoryTerms.item(ctIndex);			var key=categoryTerm.getAttribute("key")//			alert(key);			categoryTermElt = document.getElementById(key+"_box");			if (categoryName == key){				categoryTermElt.setAttribute("class","categoryBoxHighlight"); 				}			else {				categoryTermElt.setAttribute("class","categoryBox"); 				}							}	for (var storeIndex=0;storeIndex != stores.length;storeIndex++){		var store = stores.item(storeIndex);		storeElt = document.getElementById(store.getAttribute('id'));		if (storeElt.getAttribute("class")=="storeCategory"){			storeElt.setAttribute("class","store");					}		var categoryElts = store.getElementsByTagName("category");		for (var catIndex = 0;catIndex !=categoryElts.length;catIndex++){			var categoryValue = categoryElts.item(catIndex).childNodes.item(0).getData();			if (categoryValue == categoryName){				catStoresArr[storeCatIndex] = store;				storeCatIndex++;				break;				}			}		}	for (var storeCatIndex=0;storeCatIndex != catStoresArr.length;storeCatIndex++){		var store = catStoresArr[storeCatIndex];		var storeElt = document.getElementById(store.getAttribute('id'));		storeElt.setAttribute("class","storeCategory");		}	}

Finally, the showVideo() function sets the video xlink:href attribute to a new local value. It also uses the beginElement() and endElement() functions to insure that the video is always rewound prior to started.

function showVideo(evt){	var;	var storeNode=mallData.getElementById(elt.getAttribute("id"));	if (storeNode != null){		var storeVideoData=storeNode.getAttribute("video");		var storeVideo = document.getElementById("storeVideo");		if (storeVideoData != ''){			//alert(storeVideoData);			storeVideo.setAttribute("xlink:href",imageBase + storeVideoData);			storeVideo.beginElement();//			storeVideo.setAttribute("to",imageBase + storeVideoData);			}		else {			storeVideo.setAttribute("xlink:href","");			storeVideo.endElement();			}		}		}			

Just In Time For Christmas
While this uses a few of the less controversial 1.2 capabilities, this sample SVG document illustrates how to create a compelling, full-blown application that is nonetheless surprisingly simple to create. The linked nature of XML means that you could just as readily have the kiosk display additional information like sales, events, or you could do things like have the stores act as links into other "pages," and so forth.

The most recent SVG 1.2 working draft was published in November and is available here, with the SVG 1.1 available a year ago. The Adobe SVG Viewer 6.0 beta, the first to support SVG 1.2, can be downloaded for experimentation here. It supports SVG 1.2 up to the July release, though that may change by the time this articles is published.


Share the Post: