How can I achieve changing the style of an "use element", defined in defs, through scripting? I was trying to move in the w3c working draft interfaces, but I lost in that labyrinth
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100" id="svg1"> <defs> <g id="minchia" onclick="color(evt)"> <rect width="50" height="50" style="fill:#ffff6e;stroke:#ee1400;stroke-width:3" /> </g> </defs> <script type="text/javascript"> <![CDATA[ function color(evt) { node = evt.target.correspondingUseElement; alert(node.getAttributeNS(null, "style")); /* empty! */ alert(node.getAttributeNS("http://www.w3.org/1999/xlink", "style")); /* empty! */ node.setAttributeNS("http://www.w3.org/1999/xlink", "fill", "blue"); /* nothing */ node.setAttributeNS(null, "fill", "blue"); /* nothing */ } ]]> </script> <use xlink:href="#minchia" id="frufru" x="10" y="10" /> </svg>
Update
One more thing: what if the referenced element is a "g" which contains 2 other elements, like a rect and a text? How do I set the attribute for the right childNode (through DOM methods off course)? In this example, the setAttribute is styling the first child of the referenced element. What if I had to style the second one?
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="1000" id="svg1"> <defs> <g id="test" onclick="color(evt)" > <rect width="54" height="58" x="1.5" y="1.5" id="rect5" /> <text x="-34" y="47" transform="matrix(0.66777386,-0.74436421,0.74436421,0.66777386,0,0)" id="text2987" style="font-size:30px;fill:#ffffff;stroke-width:0px">JC!</text> </g> </defs> <script type="text/javascript"> <![CDATA[ function color(evt) { node = evt.target.correspondingUseElement; node.setAttributeNS(null, "style", "fill:blue"); } ]]> </script> <use xlink:href="#test" id="frufru" x="10" y="10" style="fill:#000000" /> </svg>
The SVG <defs> element is used to embed definitions that can be reused inside an SVG image. Using the SVG <defs> elements you can group SVG shapes together and reuse them as a single shape. The shapes defined inside the <defs> element will be displayed when you reference it by a <use> element.
<defs> The <defs> element is used to store graphical objects that will be used at a later time. Objects created inside a <defs> element are not rendered directly. To display them you have to reference them (with a <use> element for example).
The SVG <use> element can reuse an SVG shape from elsewhere in the SVG document, including <g> elements and <symbol> elements. The reused shape can be defined inside the <defs> element (which makes the shape invisible until used) or outside.
The xlink:href attribute defines a reference to a resource as a reference IRI. The exact meaning of that link depends on the context of each element using it. Note: SVG 2 removed the need for the xlink namespace, so instead of xlink:href you should use href .
As you can see in my test page, if you define the visual style of an element inside the <defs>
section of a document you cannot override that style on the <use>
instance, not through a visual attribute, style
attribute, or CSS class applied to the <use>
.
Further, you cannot use a visual attribute on the <use>
element to cascade styles down to elements of the source; you must use CSS styling for this.
You'll have to:
Use either CSS or set a manually-parsed-or-created style
attribute, e.g.
node.setAttribute('style','fill:blue');
As noted here you can use either setAttribute(...)
or setAttributeNS(null,...)
for SVG attributes.
Update: To answer your second question:
What if the referenced element is a "g" which contains 2 other elements, like a rect and a text?
You cannot use CSS rules to select the pseudo-children of a <use>
; they simply don't exist. What you can do, however, is apply the unchanging styling that you want to preserve inside the <def>
and then apply the style
you want on the <use>
.
For example:
<defs> <g id="foo"> <!-- Every rect instance should be filled with blue --> <rect width="54" height="58" x="1.5" y="1.5" fill="blue" /> <!-- I want to be able to change text color per use so I must be sure not to specify the fill style --> <text x="-34" y="47" transform="matrix(0.668,-0.744,0.744,0.668,0,0)" style="font-size:30px;stroke-width:0px">JC!</text> </g> </defs> <use xlink:href="#foo" style="fill:orange" transform="translate(0,-100)" /> <use xlink:href="#foo" style="fill:yellow" transform="translate(0, 100)" />
This only works if you want all changeable items to have their attributes set the same way.
Unlike HTML, the markup in SVG is the presentation. What I've suggested above is a bit of a hack that happens to work, but in general <use>
elements are designed to instantiate the full appearance of a definition. If you need custom appearance per instance, perhaps you should consider cloning elements, modifying properties, and adding those to the document instead of hacking a <use>
.
To add to @Phrogz answer, It looks like even if i try to overwrite the styles defined inside the symbol
tag its not getting overwritten in the use tag. A fiddle for that http://jsfiddle.net/rajkamal/xrdgf/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With