The SVG Canvas, Coordinate System, And Viewport

When you see SVG images on the screen you’re viewing only part of the canvas on which they’re drawn and you view the canvas through the SVG viewport. Canvas and viewport are both independent and connected and their relationship can be confusing and lead to unexpected results at times. That is until you understand the relationship and how to control the connection.

The SVG Coordinate System

At the start of the year I began a series about scalable vector graphics, which covered some of the basics for working with SVG. At the conclusion of the series, I said I would revisit SVG throughout the year and build on what we learned. Today starts the first revisit.

Here are the posts from the previous series if you missed any.

If you read the earlier series, you may remember I mentioned that if your SVG is being clipped you should increase the width and/or height of the <svg> element. Today I want to explain why that is. I want to talk about the SVG coordinate system, the SVG canvas on which you draw, and the viewport through which you can see an area of the canvas.

When I first started looking into the SVG coordinate system and viewport, I found it hard to understand conceptually what was going. I think I approached the topic from an incorrect context. In my attempts to gain that conceptual understanding, I thought of a metaphor, which I’ll share throughout this series.

Others have covered the topic well and provided different ways to conceptually understand what’s happening and I’d like to point you to a couple that I leaned on a lot working on this post and the two that will follow it.

The first post above is the first in a three part series by Sara Soueidan. I’ll be covering what Sara covers in this post over the next few weeks. The second post above is part of an SVG tutorial by Jakob Jenkov. Jakob offers a lot of good examples that helped me figure out how this all works.

The Metaphor

Picture a canvas of infinite size. You can draw anything you want anywhere on the canvas and you can draw it at any size you’d like. This is the SVG canvas.

Now imagine someone has built an equally infinite wall directly in front of the canvas. The wall stretches across the exact same infinite width and infinite height of the canvas covering every part of it.

Since a wall directly in front of a canvas makes it difficult to see what’s on the canvas, the builders of the wall were nice enough to create a window and even better they’ve given us the ability to set the size of this window. This window is the SVG viewport.

The builders didn’t stop there. They left us with tools so we can move the canvas around and decide what region of it will show through the window as well as how much of that region will show. These tools are in the form of attributes (viewBox and preserveAspectRatio) on the SVG element.

I’ll talk more about the attributes over the next two weeks. Today I want to focus on the canvas, the wall, and the window and I want to start with the coordinate system they use.

The SVG Coordinate System

SVG doesn’t behave exactly the same as the CSS box model, but the coordinate systems for both work the same way.

The origin (0,0) of any SVG coordinate system is in the upper left corner of the parent element, whether the parent is the body, a div, or some other container.

When you create a new SVG element you create a new coordinate system that represents an infinite SVG canvas. The origin may be aligned with the top left corner of the parent element, but the canvas still stretches infinitely in all directions. The x-axis is positive moving to the right and the y-axis is positive moving down. Both axes also move negatively to the left and up.

One thing to understand with SVG is there are multiple coordinate systems in play at the same time. Whenever you create a new SVG element, you create a new canvas operating in its own coordinate space as well as a viewport operating in its own coordinate space.

The coordinate systems of each canvas and viewport pair will align with each other by default. They’ll appear to be the same system, but they aren’t and as we’ll see you can change how they’re aligned with each other.

In practice the elements you create on the infinite canvas will be near the canvas origin, but in theory they could be anywhere. Nothing is stopping you from creating a circle and placing it 4 billion px to the right of the origin.

In theory, the window too could be near infinite as you can set any dimensions you want. However, you only have fixed dimensions to set the window size so it will be of fixed size and once set, this coordinate system will remain fixed in space.

User agents (browsers) will align the origins and axes of both of these coordinate systems by default, though you can change this alignment to suit your needs.

The two system can be set in different units. One could be set in pixels while another is set millimeters or picas or inches or points or ems or any unit you can specify for dimensions. The exception is %, which can’t be used.

Again keep in mind that one of these coordinate systems always acts on an infinite canvas and another acts on what is a fixed window in space.

The SVG Viewport

You create a new SVG viewport whenever you create a new SVG element. The size of the viewport is equal to the width and height you set on the SVG element.

