0

I have HTML text and SVG documents containing text, included as external object. I want to keep the size of the HTML text and the text inside the SVG document identically.

<!DOCTYPE html>
<html lang="de">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>getComputedStyle</title>
</head>

<body>
    <h3 id="headerId">Header</h3>
    <object onload="svgLoaded()" id="sampleSVG" data="sample.svg" 
        type="image/svg+xml" width="80%"></object>
    <script>
        let element = document.getElementById("headerId");
        console.log(window.getComputedStyle(element)
            .getPropertyValue("font-size"));
        console.log(element.getBoundingClientRect().height);
        var svgLoaded = function () {
            svgObject = document.getElementById("sampleSVG");
            var svgObjectIntern = svgObject.contentDocument;
            var textElement = 
               svgObjectIntern.getElementsByTagName('text');
            for (var i = 0; i < textElement.length; i++) {
                let selectedText = textElement[i];
                console.log(window
                    .getComputedStyle(selectedText)
                    .getPropertyValue("font-size"));
                console.log(selectedText.getBoundingClientRect().height);
            }
        }
    </script>
</body>
</html>

Modifying the text size inside the SVG document works fine (I am using d3.js), but as a first step I need the text size as seen by the user. If I resize the browser window or change the "width" of the SVG object, the HTML text size stays constant, whereas the text size inside the SVG changes proportionally.

To measure the text size as seen by the user I tried both "getComputedStyle" and "getBoundingClientRect". getBoundingClientRect works fine, but getComputedStyle always tells me the text size defined within the SVG document independent on any scaling.

In principle I am fine with "getBoundingClientRect". The only drawback is, this always requires a horizontal text element inside the SVG, which is not the case within all of my SVG documents. Of course I might introduce a transparent horizontal sample text.

I have the feeling, that's not very clever. Maybe there is a better solution.

1 Answers1

0

You can get at the transform matrix that transforms from the local coordinate system the text is defined in to that of the viewport the SVG is rendered into (which would be the <object> tag in your case).

While the transformation of the SVG as a whole to fit it into the size of the <object> element is a simple scale (in most cases uniform), other transformations could have happened inside the SVG: it could have been scaled unevenly, or rotated, or skewed. That all would be mirrored in the content of the matrix, and it makes its interpretation complicated. The below code example handles only the most simple case and assumes the value of the ctm.d property is a representation of an even scaling applied to the font size.

Read more about the mathematical interpretation of matrices here.

var svgLoaded = function () {
    svgObject = document.getElementById("sampleSVG");
    var svgObjectIntern = svgObject.contentDocument;
    var textElement = svgObjectIntern.getElementsByTagName('text');
    for (var i = 0; i < textElement.length; i++) {
        var selectedText = textElement[i];
        var fontsize = window
            .getComputedStyle(selectedText)
            .getPropertyValue("font-size"));
        var ctm = selectedText.getScreenCTM();
        console.log(parseFloat(fontsize) * ctm.d);
    }
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • Many thanks! Works fine. ctm.d scales both with the size of the browser window and the width-attribute. The result seems to be correct. I have to deal with the background. – Horst Marutz Mar 16 '19 at 19:04