Skip to content Skip to sidebar Skip to footer

How To Get The Scale Of A SvgElement?

I am working on svg.

Solution 1:

Another SO answer shows how to get the scale of an element relative to the document using element.getBoundingClientRect().width / element.offsetWidth. However, the svg element does not have the offsetWidth property. Therefore, one solution is to temporarily prepend a "offsetWidth-able" element to the svg element, e.g. a div, read the ratio on this temporary helper, and then delete it. On the off chance that the inserted element will have an unexpected scale transform applied to it through CSS (as shown in the code snippet), this inserted element should have a style of transform: scale(1); applied to it directly.

Update: A further complication arises when a CSS transform including a scale is applied directly to the svg element itself. In this case, parsing of the style is required which can be accomplished using getComputedStyle and getPropertyValue, and extracting the scale value from the returned matrix string. This then needs to be multiplied by the relative scale of the prepended div.

Further Update: This solution does not appear to currently work in Safari because the browser is not recognizing insertAdjacentHTML in spite of the fact that the documentation I can find says it should. (Is this a Safari bug or am I missing something?) However, the solution does work in Firefox and Chrome.

var e = document.getElementById("real");
var computedTransform = window.getComputedStyle(e).getPropertyValue("transform");
if (computedTransform === "none") {
  eDirScale = 1;
} else {
  var matrix = computedTransform.match(/matrix\(([^\)]*)\)/)[1].split(/, *| +/);
  var scaleX = Math.sqrt(matrix[0] * matrix[0] + matrix[1] * matrix[1]);
  var scaleY = Math.sqrt(matrix[2] * matrix[2] + matrix[3] * matrix[3]);
  if (scaleX !== scaleY) throw "non-uniform scaling";
  eDirScale = scaleX;
}
var eRelScale = e.getBoundingClientRect().width / e.offsetWidth;
e.insertAdjacentHTML('beforebegin', '<div id="temporaryPrepended" style="transform: scale(1)"></div>');
var prepended = document.getElementById("temporaryPrepended");
var pRelScale = prepended.getBoundingClientRect().width / prepended.offsetWidth;
prepended.parentNode.removeChild(prepended);
var scale = pRelScale * eDirScale;

document.write("<p>scale directly on 'svg': " + eDirScale + "</p>");
document.write("<p>scale on 'svg' relative to document: " + eRelScale + ", i.e. doesn't work in e.g. Firefox and, while it might work in Chrome (in Feb 2016), apparently won't in the near future</p>");
document.write("<p>scale on prepended 'div' relative to document: " + pRelScale + "</p>");
document.write("<p>total scale on 'svg' relative to document: " + scale + "</p>");
div {
  transform: scale(4);
}
<div id="wrap"  style="transform: scale(2); width:300;height:300;">
  <svg id="real" style="transform: translate(10px, 10px) scale(1.5); border:red 10px solid; opacity: 0.3;" >
    <rect/>
  </svg>
</div>

When you run the code snippet above, you may have to scroll down in the snippet window or click on "Full page" to see the results.


Solution 2:

This is not possible, or better put the `real element is not being transformed. If it were to inherit the tranformation, it would be scaled twice effectively.

You would be looking for getComputedStyle, but it'll tell you the same. For reference, a property that is inherited is included here:

var e = document.getElementById("real");
console.log(window.getComputedStyle(e)["transform"]);
console.log(window.getComputedStyle(e)["color"]);
<div id="wrap"  style="transform: scale(2); color: blue; width:300; height:300;">
<svg id="real" style="border: red 10px solid;" >
     <rect/>
</svg>
</div>

Post a Comment for "How To Get The Scale Of A SvgElement?"