Marked
Marked

Reputation: 162

SVG mm and px co-ordinates lengths differ for defined viewBox

In the following SVG image I expected the two rectangles to be at the same location and have the same size but they do not.

My understanding of the viewBox attribute is that in this instance 10px should be equal to 1mm. Is this correct or am I missing something?

<?xml version="1.0" standalone="yes"?>
<svg 
    width="210mm" 
    height="297mm" 
    viewBox="0,0,2100,2970"
    preserveAspectRatio="none"        
    xmlns="http://www.w3.org/2000/svg">
        <rect x="10mm" y="10mm" width="50mm" height="50mm"
            fill="rgba(155,155,155,0.5)" id="x1" ></rect> 
        <rect x="100" y="100" width="500" height="500"
            fill="rgba(155,155,155,0.5)" id="x2" ></rect> 

    </svg>

resulting image

Thanks in advance!

Upvotes: 3

Views: 11560

Answers (2)

Paul LeBeau
Paul LeBeau

Reputation: 101810

My understanding of the viewBox attribute is that in this instance 10px should be equal to 1mm. Is my this correct?

No, that's not correct. The SVG width value of "210mm" defines the SVG viewport width. In other words, how wide the <svg> document will appear on the page. That works out to be 794px or so. That conversion is based on the standard CSS DPI of 96 "pixels" per inch.

But "mm" values used for coordinates inside the SVG document will be converted and treated as values in the SVG user coordinate system. The same conversion ratio is used. So "1mm" will be converted to approx "3.78". Much smaller than "10".

Upvotes: 1

Matthew
Matthew

Reputation: 7590

What happens is that when you specify a unit using mm is that it must first be scaled to pixels by multiplying by the number of pixels per mm (looking around it looks like this is usually about 3.78, but that could change in various situations). Thus your actual width in pixels is 210x where x is the number of pixels per mm.

Looking at your second rectangle (without units), it starts at a point 100/2100 = 4.76% of the way from the left edge.

Your first rectangle (remembering that we must first translate from mm to pixels by the above scaling) starts at 10x/2100 = 1.8% of the way from the left (using that value of 3.78).

Adding

<line x1="1.8%" y1="0%" y2="100%" x2="1.8%" stroke="black" fill="none"/>
<line x1="4.76%" y1="0%" y2="100%" x2="4.76%" stroke="black" fill="none"/>

to the svg (and changing to color of the rectangle without a unit specifier), we see that these percentages are exactly where the edges lie.

enter image description here

For this reason, it is probably not a good idea to use a viewBox and unit specifiers on coordinates as well.

Remember that the viewBox is effectively a transformation (some combination of a scaling and a translation). Thus if two objects look different without the viewBox (which these two rectangles would), then they must also be different with the viewBox.

The simplified one sentence explanation here is that due to this transformation, the meaning of 1mm is different inside the viewBox than outside.

Upvotes: 5

Related Questions