1

I have a portion of JavaScript in an HTML page that says:

function flashElements() {
    var svg = document.getElementById("mysvg").getSVGDocument();
    var all = svg.getElementsByTagName("flash");
    for (var i=0, max=all.length; i < max; i++) {
        if (all[i].flash === "on")
        {
            all[i].setAttributeNS(null, "fill", "lime");
        }
    }
}

with the SVG loaded as follows:

<object data="alpha.svg" type="image/svg+xml" id="mysvg" width="800" height="600"></object>

The idea is to call this on a particular trigger and, if any SVG elements have the particular attribute of "flash" then their fill attribute will change colour. Of course, the above doesn't work - it's looking for elements, not attributes. So how do I iterate through all the SVG elements, looking for anything with that particular attribute?

The SVG has:

<polygon points="203,20 209,32 205,32 203,28" class="trackPlain" flash="on" />
<polygon points="205,32 209,32 217,48 213,48" class="trackPlain" flash="off" />

Actually all I want to do is flash the elements (on/off) but of course IE doesn't support animations.

2
  • 1
    Just a note: it's bad authoring practice to use non-prefixed custom attributes, you should use either custom:flash="on" or data-flash="on" to avoid clashing with future svg specs. The 'custom' prefix is just an example, it can be whatever you define it as (see w3.org/TR/REC-xml-names). Commented Aug 30, 2012 at 7:00
  • Ah ok, I did wonder! Thanks for the tip. Commented Aug 30, 2012 at 14:42

3 Answers 3

3

Not very efficient, but I imagine you could do something like this:

var allElements = svg.getElementsByTagName("*");
for(var i = 0; i < allElements.length; i++) {
    var element = allElements[i];

    if(element.getAttribute("myAttr") === "on") {
        element.setAttribute("fill", "lime");
    }    
}

Your other option is to do a tree-traversal.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, that works for me. I tried putting 10,000 rects onto the screen and alternating their fill every 750ms. On Firefox is racked up 10% processor power; on IE 6%; and on both the effect was simultaneous rather than a kind of wipe effect I was expecting. But I won't be changing that many elements at once!
If a more efficient variation would be var allElements = svg.querySelectorAll("[data-flash='on']"); and then loop without comparing the attribute.
@Duopixel Good point. I was in a bit of a hurry when I answered and didn't think to use XPath.
2

Another solution would be to use CSS selectors, that avoids changing a ton of attributes and the effect should be the same.

<style>
  .trackplain[flash="on"] { fill: lime; }
</style>

Update: to be clear, the above should be placed inside the svg document.

1 Comment

That's a new one on me - I really ought to learn CSS properly! Thanks for the idea.
0

other answer using Typescript & inskscape svg :

this.mySvg = svg.getElementsByTagName("svg")[0];
let myDom = this.svg.getElementsByTagName("*");
    for(let i=0; i < myDom.length; i++) {
      let label = myDom[i].getAttribute('inkscape:label');
      let style = myDom[i].getAttribute('style');
      if (label && style) {
           myDom[i].addEventListener("click", () => this.onClick(myDom[i], style));
      }
    }

Comments

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.