Transforms

On This Page

Introduction

Now that we have shapes, paths, ad styling under our belts, it would be quite ideal to learn how they can all be moved around, rotated, and scaled after creating them. That's where SVG transforms come into play.

The Group Tag

The Group tag, represented as <g> in SVG code, allows you to wrap shapes up into groups so that you can keep them organized and also perform actions to all of the grouped shapes all at once.

Groups can even be used to apply CSS styling to all the shapes within them at once. Here's an example of some grouped shapes:

<g stroke="green" stroke-width="4" fill="gold">
<rect x="10" y="10" width="100" height="100"/>
<circle cx="170" cy="60" r="50"/>
<path d="M 230, 110
	H 330
	L 280, 10 Z"/>
</g>

Here we have opened the group using the <g> tag and added some styling to give the shapes in the group a green outline and a gold infill. The styling is applied just as you have been doing with any other shape.

We have a square, circle, and a triangle drawn in a row using <rect>, <circle>, and <path> shapes respectively. Note how none of the shapes have any styling added. The styling in the group tag is applied to everything within the group, and the final line closes the group.

This is very useful if you want to apply uniform styling to a lot of shapes or parts of your drawing, and greatly reduces the amount of code you'll need to write per shape. With this feature of groups in mind, we can also consider how they can be used to move or transform whole groups of shapes at once.

Translate

To move a shape or a group about the canvas, we use the translate transform attribute. This takes an x and y value separated by whitespace, and the values are relative to the original position of the shape or group.

<rect x="0" y="0" width="100" height="100" fill="green" transform="translate(30 40)"/>

Note the syntax of the transform attribute and how the translate parameter is added into it. Our green square starts off in the top left corner of the canvas, but the translate values move it over 30 units on x and 40 units down on y.

When adjusting or tweaking your drawings, adding translate can help you quickly nudge a shape into the right position without having to redraw it or alter a bunch of path numbers or shape attributes.

If you don't add a y value, it gets interpreted as 0 on y. So translate(30) will only move a shape 30 units over on x but leave the y value alone.

Rotate

The rotate parameter lets you set how much a shape is rotated by degrees. It's very important to note that if only the degrees are entered, the shape will be rotated as if from the top-left origin corner of the canvas, so it's a good idea to add in x and y coordinates after the degrees to specify the point from which the shape is being rotated.

<rect x="50" y="50" width="50" height="50" transform="rotate(45, 75, 75)"/>

Here we are drawing a 50x50 square which is starting out with it's top-left corner at 50, 50 on the canvas. This means that the direct center of the square is at 75, 75.

Knowing this, we can add that to the rotate parameter. The first value is the amount of degrees to rotate the shape, and the following numbers separated by a comma are the x and y coordinates which the shape is rotating around.

In this instance, a 45 degree rotation around the 75, 75 point will rotate the square around it's center, making it look like a diamond instead of a square.

Scale

The scale parameter increases or decreases the overall size of a shape or group, but it's extremely important to note that the scale origin is always set to the top-left corner of the canvas.

This means that when you scale something, it will require a translate parameter as well to readjust the shape back to it's original position on the canvas. The amount to translate will be the inverse of however much you scale a shape. Check out this example:

<rect x=100" y="100" width="100" height="100" transform="scale(0.5)"/>

This 100x100 square is being scaled down by 0.5 units, or by half. This means that the square will turn into a 50x50 square and that it's top-left corner/position will move towards the top-left corner of the canvas by 50 units on both x and y.

To move the square back to it's original position, we have to do a little math to get the coordinates just right. Subtract the product of the original position and the scale value from the original position number, and then divide that result by the scale value.

<path id="original" d="M 100, 100
	L 200, 100
	L 200, 30 Z" fill="green"/>
<path id="mirror" d="M 100, 100
	L 200, 100
	L 200, 30 Z" fill="green" transform="translate(200 0) scale(-1,1)"/>

In our example, this looks like: (100 - (100 * 0.5))/0.5. You end up with 50/0.5, which turns out to be 100, so the translate values we'd use are translate(100, 100). This will work when either increasing or decreasing the size, just plug in your position value and scale and off you go! Just remember to do this for both x and y positions if they are different values.

If you mirror a group tag, note that the origin of the group is still 0, 0. If the first point of a path in a group is 100 units on X, scaling the group by -1 on X will put the mirror point at -100 on X, or way off the canvas to the left.

In these instances, the math is easier as you just have to double the original X value and use that for the x coordinate in the translate value to shift the mirror back into the visible part of the canvas, then adjust your positioning from there.

Scaling with Width and Height

Let's say you've built your entire drawing but realize that you want to play with the entire scale overall for output. Rather than using the scale transform, you can accomplish this task using a combination of the viewBox, the SVG tag width and height attributes, and nesting one SVG tag within another!

The viewBox Returns

