kjo
kjo

Reputation: 35301

Perplexed by SVG viewBox, width, height, etc

If my understanding of SVG were correct, the following two SVG descriptions would result in identical images, but they don't. (NOTE: The two code listings differ only in the coordinate values in their svg tags. More specifically, for every (x, y) pair in the first listing there's an (x-205, y-55) pair in the second listing.)

<!DOCTYPE html>
<html>
  <head><title>title</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
     x="0" y="0" width="210" height="60" viewBox="0 0 210 60">

      <g style="stroke: black; fill: none;">
        <path d="M 5 5 Q 105 55 205 55"/>
      </g>

    </svg>

  </body>
</html>

<!DOCTYPE html>
<html>
  <head><title>title</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
     x="-205" y="-55" width="210" height="60" viewBox="-205 -55 5 5">

      <g style="stroke: black; fill: none;">
        <path d="M -200 -50 Q -100 0 0 0"/>
      </g>

    </svg>

  </body>
</html>

In fact, according to Firefox at least, they look quite different. The rendering that I expected for both of them is what Firefox delivers for the first one (namely, a curve gently sloping down from left to right, with an initial slope of -1/2 and and final slope of 0). I'm utterly befuddled by what FF produces for the second one, because, AFAICT, the second spec is a simple wholesale ("rigid") translation, by the vector (-205, -55), of the first one.

Why don't the two displays look identical?

Upvotes: 53

Views: 35623

Answers (4)

For a precis on the viewBox see the (only) figure in this article: https://web.archive.org/web/20140119030353/https://software.intel.com/en-us/html5/blogs/viewbox-a-window-into-the-soul-of-svg, inlined below for convenience:

viewBox in a nutshell

That picture is worth 1000 words of explanation.

The width and height parameters, aka the viewport in W3C terminology are a different thing. But you're not changing those in the above example. There is a slightly complex algorithm for determining if the width and height from the SVG actually do anything because they can be overridden for example by the <object> tag that embeds the SVG in an HTML page. There are more corner cases explained at http://www.w3.org/TR/SVG/coords.html#ViewportSpace. For a more visually oriented (and perhaps more approachable) explanation of this viewport issue, you could also consult the Inkscape manual http://tavmjong.free.fr/INKSCAPE/MANUAL/html/Web-SVG-Positioning.html (As an aside, there's an extension available to set the viewBox visually from Inkscape http://pernsteiner.org/inkscape/viewbox/ you don't really have to edit the XML directly as the Inkscape manual [still] says.)

Upvotes: 74

bytrangle
bytrangle

Reputation: 1139

To answer OP's question:

Both graphics are displayed on a 210px x 60px canvas. However, the way you set up the view box for each SVG determines which portion of that canvas is going to be displayed, and how the path element inside will be scaled to fit the new viewable area.

The x and y attributes on the <svg> element is ignored, so it doesn't do anything.

The first graphic is displayed at a scale of 1:1, because one unit of coordinate corresponds to 210 / 210 = 1 pixel in width, and 60/60 = 1 pixel in height.

How the second graphic is rendered is bit more complex. The display area starts at (-205, -55) (moving to the left and to the top compared to the previous graphic) and spans 5 x 5 user unit.

One unit of coordinate in this case is 210 / 5 = 42.5 pixels in width and 60 / 5 = 12 pixels in height.

This effectively zooms in on the 5x5 unit area and enlarges the image to 42 times its width and 12 times its heights.

As a result, what you see is the bottom right of the curve, enlarged and stretched horizontally.

If you want the second svg to look the same as the first one, you need to two view boxes have the same dimension, and both graphics have the same user unit.

To achieve the first objective, set width to 210 - (-205) = 415 and height to 60 - (-55) = 110.

To make the second graphic have a user unit of 1 pixel in width and height, set width and height attributes to 415 and 110 respectively.

svg {
  display: block;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
     x="0" y="0" width="210" height="60" viewBox="0 0 210 60">

      <g style="stroke: black; fill: none;">
        <path d="M 5 5 Q 105 55 205 55"/>
      </g>

    </svg>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
     x="-205" y="-55" width="415" height="115" viewBox="-205 -55 415 115">

      <g style="stroke: black; fill: none;">
        <path d="M -200 -50 Q -100 0 0 0"/>
      </g>

    </svg>
</body>
</html>

Upvotes: 3

borbulon
borbulon

Reputation: 1411

Very late on this one, but to clarify a point Michael made above for future viewers:

if you change some of the numbers in here, but not many, you'll get the same result.

One issue you're running into is that you think that min-x + width is supposed to be the same in either svg node. min-x and min-y are the leftmost and topmost coordinates of your viewBox - effectively changing the 0, 0 position to min-x, min-y, and are really only relevant to the coordinate system of the viewBox (and by extension to your path's d attribute), not to sizing of the viewBox itself.

Also, the x and y position of an svg node are valid but ignored and have nothing to do with any placement.

So to have your second path look like your first, you can strip away the x and y attributes, and change the width and height numbers insideviewBox to match the first one:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 width="210" height="60" viewBox="-205 -55 210 60">

  <g style="stroke: black; fill: none;">
    <path d="M -200 -50 Q -100 0 0 0"/>
  </g>

</svg>

Upvotes: 3

Michael Mullany
Michael Mullany

Reputation: 31715

Because the coordinates of viewbox are not x1, y1, x2, y2 - they are minx, miny, width and height.

Upvotes: 22

Related Questions