Pedro Henrique
Pedro Henrique

Reputation: 782

How to toggle specific <animate> tags from an <use> element (SVG)

Given the following example:

<svg xmlns="http://www.w3.org/2000/svg">

    <defs>
        <rect id="rectangle" fill="red" width="25" height="25">
            <animate 
                attributeName="fill" 
                values="red;blue;green;red"
                dur="1s" 
                repeatCount="indefinite"
            />
            <animate 
                attributeName="x" 
                values="0;50;0" 
                dur="1s" 
                repeatCount="indefinite"
            />            
        </rect>
    </defs>

    <!-- i want this to have both animations -->
    <use id="rect1" href="#rectangle" />

    <!-- i want this one to inherit only the fill animation  -->
    <use id="rect2" href="#rectangle" y="50" />

</svg>

How can I make it so that "rect2" only inherits the "fill" animation?

OBS: What I didn't wanted to do was to create an intermediate "use" element inside the defs, so the main rect would have the fill animation and the intermediate use element would reference the main rect, and also declare the "x" animation. And of course, use differente "hrefs" on the external elements.

Upvotes: 0

Views: 61

Answers (2)

chrwahl
chrwahl

Reputation: 13145

As commented, maybe the <use> is not that useful in this case. You can move both the fill attribute and the <animate> elements from the <rect> to the <use> elements.

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <rect id="rectangle" width="25" height="25"/>
  </defs>
  <!-- i want this to have both animations -->
  <use id="rect1" href="#rectangle" fill="red">
    <animate
      attributeName="x" 
      values="0;50;0" 
      dur="1s" 
      repeatCount="indefinite"/>   
    <animate 
      attributeName="fill" 
      values="red;blue;green;red"
      dur="1s" 
      repeatCount="indefinite"/>
  </use>
  <!-- i want this one to inherit only the fill animation  -->
  <use id="rect2" href="#rectangle" y="50"  fill="red">
    <animate 
      attributeName="fill" 
      values="red;blue;green;red"
      dur="1s" 
      repeatCount="indefinite"/>
  </use>
</svg>

Upvotes: 0

Like said in the comments, you can't access the required attributes on <use>

Thus you have to create the SVG yourself for every instance.

This also helps you to avoid the global ID trap,
<defs> always get you into to trouble when using multiple SVGs in the page.
id="rectangle" would have been a global ID, first declaration used by every SVG on the page

<svg-rect></svg-rect>
<svg-rect fill ></svg-rect>
<svg-rect x ></svg-rect>
<svg-rect fill x dur="2s"></svg-rect>

and a native Web Component does it all:

customElements.define("svg-rect", class extends HTMLElement{
  connectedCallback(){
    this.style.display = "block";
    let dur = this.getAttribute("dur") || "1s"
    let svg = `<svg width="100px" viewBox="0 0 75 25" style="background:pink">`;
    svg += `<rect fill="red" width="25" height="25">`;
    
    if (this.hasAttribute("fill")) {
      let colors = this.getAttribute("colors") || "red;blue;green;red";
      svg += `<animate attributeName="fill" values="${colors}" dur="${dur}" repeatCount="indefinite"/>`;
    }
    
    if (this.hasAttribute("x")) {
      svg += `<animate attributeName="x" values="0;50;0" dur="${dur}" repeatCount="indefinite"/>`
    }
    
    svg += `</rect>`;
    this.innerHTML = svg;
  }
})
<svg-rect></svg-rect>
<svg-rect fill dur="3s" ></svg-rect>
<svg-rect x ></svg-rect>
<svg-rect fill x dur="2s"></svg-rect>

Upvotes: 0

Related Questions