The world of SVG is an infinite canvas. In this chapter, we'll discuss how you tell a viewer program which part of this canvas you're interested in, what its dimensions are, and how you locate points within that area.

The Viewport

The area of the canvas that your document intends to use is called the viewport. You establish the size of this viewport with the width and height attributes on the <svg> element. The values of these attributes can be simply a number, which is presumed to be in pixels; this is said to be specified in user coordinates. You may also specify width and height as a number followed by a unit identifier, which can be one of the following:

em

The font size of the default font, usually equivalent to the height of a character

ex

The height of the letter x

px

Pixels

pt

Points (1/72 of an inch)

pc

Picas (1/6 of an inch)

cm

Centimeters

mm

Millimeters

in

Inches

Examples:

<svg width="200" height="150">, <svg width="200px" height="200px">

Both of these specify an area 200 pixels wide and 150 pixels tall.

<svg width="2cm" height="3cm">

Specifies an area two centimeters wide and three centimeters high.

<svg width="2cm" height="36pt">

It is possible, though unusual, to mix units; this element specifies an area two centimeters wide and thirty-six points high.

If you have one <svg> element nested within another <svg> element, the nested tag may also specify its width and height as a percentage, measured in terms of the enclosing element. We will see nested <svg> elements in Section 2.5.

Using Default User Coordinates

When you do not use unit specifiers on your <svg> element, the viewer sets up a coordinate system where the horizontal, or x-coordinate, increases as you go to the right, and the vertical, or y-coordinate, increases as you move vertically downward. The upper left corner of the viewport is defined to have an x- and y-coordinate of zero.[1] This point, written as (0, 0) is also called the origin. The coordinate system is a pure geometric system; points have neither width nor height, and the grid lines are considered infinitely thin. We'll return to this subject in Chapter 3.

Example 2-1 establishes a viewport two hundred pixels wide and two hundred pixels high, then draws a rectangle whose upper left corner is at coordinate (10, 10) with a width of 50 pixels and a height of 30 pixels.[2]Figure 2-1 shows the result, with rulers and a grid to show the coordinate system.

Even if you don't specify units in the viewport, you may still use them in some SVG shape elements, as we do in Example 2-2. Figure 2-2 shows the result, with rulers and a grid to show the coordinate system.

Specifying units in the <svg> element does not affect coordinates given without units in other elements. Example 2-3 shows a viewport set up in millimeters, but the rectangle is still drawn at pixel (user) coordinates, as you see in Figure 2-3.

Specifying User Coordinates for a Viewport

