Jump to content
Search Community

External SVG sprites and .childnodes

CedGrvl test
Moderator Tag

Recommended Posts

I have a site with several svg icons and svg logo that I have to animate.

For a better readability, I use a sprite system on an external file.

I use XMLHttpRequests to load sprites at the beginning of the request.

 

 function getSprites(url){

    var ajax = new XMLHttpRequest();
        ajax.open("GET", url, true);
        ajax.send();
        ajax.onload = function() {

            var div = document.createElement("div");
            div.innerHTML = ajax.responseText;
            document.body.insertBefore(div, document.body.childNodes[0]);
    }

}

getSprites("./assets/images/sprites-icon.svg");
getSprites("./assets/images/sprites-logo.svg");

as soon as I use queryselector to select an element and animate it, this one is undefined

for example

 

 let shapeLogoRoadmap = document.querySelector('.js-shape-roadmap-logo').childNodes;

and here an example of svg symbol from sprite

 

<symbol id="roadmap-small-logo" viewBox="0 0 250 250">
  <g class="js-shape-roadmap-logo">
    <path fill="#93718d" style="fill: var(--first-color, #93718d)" filter="url(#AI_Shadow_2)" d="M219.4366,111.5074l-80.944-80.944a19.1431,19.1431,0,0,0-26.9852,0l-80.944,80.944a19.1431,19.1431,0,0,0,0,26.9852l80.944,80.944a19.1431,19.1431,0,0,0,26.9852,0l80.944-80.944A19.1431,19.1431,0,0,0,219.4366,111.5074ZM200.5485,135.791,135.791,200.5485a15.3013,15.3013,0,0,1-21.582,0L49.4515,135.791a15.3013,15.3013,0,0,1,0-21.582L114.209,49.4515a15.3013,15.3013,0,0,1,21.582,0l64.7575,64.7575A15.3013,15.3013,0,0,1,200.5485,135.791Z"/>
    <path fill="#977792" style="fill: var(--second-color, #977792)" filter="url(#AI_Shadow_2)" d="M201.15,114.1231,135.8769,48.85a15.4233,15.4233,0,0,0-21.7538,0L48.85,114.1231a15.4233,15.4233,0,0,0,0,21.7538L114.1231,201.15a15.4233,15.4233,0,0,0,21.7538,0L201.15,135.8769A15.4233,15.4233,0,0,0,201.15,114.1231Zm-15.2308,19.5807-52.2154,52.2154a12.3428,12.3428,0,0,1-17.4077,0L64.0808,133.7038a12.3428,12.3428,0,0,1,0-17.4077l52.2153-52.2153a12.3428,12.3428,0,0,1,17.4077,0l52.2154,52.2153A12.3428,12.3428,0,0,1,185.9192,133.7038Z"/>
    <path fill="#9c7d96" style="fill: var(--third-color, #9c7d96)" filter="url(#AI_Shadow_2)" d="M185.9192,116.2961,133.7038,64.0808a12.3428,12.3428,0,0,0-17.4077,0L64.0808,116.2961a12.3428,12.3428,0,0,0,0,17.4077l52.2153,52.2154a12.3428,12.3428,0,0,0,17.4077,0l52.2154-52.2154A12.3428,12.3428,0,0,0,185.9192,116.2961Zm-12.1846,15.6654-41.7731,41.7731a9.87,9.87,0,0,1-13.923,0L76.2654,131.9615a9.87,9.87,0,0,1,0-13.923l41.7731-41.7731a9.87,9.87,0,0,1,13.923,0l41.7731,41.7731A9.87,9.87,0,0,1,173.7346,131.9615Z"/>
    <path fill="#a0829b" style="fill: var(--fourth-color, #a0829b)" filter="url(#AI_Shadow_2)" d="M173.7346,118.0385,131.9615,76.2654a9.87,9.87,0,0,0-13.923,0L76.2654,118.0385a9.87,9.87,0,0,0,0,13.923l41.7731,41.7731a9.87,9.87,0,0,0,13.923,0l41.7731-41.7731A9.87,9.87,0,0,0,173.7346,118.0385Zm-9.7461,12.5307-33.4193,33.4193a7.8951,7.8951,0,0,1-11.1384,0L86.0115,130.5692a7.8951,7.8951,0,0,1,0-11.1384l33.4193-33.4193a7.8949,7.8949,0,0,1,11.1384,0l33.4193,33.4193A7.8951,7.8951,0,0,1,163.9885,130.5692Z"/>
    <path fill="#a98ea4" style="fill: var(--fifth-color, #a98ea4)" filter="url(#AI_Shadow_2)" d="M163.9885,130.5692l-33.4193,33.4193a7.8951,7.8951,0,0,1-11.1384,0L86.0115,130.5692a7.8951,7.8951,0,0,1,0-11.1384l33.4193-33.4193a7.8949,7.8949,0,0,1,11.1384,0l33.4193,33.4193A7.8951,7.8951,0,0,1,163.9885,130.5692Z"/>
  </g>
