SVG: viewBox, User Coordinate

By Xah Lee. Date: . Last updated: .

This page is a tutorial on SVG {viewport, viewbox, coordinates}.

Viewport

SVG: Viewport

viewBox as User Coordinates

The viewBox attribute is used to specify user coordinates.

Here is the syntax of the viewBox:

<svg viewBox=spec >

The spec is a string, contains the following values, separated by space:

Any drawing with coordinate outside of the viewBox will not be shown.

If the viewBox attribute does not exist, the coordinate is the same as viewport.

[see SVG: Viewport]

Here is some examples.

Set Coordinate Origin

Here, we shift the coordinate, so the drawing area's top left corner is {30,0}.

Here is a circle centered on {30,0} with radius 20.

<svg width="100" height="100" viewBox="30 0 100 100">
<circle cx="30" cy="0" r="20" />
</svg>

Set Coordinate Width and Height

Here, we set the viewBox's x and y ranges to be both 50, and draw a circle in the middle with radius 25.

<svg width="100" height="100" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="25" />
</svg>

You can see that the viewBox fills the viewport, even though viewBox has a width of 50, and viewport has width of 100.

By default:

  1. The viewBox will be scaled uniformly to fit in the viewport by default. Aspect ratio is preserved (no distortion, no stretching.). (which may leave empty spaces on the sides.)
  2. The viewBox will be centered in viewport.

Tech detail. Suppose, viewport width and height is {pX,pY} and viewBox width and height is {bX, bY}. Now, there's 2 ratios: pX/bX and pY/bY. Whichever is smaller will be the scaling factor.

Controlling viewport/viewBox Mapping: “preserveAspectRatio” attribute

The preserveAspectRatio attribute can be used to control the exact scaling and position of viewBox in viewport.

When the viewport and viewBox have the same width and height, there are no issues.

When viewport and viewBox have different width and height, there are these cases:

  1. the viewBox be scaled non-uniformly for each x and y dimension. (aspect ratio isn't preserved)
  2. the viewBox be scaled uniformly, then shrinked, to fit.
  3. the viewBox be scaled uniformly and clipped. (so parts don't show)

When the viewBox is scaled uniformly, there's also alignment issue. Namely, allign to {top, middle, bottom} in x-dimension, and same for y-dimension.

SVG provides a very convenient attribute preserveAspectRatio. You just tell it which of the above case you want, and you don't have to do any of the math for scaling and positioning.

Do Not Preserve Aspect Ratio

preserveAspectRatio="none"

This means don't preserve aspect ratio. Scale each dimention to fit.

Compare:

<svg width="100" height="100" viewBox="0 0 50 100" preserveAspectRatio="none">
<circle cx="25" cy="50" r="25" />
</svg>
<svg width="100" height="100" viewBox="0 0 50 100" >
<circle cx="25" cy="50" r="25" />
</svg>

Preserve Aspect Ratio

To preserve aspect ratio, use this:

preserveAspectRatio="alignmentSpec MeetOrSlice"

alignmentSpec must be one of:

MeetOrSlice must be one of:

preserveAspectRatio Example, with “meet”

Here is the same drawing with 3 different setup of “preserveAspectRatio”. All with meet (the default).

The viewport and viewBox have the same height. Only the width differ. The viewport is 100px wide, and viewBox is 50px wide.

<svg width="100" height="100" viewBox="0 0 50 100"
preserveAspectRatio="xMinYMid"
>
<circle cx="25" cy="50" r="25" />
</svg>
<svg width="100" height="100" viewBox="0 0 50 100"
preserveAspectRatio="xMidYMid"
>
<circle cx="25" cy="50" r="25" />
</svg>
<svg width="100" height="100" viewBox="0 0 50 100"
preserveAspectRatio="xMaxYMid"
>
<circle cx="25" cy="50" r="25" />
</svg>

preserveAspectRatio Example, with “slice”

Here is the same drawing with 3 different setup of “preserveAspectRatio”. All with slice.

The viewport and viewBox have the same height. Only the width differ. The viewport is 100px wide, and viewBox is 200px wide.

<svg width="100" height="100" viewBox="0 0 200 100"
preserveAspectRatio="xMinYMid slice"
>
<circle cx="100" cy="50" r="50" />
</svg>
<svg width="100" height="100" viewBox="0 0 200 100"
preserveAspectRatio="xMidYMid slice"
>
<circle cx="100" cy="50" r="50" />
</svg>
<svg width="100" height="100" viewBox="0 0 200 100"
preserveAspectRatio="xMaxYMid slice"
>
<circle cx="100" cy="50" r="50" />
</svg>

Nested SVG

You can nest a SVG inside a SVG. This is useful when you want to have a area for graph and another area for caption, legends, etc.

For example, suppose you want to plot a graph y=x^2. The range you want to plot is {x, 0, 10} and {y, 0, 10}. So, you can create a view box with height and width of 10. But, you also need a area for the graph's caption.

Normally, you need to scale and position all your drawing coordinates to leave room for caption. But you can have a nested SVG tag inside the main SVG viewbox. In the inner SVG, you can just specify a viewbox dimension and position for the coordinate for your plot. This way, you don't have to otherwise recompute your drawing's coordinates.

The syntax for the nested SVG is just 2 extra attribute, x and y: <svg x="val" y="val">. The x and y specifies where your inner SVG's viewport's upper left corner is positioned.

Here is a example:

<svg width="100" height="100">
  <svg x="20" y="20" width="80" height="80" viewBox="0 0 100 100">
    <rect x="0" y="0" width="100" height="100" style="fill:green; stroke:blue; stroke-width:5" />
  </svg>
</svg>

In the above example, the SVG view box is same as view port, with side length of 100. It has a inner SVG, with side length of 80, with origin at {20,20}. The inner SVG has a view box with side length of 100. (so, you don't have to rescale your points.) It draws a square of length 100.

User Coordinate Unit Legth

SVG: ViewBox, User Coordinate's Unit Size

BUY ΣJS JavaScript in Depth