SVG: viewBox, User Coordinate
This page is a tutorial on SVG {viewport, viewbox, coordinates}.
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:
- x-min and y-min is the coordinate of top left corner.
- x-width and y-height is the range of the x-coordinate and y-coordinate. They cannot be negative.
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.
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.
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:
- 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.)
- 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:
- the viewBox be scaled non-uniformly for each x and y dimension. (aspect ratio isn't preserved)
- the viewBox be scaled uniformly, then shrinked, to fit.
- 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:
Preserve Aspect Ratio
To preserve aspect ratio, use this:
preserveAspectRatio="alignmentSpec MeetOrSlice"
alignmentSpec must be one of:
xMinYMin
xMinYMid
xMinYMax
xMidYMin
xMidYMid
(default)xMidYMax
xMaxYMin
xMaxYMid
xMaxYMax
MeetOrSlice must be one of:
meet
(the default) means shrink to fit. (so there may be empty area on the sides in viewport)slice
means clip. (so part of the drawing is cut off)
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.
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.
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:
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.