Up to this point, all graphics have been displayed "as is." There will be times when you have a graphic that you would like to move to a new location, rotate, or scale. To accomplish these tasks, you add the transform attribute to the appropriate SVG elements. This chapter examines the details of these transformations.

The translate Transformation

In Chapter 4, you saw that you can use x and y attributes with the <use> element to place a group of graphic objects at a specific place. Look at the SVG in Example 5-1, which defines a square and draws it at the upper left corner of the grid, then re-draws it with the upper left corner at coordinates (50, 50). The dotted lines in Figure 5-1 aren't part of the SVG, but serve to show the part of the canvas that we're interested in.

As it turns out, the x and y values are really a shorthand for one form of the more general and more powerful transform attribute. Specifically, the x and y values are converted to an attribute like transform="translate(x-value, y-value)", where translate is a fancy technical term for "move." The x-value and y-value are measured in the current user coordinate system. Let's use transform to get the same effect of making a second square with its upper left corner at (50, 50). Example 5-2 lists the SVG.

The resulting display will look exactly like that in Figure 5-1. You might think this was accomplished by moving the square to a different place on the grid, as shown conceptually in Figure 5-2, but you would be wrong.

Figure 5-2. How moving appears to work (but really doesn't)

What is really going on behind the scenes is an entirely different story. Rather than moving the square, the translate specification picks up the entire grid and moves it to a new location on the canvas. As far as the square is concerned, it's still being drawn with its upper left corner at (0, 0), as depicted in Figure 5-3.

Figure 5-3. How moving with translate really works

Warning

A translation transformation never changes a graphic object's grid coordinates; rather, it changes the position of the grid on the canvas.

At first glance, using translate seems as ridiculous and inefficient as moving your couch further away from the outside wall of the house by moving the entire living room, walls and all, to a new position. Indeed, if translation were the only transformation available, moving the entire coordinate system would be wasteful. However, we will soon see other transformations, and combinations of a sequence of transformations, which are more mathematically and conceptually convenient if they apply to the entire coordinate system.

The scale Transformation

It is possible to make an object appear larger or smaller than the size at which it was defined by scaling the coordinate system. Such a transformation is specified either as:

transform="scale(value)"

Multiplies all x- and y-coordinates by the given value.

transform="scale(x-value,y-value)"

Multiplies all x-coordinates by the given x-value and all y-coordinates by the given y-value.

Example 5-3 is an example of the first kind of scaling transformation, which uniformly doubles the scale of both axes. Once again, the dotted lines in Figure 5-4 aren't in the SVG; they simply show the area of the canvas that we're interested in. Note that the square's upper left corner is at (10, 10).

You might be thinking, "Wait a minute — I can understand why the square got larger. But I didn't ask for a translate, so why is the square in a different place?" Everything becomes clear when you look at Figure 5-5 to see what has actually occurred. The grid hasn't moved; the (0, 0) point of the coordinate system is still in the same place, but each user coordinate is now twice as large as it used to be. You can see from the grid lines that the upper left corner of the rectangle is still at (10, 10) on the new, larger grid, since objects never move. This also explains why the outline of the larger square is thicker. The stroke-width is still one user unit, but that unit has now become twice as large, so the stroke thickens.

Figure 5-5. How the scale transformation works

Warning

A scaling transformation never changes a graphic object's grid coordinates or its stroke width; rather, it changes the size of the coordinate system (grid) with respect to the canvas.

It is possible to specify a different scale factor for the x-axis and y-axis of the coordinate system by using the second form of the scale transformation. Example 5-4 draws the square with the x-axis scaled by a factor of three and the y-axis scaled by a factor of one and a half. As you can see in Figure 5-6, the one-unit stroke width is also non-uniformly scaled.

It's fairly clear that the width and height of the scaled rectangle should be three times as large as the unscaled rectangle. However, you may wonder if the x- and y-coordinates are evaluated before or after the rectangle is scaled. The answer is that SVG applies transformations to the coordinate system before it evaluates any of the shape's coordinates. Example 5-5 is the SVG for the scaled rectangle, shown in Figure 5-7 with grid lines that are drawn in the unscaled coordinate system.

Sequences of Transformations

It is possible to do more than one transformation on a graphic object. You just put the transformations, separated by whitespace, in the value of the transform attribute. Here is a rectangle that undergoes two transformations, a translation followed by a scaling. (The axes are drawn to show that the rectangle has, indeed, moved.)

Figure 5-9 shows what is happening at each stage of the transformation.

Figure 5-9. How translate followed by scale works

Note

The order in which you do a sequence of transformations affects the result. In general, transformation A followed by transformation B will not give the same result as transformation B followed by transformation A.

Example 5-6 draws the same rectangle as in the previous example, only in a light gray color. Then it draws the rectangle again, but does the scale before the translate. As you can see from the result in Figure 5-10, the rectangles end up in very different places on the canvas.

Example 5-6. Sequence of transformations -- scale followed by translate

The reason that the black rectangle ends up farther away from the origin is that the scaling is applied first, so that the translate of 20 units in the x-direction and 10 units in the y-direction is done with units that are now twice as large, as shown in Figure 5-11.

Figure 5-11. How scale followed by translate works

Technique: Converting from Cartesian Coordinates

If you are transferring data from other systems to SVG, you may have to deal with vector drawings that use Cartesian coordinates (the ones you learned about in high school algebra) to represent data. In this system, the (0, 0) point is at the lower left of the canvas, and y-coordinates increase as you move upwards. Figure 5-12 shows the coordinates of a trapezoid drawn with Cartesian coordinates.

Figure 5-12. Trapezoid drawn with Cartesian coordinates

Since the y-axis is "upside-down" relative to the SVG default, the coordinates have to be recalculated. Rather than do it by hand, you can use a sequence of transformations to have SVG do all the work for you. First, translate the picture into SVG, with the coordinates exactly as shown in Example 5-7. (We'll also include the axes as a guide.) To nobody's surprise, the picture will come out upside-down. Note that the image in Figure 5-13 is not left-to-right reversed, since the x-axis points the same direction in both Cartesian coordinates and the default SVG coordinate system.

The rotate Transformation

It is also possible to rotate the coordinate system by a specified angle. In the default coordinate system, angle measure increases as you rotate clockwise, with a horizontal line having an angle of zero degrees, as shown in Figure 5-15.

Figure 5-15. Default measurement of angles

Unless you specify otherwise, the center of rotation (a fancy term for the "pivot point") is presumed to be (0, 0). Example 5-9 shows a square drawn in gray, then drawn again in black after the coordinate system is rotated 45 degrees. The axes are also shown as a guide. Figure 5-16 shows the result. If you're surprised that the square has appeared to move, you shouldn't be. Remember, the entire coordinate system has been rotated, as shown in Figure 5-17.[1]

Most of the time, you will not want to rotate the entire coordinate system around the origin; you'll want to rotate a single object around a point other than the origin. You can do that via this series of transformations: translate(centerX,centerY)rotate(angle)translate(-centerX, -centerY). SVG provides another version of rotate to make this common task easier. In this second form of the rotate transformation, you specify the angle and the center point around which you want to rotate:

rotate(angle, centerX, centerY)

This has the effect of temporarily establishing a new system of coordinates with the origin at the specified center x and y points, doing the rotation, and then re-establishing the original coordinates. Example 5-10 shows this form of rotate to create multiple copies of an arrow, shown in Figure 5-18.

Technique: Scaling Around a Center Point

While it's possible to rotate around a point other than the origin, there is no corresponding capability to scale around a point. You can, however, make concentric symbols with a simple series of transformations. To scale an object by a given factor around a center point, do this:

translate(-centerX*(factor-1), -centerY*(factor-1))
scale(factor)

You may also want to divide the stroke-width by the scaling factor so the outline stays the same width while the object becomes larger. Example 5-11 draws the set of concentric rectangles shown in Figure 5-19.[2]

The skewX and skewY Transformations

SVG also has two other transformations: skewX and skewY, which let you skew one of the axes. The general form is skewX(angle) and skewY(angle) The skewX transformation "pushes" all x-coordinates by the specified angle, leaving y-coordinates unchanged. skewY skews the y-coordinates, leaving x-coordinates unchanged, as shown in Example 5-12.

Transformation Reference Summary

Table 5-1 gives a quick summary of the transformations available in SVG.

Table 5-1. SVG transformations

Transformation

Description

translate(x,y)

Moves the user coordinate system by the specified x and y amounts. Note: If you don't specify a y value, zero is assumed.

scale(xFactor,yFactor)

Multiplies all user coordinate systems by the specified xFactor and yFactor. The factors may be fractional or negative.

scale(factor)

Same as scale(factor,factor).

rotate(angle)

Rotates the user coordinate by the specified angle. The center of rotation is the origin (0, 0). In the default coordinate system, angle measure increases as you rotate clockwise, with a horizontal line having an angle of zero degrees.

rotate(angle,centerX,centerY)

Rotates the user coordinate by the specified angle. centerX and centerY specify the center of rotation.

skewX(angle)

Skews all x-coordinates by the specified angle. Visually, this makes vertical lines appear at an angle.

skewY(angle)

Skews all y-coordinates by the specified angle. Visually, this makes horizontal lines appear at an angle.

Notes

↑ All the figures in this chapter are static pictures. This one shows two squares; one rotated and one unrotated. To show an animation of a rotating square, use <animateTransform>, which we will discuss in Chapter 11, in Section 11.6.

↑ This is also a static picture, a "square bullseye." If you want to show an animation of an expanding square, you'll use <animateTransform>, which we will discuss in Chapter 11, in Section 11.6.