oceanGermanique
oceanGermanique

Reputation: 409

Computing the equivalent transform of an SVG viewport

I'm trying to apply the process explained in this link :
https://www.w3.org/TR/SVG/coords.html#ComputingAViewportsTransform

I will apply the theory on a very simple example, a circle

svg {  
    background-color: gray;  
}
 <svg width="100" height="100" viewBox="0 0 50 100">  
    <circle r="50"  />  
 </svg>

I will therefore apply the process explained in the link below, the goal is then to apply the transformation and achieve the same result

8.2. Computing the equivalent transform of an SVG viewport
This process converts the min-x, min-y, width and height values of a viewBox attribute, the position and size of the element on which the viewBox attribute is defined, and the value of the preserveAspectRatio attribute on that element into a translation and a scale that is applied to content contained by the element.

  1. Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute respectively.
    the values ​​of my example
    vb-x = 0
    vb-y = 0
    vb-width = 50
    vb-height = 100

  2. Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
    I think these are the attributes of the circle element
    e-x = 0
    e-y = 0
    e-width= 50
    e-height = 50

  3. Let align be the align value of preserveAspectRatio, or 'xMidYMid' if preserveAspectRatio is not defined.
    I have not defined preserveAspectRatio
    align = xMidYMid

  4. Let meetOrSlice be the meetOrSlice value of preserveAspectRatio, or 'meet' if preserveAspectRatio is not defined or if meetOrSlice is missing from this value.
    meetOrSlice = meet

  5. Initialize scale-x to e-width/vb-width.
    scale-x = 50/50 = 1

  6. Initialize scale-y to e-height/vb-height.
    scale-y = 50/100 = 0.5

  7. If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller.
    scale-y = 1 (if I understood correctly)

  8. Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the larger.
    n/a

  9. Initialize translate-x to e-x - (vb-x * scale-x).
    translate-x = 0 - ( 0 * 1)

  10. Initialize translate-y to e-y - (vb-y * scale-y)
    translate-y = 0 - ( 0 * 1)

  11. If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
    translate-x += ( 50 - 50 * 1 ) /2
    translate-x = 0

  12. If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
    n/a

  13. If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
    translate-y += ( 100 - 100 * 1 ) /2
    translate-y = 0

  14. If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
    n/a

The transform applied to content contained by the element is given by :
translate(translate-x, translate-y) scale(scale-x, scale-y) =
translate(0 0) scale(1 1)
(of course this is not going to work, but where did I go wrong?)

svg {
    background-color: gray;
}
<svg  
    width="100"  
    height="100"  
    transform="translate(0 0) scale(1 1)">  
    <circle r="50"  />  
</svg>

Alors voilà, if I understood correctly, I could replace the viewBox element with the transformation translate(0 0) scale(1 1)
obviously, it doesn't work...
where did I go wrong?

AUGUST 4 : UPDATED FROM ACCEPTED ANSWER OF errstrietzel

first : I read the first paragraph of the specification too quickly:

This process converts the min-x, min-y, width and height values of a viewBox attribute, the position and size of the element on which the viewBox attribute is defined, and the value of the preserveAspectRatio attribute on that element into a translation and a scale that is applied to content contained by the element.

c'est-à-dire, you must put the transform attribute in the circle element and not in the svg element.

then, I miscalculated the components e-width & e-height (line 2) :

e-width= 100
e-height= 100

alors translate-x is modified :

translate-x = (e-width - 50 x 1 ) /2
translate-x = (100 - 50 ) / 2
translate-x = 25

svg {  
    background-color: gray;  
}
<svg
    width="100"  
    height="100"  
    >  
    <circle r="50" transform="translate(25 0) scale(1 1)" />  
</svg>

<h1>equivalent</h1>
<svg width="100" height="100" viewBox="0 0 50 100">  
    <circle r="50"  />  
 </svg>

Upvotes: 0

Views: 72

Answers (1)

herrstrietzel
herrstrietzel

Reputation: 17125

If your ultimate goal is to gain a deep understanding of certain SVG aspects like viewBox combined with preserveAspectRatio you may rather opt for "secondary" sources providing a way more comprehensible explanation (actually the W3C spec documentations can be ... not so great "infotainment-wise").

See for instance this elaborate post on CSS-tricks.com: »How to Scale SVG«

Fun fact: the recommended post is written by Amelia Bellamy-Royds who happens to be a member of the current W3C SVG working group.

viewBox and preserveAspectRatio

Significant for your first SVG example is that element size and viewBox don't match. In this case the default preserveAspectRatio="xMidYMid" will take effect by centering the SVG content within the elements bounding box.

svg {  
  outline: 1px solid gray; 
  display:block;
}
<h3>viewBox doesn't match element size – preserveAspectRatio settings apply</h3>
<svg width="100" height="100" viewBox="0 0 50 100">  
     <rect width="100%" height="100%" fill="none" stroke="red"/>
    <circle r="50"/>  
 </svg>
<svg width="400" height="100" viewBox="0 0 50 100">  
     <rect width="100%" height="100%" fill="none" stroke="red"/>
    <circle r="50"/>  
 </svg>


<h3>Explicit settings</h3>
 <svg width="100" height="100" viewBox="0 0 50 100"
      preserveAspectRatio="xMidYMid">  
     <rect x="0"  y="0" width="100%" height="100%" fill="none" stroke="red"/>
      <circle cx="0" cy="0"r="50"/>  
 </svg>

<h3>Omit viewBox – replicating previous result</h3>
<svg  
    width="100"  
    height="100">  
    <circle r="50" transform="translate(25 0) scale(1)" />  
</svg>

In the above example I've added a <rect> element with a size of width/height = 100% to illustrate the "object-fit" behavior. This full-size rect adapts to the intrinsic viewBox but not to the parent SVG size.
To replicate the layout without a viewBox we need to adjust the position by applying a transform to an elements but not to the parent SVG.

Applying a transform to the outermost SVG will only transform/shift the element in the HTML layout context but not inherit to inner SVG (child) elements.

Suggest clarifications for the official specs

You can also suggest improvements to the current spec descriptions via the github repo "w3c/svgwg"

Spec state: Is the specification implemented?

Keep in mind you're referring to a W3C SVG editor's draft (see the red background color on the left) – some described specs may not be implemented by any browser vendor to this date (or may be moved/removed to/from the next spec version ... or renamed ... I'm referring to the looooong history of text SVG line-wrapping concepts).

Also worth reading

Upvotes: 1

Related Questions