In the examples so far, numbers without units have been considered to be pixels. Sometimes this is not what you want. For example, you might want to set up a system where each user coordinate represents one-sixteenth of a centimeter. (We're using this coordinate system to prove a point, not to show a paragon of good design.) In this system, a square that is 40 units by 40 units will display as 2.5 centimeters on a side.

To accomplish this effect, you set the viewBox attribute on the <svg> element. The value of this attribute consists of four numbers that represent the minimum x-coordinate, minimum y-coordinate, width, and height of the user coordinate system that you want to superimpose on the viewport.

So, to set up the sixteen-units-per-centimeter coordinate system for a four centimeter by five centimeter drawing, you'd use this starting tag:

<svg width="4cm" height="5cm" viewBox="0 0 64 80">

Example 2-4 lists the SVG for a picture of a house, displayed using the new coordinate system.

Figure 2-4 shows the result. The grid and darker numbers show the new user coordinate system; the lighter numbers are positioned at one-centimeter intervals.

Figure 2-4. New user coordinates

The numbers you specify for the value of the viewBox attribute may be separated by commas or whitespace. If either the width or height is zero, none of your graphic will display. It is an error to specify a negative value for the viewBox width or height.

Preserving Aspect Ratio

In the previous example, the aspect ratio, or ratio of width to height, of the viewport and the viewBox were identical (4/5 = 64/80). What happens, though, if the aspect ratio of the viewport and the viewBox are not the same, as in this example, where viewBox has an aspect ratio of one to one, but the viewport has an aspect ratio of one to three?

<svg width="45px" height="135px" viewBox="0 0 90 90">

There are three things that SVG can do in this situation:

Scale the graphic uniformly according to the smaller dimension so the graphic will fit entirely into the viewport. In the example, the picture would become half its original width and height. We'll show you examples of this in Section 2.4.2.

Scale the graphic uniformly according to the larger dimension and cut off the parts that lie outside the viewport. In the example, the picture would become one and a half times its original width and height. We'll show you examples in Section 2.4.3.

Stretch and squash the drawing so that it fits precisely into the new viewport. (That is, don't preserve the aspect ratio at all.) We will cover this in Section 2.4.4.

In the first case, since the image will be smaller than the viewport in one dimension, you must specify where to position it. In the example, the picture will be scaled uniformly to a width and height of 45 pixels. The width of the reduced graphic fits the width of the viewport perfectly, but you must now decide whether the image meets (is aligned with) the top, middle, or bottom of the 135-pixel viewport height.

In the second case, since the image will be larger than the viewport in one dimension, you must specify which area is to be sliced away. In the example, the picture will be scaled uniformly to a width and height of 135 pixels. Now the height of the graphic fits the viewport perfectly, but you must decide whether to slice off the right side, left side, or both edges of the picture to fit within the 45-pixel viewport width.

Specifying Alignment for preserveAspectRatio

The preserveAspectRatio attribute lets you specify the alignment of the scaled image with respect to the viewport, and whether you want it to meet the edges or be sliced off. The model for this attribute is:

preserveAspectRatio="alignment [meet | slice]"

where alignment specifies the axis and location, and is one of xMinYMin, xMinYMid, xMinYMax, xMidYMin, xMidYMid, xMidYMax, xMaxYMin, xMaxYMid, or xMaxYMax. This alignment specifier is formed by concatenating an x-alignment and a y-alignment as shown in Table 2-1. The default value for preserveAspectRatio is xMidYMid meet.

Note

The y-alignment begins with a capital letter, since the x- and y-alignments are concatenated into a single word.

Table 2-1. Values for alignment portion of preserveAspectRatio

X alignment

Value

Action

xMin

Align minimum x of viewBox with left corner of viewport.

xMid

Align midpoint x value of viewBox with midpoint x value of viewport.

xMax

Align maximum x value of viewBox with right corner of viewport.

Y alignment

Value

Action

YMin

Align minimum y of viewBox with top edge of viewport.

YMid

Align midpoint y value of viewBox with midpoint y value of viewport.

YMax

Align maximum y value of viewBox with bottom edge of viewport.

So, if you want to have the picture with a viewBox="0 0 90 90" fit entirely within a viewport that is 45 pixels wide and 135 pixels high, aligned at the top of the viewport, you would write:

In this case, since the width fits precisely, the x-alignment is irrelevant; you could equally well use xMidYmin or xMaxYMin. However, in the interests of consistency, it's usually best to make both specifiers the same when only one axis is affected.

This is all fairly abstract; here are some concrete examples that show you how the combinations of alignment and meet and slice interact with one another.

Using the none Specifier

Finally, there is the third option for scaling a graphic when the viewBox and viewPort don't have the same aspect ratio. If you specify preserve- AspectRatio="none", then the graphic will be scaled non-uniformly so that its user coordinates fit the viewport. Figure 2-7 shows such a "fun-house mirror" effect produced with the <svg> tags in Example 2-7.

Nested Systems of Coordinates

You can establish a new viewport and system of coordinates at any time by putting another <svg> element into your document. The effect is to create a "mini-canvas" upon which you can draw. We used this technique to create illustrations such as Figure 2-5. Rather than drawing the rectangles, then rescaling and positioning the cat inside each one (the brute force approach), we took these steps:

Draw the blue rectangles on the main canvas

For each rectangle, define a new <svg> element with the appropriate preserveAspectRatio attribute

Draw the cat into that new canvas (with <use>), and let SVG do the heavy lifting

Here's a simplified example that shows a circle on the main canvas, then inside a new canvas that's outlined by a blue rectangle that's also on the main canvas. Figure 2-8 is the result we wish to achieve.

Figure 2-8. Nested viewport example

First, generate the SVG for the main coordinate system and the circle. Note that we've established the user coordinates to coincide exactly with the viewport in this document.

Now, add another <svg> element for the new viewport. In addition to specifying the viewBox, width, height, and preserveAspectRatio specification, you may also specify the x and y attributes — in terms of the enclosing <svg> element — where the new viewport is to be established. (If you don't give values for x and y, they are presumed to be zero.)