3

I have a SVG document where three circles are drawn:

<?xml version="1.0"?>
<svg width="450" height="80" xmlns="http://www.w3.org/2000/svg">
    <script>
    document.fillCircle = function(id) {
        var circles = document.getElementsByTagName('circle'),
            circle  = document.getElementById(id);

        [].forEach.call(circles, function(circle) {
            circle.setAttribute('fill','#ffffff');
        });

        circle.setAttribute('fill', '#000000');
    }
    </script>
    <g>
        <line y1="35" x1="35" y2="35" x2="375" stroke-width="3" stroke="#000000"/>
        <circle id="state1" r="30" cy="35" cx="35"  stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
        <circle id="state2" r="30" cy="35" cx="205" stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
        <circle id="state3" r="30" cy="35" cx="375" stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
    </g>
</svg>

For testing purposes I have the onclick="" method, but actually this document is an object in my html document:

<object id="test" data="test-vector.svg" width="100px" height="100px"></object>

I have a dataset and these three circles show the "progress" of every item. I regularly update the JSON set by pulling the new list from the server. For every item changed, I want to update the filled circle.

I would like to update the svg based on some javascript. However, I can't make it to get into the DOM of the SVG. I do not really care if the fillCircle() is inside the svg or not and if I have to use <embed>, <object> or something else, but this kind of javascript does not work for me.

<html>
<body>
    <object id="test" data="test-vector.svg"></object>
    <script>
        var svg = document.getElementById('test');
        console.log(svg);
        svg.fillCircle('state2');
    </script>
</body>
</html>

I tried several things I found on SO, like this one and this one, but whatever I test, the exception is always:

Uncaught TypeError: Object #<HTMLObjectElement> has no method 'fillCircle'

2 Answers 2

8

var object = document.getElementById("test") will get you the object element but you can't call that till the object has loaded. Once you have that you can use object.contentDocument to do things with the embedded svg document.

<html>
<body>
    <object id="test" data="test-vector.svg" onload="f()" ></object>
    <script>
        function f() {
            var svg = document.getElementById('test');
            svg.contentDocument.fillCircle('state2');
        }
    </script>
</body>
</html>
Sign up to request clarification or add additional context in comments.

4 Comments

Obviously I have not thought of the load of the object. Thanks for the information. I don't like the onload="f() as a matter of personal preference, but you have pointed me in the right direction! Kudos for the fast answer!
@robert From a little experimentation this does not seem to work if the SVG's script is imported and not embeded, ie if fillCircle was in an external js file imported by the SVG. Is that the expected behavior or is there another approach?
@DavidSmith You should a separate question about that.
@robert Thanks, done that: stackoverflow.com/questions/45854847/…
2

Why don't you embed the SVG directly in your HTML code (using SVG tags)? According to W3, this works in all modern browsers (and IE >= 9). Accessing and changing the circles' properties with JS is then trivial...

<html>
    <body>
        <svg>...</svg>
    </body>
</html>


If you want to keep your HTML/SVG structure though, you can do the following:

var svg = document.getElementById("test");
svg.onload = function(){
    svg.contentDocument.fillCircle("state2");
};

The trick is to wait for the SVG object to load (onload event); not till then you can safely use the contentDocument property. Btw, this is also described in this solution on SO (you posted a link to it). ;)

1 Comment

I prefer not to embed the svg in my document because I need to place it there for about 30-40 times. I prefer to have it in one document and embed it then all those 30-40 times. About the loading, I clearly missed the point of that answer. I came up with that contentDocument usage, but without the load that failed miserably too. @robert-longson was just a bit earlier with his answer, but thanks for the good explanation! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.