Yes, this is a callback to the Setup page where we discussed the viewBox attribute. This attribute takes 4 values, the first being the x and y coordinate of the canvas origin (top-left corner of the canvas), and the last two values are the width and height of the viewbox. Here's code for a 100x100 unit viewBox:

<svg viewbox="0 0 100 100" ...>

The viewBox designates the actual canvas borders for your drawing, so anything drawn outside of that 100x100 box will be cut off. Now, let's say you make a great drawing within that 100x100 space but want to blow it up to 500x500 units. You use the width and height parameters to do this, altering the output size of the SVG file itself without messing up any of the values in your drawing.

<svg viewBox="0 0 100 100" width="500" height="500" ...>

Note: Pay careful attention to the width and height values as compared to the size set in the viewBox. You need to make sure that the ratio of the values is maintained, otherwise your drawing will get squashed or stretched!

For example, if your viewBox is set to "0 0 100 200", you would multiply the viewBox width and height values by 2 if you wanted to double the size of the drawing. Those values would go in the SVG canvas width and height attributes, like so:

< svg viewBox="0 0 100 200" width="200" height="400"...>

Our previous 500x500 example is easy since the drawing and the scaled output are squares, but if your drawing is set within a viewBox rectangle, make sure your final width and height output values are correct.

Nesting SVGs

Nice, but now you want to center this blown up drawing on a sheet of letter paper. This is where we can use SVG nesting in our files. We can wrap our original SVG tags within another set of SVG tags, set the outer SVG width and height to 850x1100 to make it letter paper sized, and use a translate group transform to center the drawing SVG, like so:

&svg id="finalOutput" width="850" height="1100" ... >

<g transform="translate(175, 300)">
<svg id="drawing" viewBox="0 0 100 100" width="500" height="500"...>

...all your SVG drawing code...

</svg>
</g>

</svg>

We do have to do a little math here to center our drawing SVG within the finalOutput SVG. Remember that half of 850x1100 is 425x550. Half of 500 for our drawing is 250. We subtract 250 from the 425x550 values to find the values we need to put into the group translate attribute.

425 minus 250 is 175 for x, and 550 minus 250 is 300 for y. The drawing SVG is wrapped in a group tag that has the translate transform all set up with those values, so translate(175, 300).

This centers our 500x500 drawing right in the middle of our letter paper. Pretty spiffy! Remember to account for different sizes of the canvas if your drawing is not a perfect square.

Multiple Transforms and Order of Operation

Note that we used two transforms within the transform attribute. You can add multiple attributes here within the transform quotes separated by a space.

Order of operations is important, and SVG will perform transforms on the shape in the order in which they appear within the transform attribute. Scaling first and then translating will look different than translating first and then scaling.

A common use case for this is building a shape and then duplicating and flipping it for symmetry, such as making legs and arms for a character. This would involve translating the shape and then "mirroring" the shape by flipping it across the Y axis.

If only mirroring across the X axis for horizontal symmetry, make sure to use scale(-1, 1) so that the Y axis scale is not affected. Adding this transform to a shape will make it disappear from the canvas since the x position value has been made negative. For example, a shape 300 units over on x will have it's mirrored duplicate at -300 units.

Knowing this, a translate transform would have to be added before the scale transform to prepare and shift the shape into a position where mirroring it would put it back into the visible canvas. This is done by doubling the x value of the original shape. So transform=" translate(600)scale(-1, 1)" would mirror the original shape that was at 300 units on x and bring the mirrored copy next to it.

If flipping/mirroring a shape vertically across the X axis, just perform the same operation an account for the x values not being affected, such as transform="translate(0 600) scale(1, -1)".

Skew

Skewing is a transform that shifts the top part of the shape away from the bottom of the shape at a specified angle on the X axis, or shifts the sides of the shape away from each other along the Y axis.

Imagine that you have a Slinky in front of you. If you held the bottom of the Slinky in place and slid the top of the Slinky to the left or right, you are essentially Skewing the shape of the Slinky. The top and bottom remain parallel to each other, but the sides shift and stretch the further apart you move the top from the bottom.

To skew a shape along the x axis, we use the skewX() transform, and skewY() for the y axis. Place the amount you want to skew a shape within the parentheses in the form of a number which represents an angle in degrees.

<rect x="10" y="10" width="100" height="100" fill="green" transform="skewX(15)"/>
<rect x="130" y="10" width="100" height="100" fill="gold" transform="skewY(15)"/>

The green box is slightly skewed to the right, with the top of the box being slid over so that the sides of the box make a 15° angle between the bottom and top edges.

The gold box is skewing on the y axis, with the right side of the box sliding lower than the left, creating a 15° slope with the top and bottom edges.

Note that this will distort anything within the shape or the group that you are skewing. Remember that the edges being skewed don't get closer or farther apart but are just sliding along an axis, so everything between them will stretch at the skewing angle.