Building composite shapes in SVG

 
Published on 2004-05-05 by John Collins.

Introduction to composite shapes

While SVG (Scalable Vector Graphics) has lots of primitive shapes build in, such as rectangles, circles et cetera, you may also like to make your own custom shapes. Defining a custom, composite shape allows you to reuse this shape definition again and again, allowing you to created multiple instances of the same custom shape.

In this tutorial, I will show you how this is possible using an XML (eXtensible Markup Language) technology called XLink, to reference links to custom shapes within the same document, then reuse these shapes using the SVG use tag. Let us begin by looking at XLink.

A brief introduction to XLink

While you do not have to be an XML guru to use SVG, it often helps to have a look at the many XML technologies out there to help you gain a better insight into SVG and how it works. XLink is concerned with linking objects together, much in the same way as the a href tag in HTML. In practice, XLink works by establishing the XLink namespace within an SVG document, then for each element that supports XLink, setting one or more XLink attributes. The attribute that we will be using is the xlink:href attribute, which is used to retrieve resources.

Now that we have some understanding of the theory behind XLink, let us now look at an example of it in action:

Composite Shapes

In this example, we have three rectangles, with each one containing a blue circle. However, this composite shape consisting of one rectangle and one circle has only been defined once, then reused three times over. This will become clearer when we next look at the source code.

The code for composite.svg:

<svg xmlns="http://www.w3.org/2000/svg" 
  xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<circle cx="75" cy="50" r="25" id="centerCircle"/>
<rect width="150" height="100" x="0" y="0" style="fill:white; 
  stroke:#000000; stroke-width:2px;" id="outerRectangle"/>
<g id="compShape">
    <use xlink:href="#outerRectangle" x="0" y="0"/>
    <use xlink:href="#centerCircle" x="0" y="0" fill="blue"/>   
</g>
 
</defs>
 
<use xlink:href="#compShape" x="75" y="25" id="comp1"/>
<use xlink:href="#compShape" x="75" y="145" id="comp2"/>
<use xlink:href="#compShape" x="75" y="265" id="comp3"/>
 
</svg>

We begin by including all of the shape definitions we will use within the defs tags in the top of the document. Firstly, we define the circle and give it the id of centerCircle, then the rectangle with the id outerRectangle. At this stage, these shapes are fully-independant primitive shapes. Now we create a custom graphic with the g element, and give this the id of compShape. This is where XLink comes into play: we use the use xlink:href... tags to include a reference to the centerCircle and outerRectangle elements within the g element, effectively making the g element a composite of the two primitive shapes. At this stage you should be realizing the true power of the g element, as you can include any combination of shapes and text within the g element that you like.

After the end of the definition section, we now draw three examples of the composite shape on the screen, each one with different y values to position them apart, and each one with a unique id. As you can see, there is no need to reposition the circle each time the rectangle is moved; as this is a composite all elements move together as one.

Conclusion

This simple demonstration shows how easily it is to build custom, composite shapes in SVG. It is only in more advanced applications, with composites of text, polygons and gradients that such a technique would prove its full worth. Remember that as SVG is an W3C specification, like CSS (Cascading Style Sheets) and the DOM (Document Object Model), all of these technologies are also fully compatible with each other, so it would be possible to write JavaScript to interact with you custom shapes, for example, to make them move or re-scale in unison, there are many further possibilities.


Updated 2020 : note that the above post was originally published in 2004, but is left here for archival purposes.