SVG: viewBox, User Coordinates

, , …,
Buy Xah JavaScript Tutorial.

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

If you are new to SVG, see SVG: Basic Examples.

Viewport

SVG: Viewport, Default Coordinate

viewBox = User Coordinates

The viewBox attribute is used to specify user coordinates.

Here's the syntax of the viewBox:

<svg width="…" height="…" viewBox="x-min y-min x-width y-height" >

Any drawing outside of the viewBox will not be shown.

If the viewBox attribute does not exist, than the coordinate is the same as view port.

Here's some examples.

Shifting Coordinates

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

Here's 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>

Change SVG Coordinate Dimension

Here, we set the viewBox's x & 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 fill 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. (which may leave empty spaces on the sides, but no distortion or stretching.)
  2. The viewBox will be centered in viewport.

Here's the tech detail. Suppose, viewport width & height is {pX,pY} and viewBox width & 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 & position of viewBox in viewport.

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

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

  1. the viewBox be scaled non-uniformly for each x & 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 & 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="alignment spec meet or slice"

alignment spec must be one of:

meet or slice must be one of:

preserveAspectRatio Example, with 「meet」

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

The viewport & 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's the same drawing with 3 different setup of “preserveAspectRatio”. All with slice.

The viewport & 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 & width of 10. But, you also need a area for the graph's caption.

Normally, you need to scale & 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 & 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 & y: <svg x="…" y="…">. The x & y specifies where your inner SVG's viewport's upper left corner is positioned.

Here's 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.

Reference

Coordinate Systems, Transformations and Units – SVG 1.1 (Second Edition)

blog comments powered by Disqus