title: SVG Scale without moving location
body: <p>What I'm trying to do is simple: scale some SVG dots from <code>scale(0)</code> to <code>scale(1)</code> when a sibling element is hovered using vanilla js. They are the red ones in <a href="http://jsfiddle.net/Zeaklous/ST59M/1/" rel="noreferrer"><strong>the demo</strong></a></p>
  
  <p>Here's the basic SVG setup</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
  &lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt;
  &lt;svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
        x="0px" y="0px" viewBox="0 0 720 576" style="enable-background:new 0 0 720 576;" xml:space="preserve"&gt;
      &lt;style type="text/css"&gt;
          .st3 {
              fill:red;
          }
          * {
              -webkit-transition:.3s;
              transition:.3s;
          }
      &lt;/style&gt;
      &lt;g id="Layer_4"&gt;
          &lt;!-- Shield --&gt;
          &lt;path class="st8" d="M601,304.7c-32.4-15.4-68.6-24-106.8-24c-40.4,0-78.5,9.6-112.3,26.6c4.9,79.7,41.9,146.7,109.5,187.6
              C559.8,454.1,597,385.6,601,304.7z" /&gt;
          &lt;path class="st9" d="M420.1,328.7c2.1-4.7,32.5-23.9,72.5-23.9c39.9,0,73.1,20,75.5,24.3c2.4,4.3,5.7,40-12.7,74.6
                  c-19.7,36.9-53.5,50.1-61.8,50.4c-6.4,0.2-41.8-14.3-62.5-51.6C411.5,367.4,418,333.4,420.1,328.7z" /&gt;
          &lt;circle class="st10" cx="494.9" cy="373.3" r="35.5" /&gt;
      &lt;/g&gt;
      &lt;g id="Layer_8"&gt;
          &lt;!-- Dots on shield --&gt;
          &lt;circle class="st3" cx="578.8" cy="316.2" r="4.6" /&gt;
          &lt;circle class="st3" cx="543.4" cy="346.2" r="4.6" /&gt;
          &lt;circle class="st3" cx="505" cy="375.5" r="4.6" /&gt;
      &lt;/g&gt;
  &lt;/svg&gt;
  </code></pre>
  
  <p><strong>The issue</strong> is that SVG scales based on the origin location, not the current location, thus when a transform is applied it moves the element in addition to scaling it. I am attempting to fix this situation by translating by the <code>BBox()</code> offset, scaling, then translating back but that only seemed to help and not entirely fix the issue.</p>
  
  <pre><code>var shield = document.getElementById("Layer_4"),
      dots = document.querySelectorAll("#Layer_8 .st3");
  
  toggleTransform(false);
  
  shield.onmouseover = function () { toggleTransform(true); }
  shield.onmouseout = function () { toggleTransform(false); }
  
  function toggleTransform(bool) {
      if (!bool) {
          for (var i = 0; i &lt; dots.length; i++) {
              var box = dots[i].getBBox(),
                  cx = box.x + box.width / 10,
                  cy = box.y + box.height / 10;
              //dots[i].setAttribute("transform", "translate(" + cx + " " + cy + ") scale(0) translate(" + cx + " " + cy + ")");
              dots[i].style.WebkitTransform = "translate(" + cx + "px, " + cy + "px) scale(0) translate(" + -cx + "px, " + -cy + "px)";
          }
      } else {
          for (var i = 0; i &lt; dots.length; i++) {
              var box = dots[i].getBBox(),
                  cx = box.x + box.width / 2,
                  cy = box.y + box.height / 2;
              //dots[i].setAttribute("transform", "translate(0 0) scale(1) translate(0 0)");
              dots[i].style.WebkitTransform = "translate(0, 0) scale(1) translate(0, 0)";
          }
      }
  }
  </code></pre>
  
  <p>I tried using both <code>setAttribute</code> and CSS's transform (I couldn't get <code>setAttribute</code> to transition, presumably because it's not animatable by CSS) but couldn't get it with either. I've only been testing in Chrome</p>
  
  <p>Anyone have an idea how I can scale, while not moving, red dots?</p>
  
  <p><a href="http://jsfiddle.net/Zeaklous/ST59M/1/" rel="noreferrer"><strong>Here's the demo</strong></a> again if you missed it</p>
  
  <p><strong>Edit</strong></p>
  
  <p>I made a function based on RashFlash's answer to make it quite simple to use and also takes into account offsets and different transform origins</p>
  
  <pre><code>function scaleMe(elem, scaleX, scaleY, newOffsetX, newOffsetY, originX, originY) {
      newOffsetX = null ? 0 : newOffsetX;
      newOffsetY = null ? 0 : newOffsetY;
      originX = null ? "center" : originX;
      originY = null ? "center" : originY;
  
      var bbox = elem.getBBox(),
          cx = bbox.x + (bbox.width / 2),
          cy = bbox.y + (bbox.height / 2),        
          tx = -cx * (scaleX - 1) + newOffsetX,
          ty = -cy * (scaleY - 1) + newOffsetY;        
  
      if(originX === "left" || originX === "right") {
          tx = newOffsetX;
      }
      if(originY === "top" || originY === "bottom") {
          ty = newOffsetY;
      }
  
      var scalestr = scaleX + ',' + scaleY,
          translatestr = tx + 'px,' + ty + 'px';
  
      elem.style.WebkitTransformOrigin = originX + " " + originY;
      elem.style.MozTransformOrigin = originX + " " + originY;
      elem.style.msTransformOrigin = originX + " " + originY;
      elem.style.transformOrigin = originX + " " + originY;
  
      elem.style.WebkitTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
      elem.style.MozTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
      elem.style.msTransform = "translate(" + translatestr + ") scale(" + scalestr + ")";
      elem.style.transform = "translate(" + translatestr + ") scale(" + scalestr + ")";
  }
  </code></pre>