1
2
3
<svg width="600" height="300" style="outline: 5px solid #630">
  <rect width="200" height="100" fill="#f00" />
</svg>

Here I created a viewport that’s 600px wide and 300px high. Inside the viewport I created a 200px by 100px red rectangle. Since I didn’t specify units, pixels will be used as they’re the default. Because that’s what I usually want, I tend not to specify units as shortcut.

I also added an outline the <svg> element in order to see the viewport boundaries.Here’s what the code produces.

You can see a 5px brown outline that encloses an area 600px wide and 300px high. Everything inside the outline is the viewport.

The lone graphic inside the viewport is a 200x by 100px red rectangle. By default the rectangle is located with it’s top left corner at the origin of the SVG canvas, which aligns with the origin of the viewport.

One question I had was what size would the viewport be if you don’t set a width and height? I couldn’t find anything definitive. It’s up to each user-agent to decide the dimensions, but 300px by 150px seems to be the general default. I wouldn’t suggest relying on the default, though. Better to set the dimensions you want.

Moving SVG Elements on the Canvas

You can change where on the SVG canvas the rectangle is located by giving it x and/or y coordinates. Here I set both x and y to 10 (px) and you can see the rectangle moves away from the top left corner of the viewport.

1
2
3
<svg width="600" height="300" style="outline: 5px solid #630>
  <rect x="10" y="10" width="200" height="100" fill="#f00" />
</svg>

Changing the x and/or y coordinates this way moves the drawn object on the SVG canvas. The canvas itself hasn’t moved and neither has the viewport. All I’ve done is drawn the same red rectangle in a different location on the canvas.

You can also draw the rectangle so part of it is outside the viewport.

1
2
3
<svg width="600" height="300" style="outline: 5px solid #630>
  <rect x="-100" y="-50" width="200" height="100" fill="#f00" />
</svg>

You can see here that most of the rectangle is no longer visible. Only the portion still inside the viewport can be seen. While I’ve only moved it a few pixels, in theory you could draw the rectangle anywhere you’d like on the infinite SVG canvas.

Seeing Outside the Viewport

One thing I don’t see mentioned often is why we can’t see anything outside of the viewport. The reason is the SVG element has its overflow property set to hidden by default so anything outside the viewport is hidden.

Of course, the overflow property has some other values, including visible.

1
2
3
<svg width="600" height="300" style="outline: 5px solid #630; overflow: visible">
  <rect x="-100" y="-50" width="200" height="100" fill="red" />
</svg>

Changing the overflow property to visible lets you see the parts of the SVG canvas that are outside the viewport, at least the part of the canvas that fits within your screen (another viewport created by your browser).

Now you can see the entire red rectangle, including the part outside the viewport. You won’t normally do this when working with SVG, but it can be a good way to help you understand what’s going on.

Establishing a new Viewport

Earlier I said there are multiple SVG coordinate systems in play at the same time. One for the canvas and one for the viewport at the very least. I also mentioned you can create new canvases and establish new viewports.

Anytime you create a new SVG element, even one nested inside another SVG element you create a new canvas and viewport with its own coordinate systems. A handful of elements create new canvases and viewports.

  • The <svg> element
  • The <symbol> element when instantiated with the <use> element
  • An <img> element that references an SVG file
  • A <foreignObject> element

Since we haven’t discussed these elements (aside from the svg element) yet, I’ll just list them for now. I mainly wanted reinforce that you can create multiple SVG canvases and viewports in the same HTML document.

Closing Thoughts

I’d like to stop here for today. It might not seem like I covered a lot of new things about SVG, but I want the conceptual understanding to sink in.

The metaphor that helped me understand the concept is that of an infinite wall in front of an equally infinite canvas. We can see the SVG canvas through a window in the wall called the SVG viewport and we can control the size of this window.

Next week I want to continue and talk about the first of two attributes we can use to move the canvas around and decide what part and how much of it to show through the viewport. I’ll look at the viewBox attribute and the following week I’ll talk about the preserveAspectRatio attribute.

Download a free sample from my book, Design Fundamentals.

Leave a Reply

Your email address will not be published. Required fields are marked *