title: Place one SVG element on top of another when using a non proportional viewbox
body: <p>I have this SVG:</p>
  
  <pre><code>&lt;svg id="root" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="347.27mm" viewBox="0 0 409.32783 1230.3321" width="115.48mm" version="1.1"&gt;
    &lt;circle id="b1" cx="0" cy="0" r="15" class="bottom" /&gt;
    &lt;circle id="b2" cx="120" cy="100" r="15" class="bottom" /&gt;
    &lt;g transform="translate(17,43)"&gt;
      &lt;circle id="b3" cx="240" cy="200" r="15" class="bottom" /&gt;
      &lt;circle id="b4" cx="360" cy="300" r="15" class="bottom" /&gt;
    &lt;/g&gt;
  
    &lt;!--      &lt;g transform="translate(10,20)"&gt; --&gt;
    &lt;circle id="t1" cx="80" cy="30" r="15" class="top" /&gt;
    &lt;circle id="t2" cx="130" cy="30" r="15" class="top" /&gt;
    &lt;!--        &lt;g transform="translate(10,20)"&gt; --&gt;
    &lt;circle id="t3" cx="180" cy="30" r="15" class="top" /&gt;
    &lt;circle id="t4" cx="230" cy="30" r="15" class="top" /&gt;
    &lt;!--    &lt;/g&gt; --&gt;
    &lt;!--      &lt;/g&gt; --&gt;
  &lt;/svg&gt;
  </code></pre>
  
  <p>After the red balls coordinates are changed by the code that follows. It renders as:</p>
  
  <p><a href="https://i.stack.imgur.com/NjqUb.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/NjqUb.png" alt="Rendered SVG"></a></p>
  
  <p>I want to center the red balls on top of the green ones. I have a solution that works if you remove the viewBox attribute in the SVG tag. But unfortunately I can't do that. However, this works if the viewBox isn't there:</p>
  
  <pre><code>var svg = document.getElementById("root");
  
  for (var index = 1; index &lt;= 4; index++) {
    var bottom = svg.getElementById("b" + index);
    var top = svg.getElementById("t" + index);
  
    var targetX = parseFloat(top.getAttribute("cx"));
    var targetY = parseFloat(top.getAttribute("cy"));
  
    var center = getElementCenter(svg, bottom);
  
    top.setAttribute("cx", parseFloat(center.x));
    top.setAttribute("cy", parseFloat(center.y));
  }
  
  function getTransformedCoords(x, y, matrix) {
    var transformedX = x * matrix.a + y * matrix.c + matrix.e;
    var transformedY = x * matrix.b + y * matrix.d + matrix.f;
  
    return {
      x: transformedX,
      y: transformedY
    };
  }
  
  function getElementCenter(svg, element) {
    var x, y, width = 0, height = 0;
  
    var boundingBox = element.getBBox();
    var centerX = boundingBox.x + (boundingBox.width / 2);
    var centerY = boundingBox.y + (boundingBox.height / 2);
  
    var out = getTransformedCoords(centerX, centerY, element.getCTM()); // getCTM affected by the viewport
  
    centerX = out.x;
    centerY = out.y;
  
    return {
      x: centerX,
      y: centerY
    };
  }
  </code></pre>
  
  <p>My working theory is that this is because the viewBox hasn't got the same ratio as the viewport. But I don't know how to fix that.</p>
  
  <p><em>I want to use <strong>plain JavaScript</strong> to do this. Even if it would be nice to use a suitable library.</em></p>
  
  <p><strong>Questions:</strong></p>
  
  <ol>
  <li>How can I make it work while keeping the viewBox?</li>
  <li>Is it possible to make it account for the transformations in the green circles as well? I commented those out in the SVG, but it would be nice to have something solid that works when they're in there as well. But number 1 is enough for me to accept the answer.</li>
  </ol>
  
  <p>JSFiddle if you want to try the code out: <a href="https://jsfiddle.net/kentl/gpqcdecx/" rel="nofollow noreferrer">https://jsfiddle.net/kentl/gpqcdecx/</a></p>
  
  <p>PS. Here's the CSS if you want to style it:</p>
  
  <pre><code>.top {fill:red;animation:fall 4s ease-in-out infinite;}
  .bottom{fill:green;}
  @keyframes fall {0%{opacity:0.0;}50%{opacity:1.0;}100%{opacity:0.0;}}
  </code></pre>