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

(originally from Fall 2014 - CS559 Computer Graphics)

In the last tutorial 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>

You might also notice in this example 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.

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>

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 in order for the web browser to understand how to use the link in the use statement, I needed to add a magic string to the svg tag. And also 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.

Although the SVG is a little on the cryptic side (the xmlns:xlink="http://www.w3.org/1999/xlink on the first line, the need for the hashtag for the name in the use statement), this can save a lot of typing. Especially if I name a group.

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

1<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 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 xlink:href="#mysquare" transform="translate(20,20)" />
6<use xlink:href="#mysquare" transform="translate(50,20)" />
7<use xlink:href="#mysquare" transform="translate(20,50)" />
8<use xlink:href="#mysquare" transform="translate(50,50)" />
9</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).

 1<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 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 xlink:href="#mysquare" transform="translate( 0, 0)" />
 6    <use xlink:href="#mysquare" transform="translate(30, 0)" />
 7    <use xlink:href="#mysquare" transform="translate( 0,30)" />
 8    <use xlink:href="#mysquare" transform="translate(30,30)" />
 9</g>
10</defs>
11<g transform="translate(20,20)">
12    <use xlink:href="#foursquare" />
13    <g transform="translate(60,0)">
14        <use xlink:href="#foursquare" />
15        <g transform="translate(60,0)">
16            <use xlink:href="#foursquare" />
17            <g transform="translate(60,0)" stroke="red" stroke-width="3">
18                <use xlink:href="#foursquare" />
19            </g>
20        </g>
21    </g>
22</g>
23</svg>

It’s really worth making sure that you understand this example. Not for the SVG and the re-use, but more importantly 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