Life
Copyright © 2024 Jiri Kriz, www.nosco.ch

SVG Coordinates

Comments (0)
Experiments with SVG coordinates.

Basic setting

I use the inline <svg> element and style it as follows:

<style>
	svg {
		border: 5px solid #8000ff;
	}
	line {
		stroke-width: 1; 
		stroke: #F00;
	}
	rect {
		fill: #0F0; 
		stroke-width: 5; 
		stroke: #000;
	}
	circle {
		fill: #FF0; 
		stroke-width: 5; 
		stroke: #000;
	}
</style>

Let us look at the following drawing

that was generated using the code:

<svg width="400" height="200" 
	viewBox="0 0 400 200" 
	preserveAspectRatio="xMidYMid meet">
<rect x="0" y="0" width="100" height="150" />
<circle cx="300" cy="0" r="50" />
<line x1="200" y1="0" x2="200" y2="200" />
<line x1="0" y1="100" x2="400" y2="100" />
</svg>

The coordinates inside <svg> are in a virtual coordinate system with (0, 0) at the top left corner, the horizonatal axis x (resp. width) running to the right and the vertical axis y (resp. height) running downwards.

The viewBox="0 0 400 200" is a rectangle in this system with x=0, y=0, width=400, height=200 that specifies the area of svg that will be displayed in the browser. Everything outside this area is ignored and clipped off. We see that a part of the circle that is outside the vievBox is clipped off. The left and top borders of the rectange are thinner than the other borders. The left border is drawn at x=0 and has the width 5, so it is drawn at the pixels -2, -1, 0, 1, 2 but because of the viewBox starting at x=0 only the pixels 0, 1, 2 are visible such that the effective width of the left border is only 3. Analogously, the "height" of the top border is 3.

I specified also the dimensions <svg width="400" height="200" ... . These are the sizes of the "viewport" that is the area in the browser window where the <svg> is displayed. The browser maps the viewBox to the viewport. The mapping is defined by preserveAspectRatio="xMidYMid meet" . This means that center of the viewBox is mapped to the center of the viewport and the mapping preserves the aspect ratio which is the ratio between width and height. This specification of the preserveAspectRatio is the default value and could have been ommitted. In the example the size of the viewport equals the size of the viewBox so the mapping is 1:1, without any scaling. Notice also that the viewport remains fixed when you resize the browser window.

Mapping of viewBox to viewport

Let us change the viewport to 300x200 but keep the viewBox:

<svg width="320" height="100" 
	viewBox="0 0 400 200" 
	preserveAspectRatio="xMidYMid meet">
<rect x="0" y="0" width="100" height="150" />
<circle cx="300" cy="0" r="50" />
<line x1="200" y1="0" x2="200" y2="200" />
<line x1="0" y1="100" x2="400" y2="100" />
</svg>

The center of the view is the cross, i.e. the intersection of the two red lines. This is mapped to the center of the viewport, which is the drawing area in the browser window. The length of the red lines equals the size of the viewBox. We see that the drawing was scaled such that the viewBox fits maximally into the viewport without distortion of the aspect ratio. We denote by w, h the width and height of the viewBox and by W, H the width and height of the viewport. The scaling factor is:

f = min(w / W, h / H)
f = min(400/320, 200/100) = 1.25

Let us denote the coordinates in the <svg> by x, y and the coordinates in the viewport by X, Y. Let x_0, y_0 be the coordinates of the top left corner of the viewBox in the svg-system. The coordinate system in the viewport has the origin at the top left corner of the viewport (purple rectangle) with the X-axis running to the right and the Y-axis running downwards.

The mapping preserveAspectRatio="xMidYMid meet" . from the viewBox to the viewport is:

Mapping "xMidYMid meet":

middle point of the viewBox (in svg-system):
(x_m, y_m) = (x_0 + w/2, y_0 + h/2)

middle point of the viewport (in viewport system):
(X_m, Y_m) = (W/2, H/2)

mapping (x, y) -> (X, Y):
(X, Y) = (X_m + f*(x - x_m), Y_m + f*(y - y_m)

Another common mapping is preserveAspectRatio="xMinYMin meet" . This mapping maps (x_0, y_0) of the viewBox to (0, 0) of the viewport:

Mapping "xMinYMin meet": (x, y) -> (X, Y):
(X, Y) = (f*x, f*y)
<svg width="320" height="100" 
	viewBox="0 0 400 200" 
	preserveAspectRatio="xMinYMin meet">
<rect x="0" y="0" width="100" height="150" />
<circle cx="300" cy="0" r="50" />
<line x1="200" y1="0" x2="200" y2="200" />
<line x1="0" y1="100" x2="400" y2="100" />
</svg>

Unspecified viewport

If the viewport is not specified then it is assumed that its width W fills completely the width of the browser window resp. the width of the enclosing HTML element (<body>, <div>, ... ).

<svg viewBox="0 0 400 200">
<rect x="0" y="0" width="100" height="150" />
<circle cx="300" cy="0" r="50" />
<line x1="200" y1="0" x2="200" y2="200" />
<line x1="0" y1="100" x2="400" y2="100" />
</svg>

Resize the width of the browser window with the mouse. The drawing is resized correspondingly and fills the whole width of the browser window. (The thin margins on the left and right are the 10px padding of the <body> element.)

Let us consider what happens if we put <svg> into a <div>

<div style="width:300px; height:100px; 
	border:5px solid #bf8040;">
<svg viewBox="0 0 400 200">
<rect x="0" y="0" width="100" height="150" />
<circle cx="300" cy="0" r="50" />
<line x1="200" y1="0" x2="200" y2="200" />
<line x1="0" y1="100" x2="400" y2="100" />
</svg>
</div>

<svg> respects the width restriction of the <div> , but not the height restriction. Here is the effect of:

<div style="width:300px; height:100px; 
	border:5px solid #bf8040; 
	overflow:auto;">

If we specify only the width <div style="width:300px;"> :

The best strategy is likely not to specify the dimensions of the enclosing <div> or to specify the width only setting it to the width of the viewport. So, if we want to center the <svg> inside a <div> :

<div style="width:300px; margin:auto; 
	border:5px solid #bf8040;" >
<svg width="300" height="100" viewBox="0 0 400 200">
...

The centering can also be achieved easily by declaring <svg> to be a block (it is "inline" per default).

<svg width="320" height="100" style="display:block; margin:auto;"
	viewBox="0 0 400 200" 
	preserveAspectRatio="xMinYMin meet">
...

Links

Comments

New Comment