SVG4: Groups, Transforms, Re-Use, and Hierarchies

(This is part 4 of the 6 part SVG Tutorial))

On the last page, we saw that we could make groups out of primitives, and that we can also apply transformations to elements. The examples just applied transforms to primitives, but, of course, we can apply transforms to groups.

 1<svg xmlns="http://www.w3.org/2000/svg" height="60" width="60">
 2<!-- two squares (the same, except that one gets translated) -->
 3<rect x="10" y="10" height="20" width="20" />
 4<rect x="10" y="10" height="20" width="20" transform="translate(30,0)" />
 5 
 6<!-- make a group - notice that any properties trickle down -->
 7<g transform="translate(0,30)" fill="#f00">
 8<!-- these are the same two squares as above, just not in the group -->
 9<rect x="10" y="10" height="20" width="20" />
10<!-- note that transforms compose/add not override -->
11<rect x="10" y="10" height="20" width="20" transform="translate(30,0)" />
12</g>
13</svg>
svg4-1.svg

You might also notice in this example ( svg4-1.svg ): that I put some comments into my SVG code.

Make sure you understand what’s happening here: the lower right square got there by having two translations.

Re-Use

Since I am typing all of this SVG by hand, it would be nice to avoid repeating myself so much with each little square (since they can be the same and just transformed into place). SVG lets us define our own objects and re-use them. ( svg4-2.svg ):

1<svg xmlns="http://www.w3.org/2000/svg" height="60" width="60">
2<!-- two squares (the same, except that one gets translated) -->
3<rect id="mysquare" x="10" y="10" height="20" width="20" />
4<use href="#mysquare" transform="translate(30,0)" />
5</svg>
svg4-2.svg

The trick is that we give the object that we draw a name (here, I am calling it “my square”, and then we can re-use it later). Notice that when I refer to the tag, I have to use a # (a hash) to say that this is something in the current document.

There is one complication: when I refer to #mysquare, SVG needs to know where to look. In older versions of things, we had to explicitly tell it what namespace to look in. We had to specify for the entire SVG file that it uses the “xlink” namespace, and we had to use that namespace. This meant that the old demos (that you may still see) look like: ( svg4-2.svg ):

1<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="60" width="60">
2<!-- two squares (the same, except that one gets translated) -->
3<rect id="mysquare" x="10" y="10" height="20" width="20" />
4<use xlink:href="#mysquare" transform="translate(30,0)" />
5</svg>
svg4-2-old.svg

Re-use can be helpful, especially when the objects get more complicated. It obviously can save a a lot of typing. But it also facilitates keeping things consistent. Here, all of my squares are the same. Also notice how a make a group of two squares, and then re-use that ( svg4-3.svg ):

1<svg xmlns="http://www.w3.org/2000/svg" height="60" width="60">
2<g id="mygroup">
3<rect id="mysquare" x="10" y="10" height="20" width="20" />
4<use href="#mysquare" transform="translate(30,0)" />
5</g>
6<use href="#mygroup" transform="translate(0,30)" fill="red" />
7</svg>
svg4-3.svg

Notice how I was able to specify attributes for the things I used (making the second copy red). While this affects the objects, the objects overrride the outside attributes. Notice in this example how red overrides black (the default), but not green (which is specified on the object) ( svg4-3a.svg ):

1<svg xmlns="http://www.w3.org/2000/svg" height="60" width="60">
2<g id="mygroup">
3<rect id="mysquare" x="10" y="10" height="20" width="20" />
4<use href="#mysquare" transform="translate(30,0)" fill="green" />
5</g>
6<use href="#mygroup" transform="translate(0,30)" fill="red" />
7</svg>
svg4-3a.svg

Sometimes, you might want to make an object just to be used. Here, I’ll define a little square in a convenient place (at the origin), and then I can just move it all over the place. The trick is that I will put the square into a <defs> tag, which basically says “don’t draw the stuff inside this tag.” Things still can be named, and used later. ( svg4-4.svg ):

1<svg xmlns="http://www.w3.org/2000/svg" height="70" width="70">
2<defs>
3<rect id="mysquare" x="-10" y="-10" height="20" width="20" transform="rotate(45)" />
4</defs>
5<use href="#mysquare" transform="translate(20,20)" />
6<use href="#mysquare" transform="translate(50,20)" />
7<use href="#mysquare" transform="translate(20,50)" />
8<use href="#mysquare" transform="translate(50,50)" />
9</svg>
svg4-4.svg

Notice how I placed my square with its center at the origin, so when I used it, I could place it by placing the center (much as I would place a circle).

Hierarchies

Of course, you can put groups within groups (within groups …)

The key is to remember that the coordinate systems combine by composition. To everything you do to the outermost (or “parent”) group, gets applied to all of the children. Of course, you can (and maybe should) think about it as the children start out with the parent’s coordinate system (which, the might change before drawing or passing it on to their children). ( svg4-5.svg ):

 1<svg xmlns="http://www.w3.org/2000/svg" height="70" width="300">
 2<defs>
 3<rect id="mysquare" x="-10" y="-10" height="20" width="20" transform="rotate(45)" />
 4<g id="foursquare">
 5    <use href="#mysquare" transform="translate( 0, 0)" />
 6    <use href="#mysquare" transform="translate(30, 0)" />
 7    <use href="#mysquare" transform="translate( 0,30)" />
 8    <use href="#mysquare" transform="translate(30,30)" />
 9</g>
10</defs>
11<g transform="translate(20,20)">
12    <use href="#foursquare" />
13    <g transform="translate(60,0)">
14        <use href="#foursquare" />
15        <g transform="translate(60,0)">
16            <use href="#foursquare" />
17            <g transform="translate(60,0)" stroke="red" stroke-width="3">
18                <use href="#foursquare" />
19            </g>
20        </g>
21    </g>
22</g>
23</svg>
svg4-5.svg

It is really worth making sure that you understand this example. Not just for the SVG and the re-use, but also for the nested groups and the hierarchical transforms. Notice how each group is offset 60 units in X relative to its parent (except for the outermost group that is translated 20 units from the edge).

Next: SVG5: More Transforms and Composition
Prev: SVG3: Manipulating Primivites