</symbol>

tried setinterval on animation but without success

In this situation, I want to have access to each path because I animate them one after the other.

Should I give them the same class name? or?

svg are as clear as possible, but I prefer to avoid inline svg but if there is no other better solution....

I need to have access to each path of the svg

 

I read that you can have problems with childnodes in this kind of situation?

If I understood correctly from the moment I want to access the "nodes" I have a problem with the shadow DOM?

 

To summarize, I would like to be able to manage each path of my svg, keeping a good organization.

 

I asked this question also on stack owerflow

Sorry about the copy/past

 

Thx Guys !

Link to comment
Share on other sites

Hey CedGrvl,

 

In theory document.querySelector('.js-shape-roadmap-logo') should return your element after the content has been loaded. 

 

This sort of thing is best if you put it in a minimal demo so we can see exactly what's going on. The thread below can help you set up a minimal demo:

 

Link to comment
Share on other sites

On 11/2/2019 at 4:04 PM, CedGrvl said:

Sometimes it works when I refresh the page multiple time ?

Sounds like it's a race condition then. Your listener should be on the completion of it, not a random time after it is initialized. If you can recreate your situation in a demo, we'd be happy to give it a look!

Link to comment
Share on other sites

Oh Great Is it possible to understand what I did wrong ?

 

See the Pen NWWYoEv by CedGrvl (@CedGrvl) on CodePen

 

I found this solution here  https://css-tricks.com/ajaxing-svg-sprite/  after I saw one of your posts, I think Blake.

 

So if I understand correctly, you're using a window object?

and there are two ways to inject?
innerHTML or insertAdjacentHTML ?

 

First time I see the inverted quote very useful

 

Feel so far from being confortable with js

 

Thx

Link to comment
Share on other sites

3 hours ago, CedGrvl said:

Oh Great Is it possible to understand what I did wrong ?

 

You have to wait for it to load before selecting an element. And your your SVG doesn't have a .js-shape-roadmap-logo element. Perhaps you changed it. 

 

var ajax = new XMLHttpRequest();
ajax.open("GET", "https://codepen.io/CedGrvl/pen/ZEExVjL.html", true);
ajax.send();
ajax.onload = function(e) {
  var div = document.createElement("div");
  div.innerHTML = ajax.responseText;
  document.body.insertBefore(div, document.body.childNodes[0]);
  // let shapeLogoRoadmap = document.querySelector('.js-shape-roadmap-logo').childNodes;
  let shapeLogoRoadmap = document.querySelector('#roadmap-big-logo').childNodes;
  console.log(shapeLogoRoadmap);
}

 

I'll just add that animating <use> elements can be annoying because you can't select child nodes. You're actually selecting the symbol in the svg you loaded. Changing that symbol affects all <use> elements that link to it.

 

 

 

 

3 hours ago, CedGrvl said:

I found this solution here  https://css-tricks.com/ajaxing-svg-sprite/  after I saw one of your posts, I think Blake.

 

There are several ways to load SVGs. Here's a more modern way using promises and fetch instead of callbacks and ajax.

 

See the Pen 27ecfcb76a799484b07a1d6ef75ba6b3 by osublake (@osublake) on CodePen

 

 

3 hours ago, CedGrvl said:

and there are two ways to inject?
innerHTML or insertAdjacentHTML ?

 

For strings, yes. innerHTML replaces everything inside an element. insertAdjacentHTML doesn't replace anything. You can choose from 4 different positions to append/prepend the html to.

https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML

 

3 hours ago, CedGrvl said:

First time I see the inverted quote very useful

 

There's a lot of neat uses for that. 

https://css-tricks.com/template-literals/

 

 

 

  • Like 4
Link to comment
Share on other sites

3 hours ago, CedGrvl said:

So if I understand correctly, you're using a window object?

 

Forgot to mention, that yes, I'm using the window to make it global. This pattern makes sure it doesn't overwrite window.mySvg if it already exists.

 

window.mySvg = window.mySvg || {};

 

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...