Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
ltscribble

accessing svg paths in external file

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I have an animation with a lot of svg's in it, so I'd like to reference them so that the code in the page is a bit easier to handle. 

 

I can animate the paths if I have all the svgs in the page but is it possible to move the svg's into a external files (I've tried <svg> <use> and <img>) but I can't seem to target the paths when I do this?

 

See the Pen ByRNEZ by LegendT (@LegendT) on CodePen

Link to comment
Share on other sites

As far as I'm aware, the best way to embed external svg file in html at the moment is using <object> tag. The syntax is like following:

 

<object type="image/svg+xml" data="images/mySVG.svg"><!--fallback--></object>
 
"Fallback" option here allows you to specify alternative image in standard jpeg format just in case user's browser doesn't support svg.
 
So, you can take your svg code, place it in external svg file and connect it like that, but the downside will be inability to apply CSS stylesheets or use external JS scripts, everything should be contained within this svg file.
 
To be honest, lately I read somewhere about possiibility to connect external CSS stylesheets to <object> svg, but haven't managed it to work (yet). For this reason I stuck with inline svg for now.
  • Like 1
Link to comment
Share on other sites

Hi ltscribble  :)

 

try this :

 

html :

<object id="yoursvg" data="SvgFile.svg" type="image/svg+xml" ></object>

js :

var colors =["#FF0000","#FFFF00","#00FF00","#00FFFF","#0000FF","#FF00FF","#ED1C24","#FFF200","#00A651","#00AEEF","#2E3192","#EC008C","#FF0000"];

document.getElementById("yoursvg").addEventListener("load", function() {
   var doc = this.getSVGDocument();
   var hand = doc.getElementById("left-hand-palm"); 

   tl = new TimelineMax({repeat:-1});
   for (j = 0; j < colors.length; j++) {
   tl.to(hand, 1, {fill:colors[j], ease:Linear.ease});
   };
  
});
  • Like 4
Link to comment
Share on other sites

Diaco.AW, nice approach, I tried it with my project. It works with Firefox and Internet Explorer, but Chrome seems to have some kind of security problem with accessing embedded svg files.

var doc = this.getSVGDocument();   //returns null

 

Also, they say using .contentDocument is more advisable instead of .getSVGDocument(), which is deprecated, but this doesn't help with Chrome.

http://stackoverflow.com/questions/22529398/getsvgdocument-returns-null-in-firefox-and-chrome
http://stackoverflow.com/questions/337293/how-to-check-if-an-embedded-svg-document-is-loaded-in-an-html-page

Link to comment
Share on other sites

pls use a local test server like Xampp ; some browsers like the Google Chrome will not load local file by default due to security reason .

  • Like 5
Link to comment
Share on other sites

Yes, local server solves the problem! Thanks!

Link to comment
Share on other sites

Hi Scribble,

 

The SVG inside the <use> tags won't show up in your CodePen because the file is on another domain and you aren't referencing it (#left-hand).

 

<svg class="left-hand">
  <use xlink:href="http://my-server.com/left-hands.svg#left-hand"></use>
</svg>

However, using <use> might not be the best solution if you are trying to create SVG animations. First, IE does not support it, although there are ways around this. Second, the SVG is encapsulated so you won't be able to directly select your shapes/paths.

 

// Won't work with <use>
var hand = $("#left-hand-palm");

Diaco did a good job of showing us how to embed and reference an SVG. However, an embedded SVG is encapsulated inside an external document, so things like your CSS styles won't crossover into the SVG's document. 

 

I like to load external SVGs via Ajax, and then inject them into the page. Doing this will allow you to interact with the SVG just like an inline SVG. No need to modify your code!

 

Here's a demo of how to display an SVG using the ajax, object, use, and inline approaches. Notice how only the ajax version works like the inline version.

 

Plunker URL: http://plnkr.co/edit/LneUEK?p=preview

  • Like 11
Link to comment
Share on other sites

And here's the above-mentioned method to connect extarnal css stylesheet to embedded as <object> svg file. I made it work at last)

You have to place this in the head of your svg file, just above the opening <svg> tag:

<?xml-stylesheet href="../css/svg-style.css" type="text/css"?>
<svg...

Pay attention to URL path, if's usually better to give the full path starting from root folder.

 

Slightly other way of doing the same:
 

<svg>
<defs>
<link href="../css/svg-style.css" type="text/css" rel="stylesheet" xmlns="http://www.w3.org/1999/xhtml"/>
</defs>
...
Link to comment
Share on other sites

  • 5 months later...

Does @Raynor's technique work on multiple objects with the same id? I just started with gsap myself here.

 

I had a div thumbnail that I wanted to place an animated svg frame on top of as a spinning border, I started with @Diaco's approach and looped with the getElementsByClassName div to count the ids up +1.

 

My question would be, is this ok to loop like this? I'm not sure if I should re-use a timeline or calling new TweenMaxes via svg loading has much impact on performance etc. I only need about 8-12 thumbnails per page.

.thumb {
width:180px;
height:180px;
border:none;
}

#t0 {
background: url("thumb_0.jpg") #eee no-repeat;
}

#t1 {
background: url("thumb_1.jpg") #eee no-repeat;
}
<div id="t0" class="thumb">
	<object id="nonagon0" data="nonagon.svg" type="image/svg+xml"></object>
</div>

<div id="t1" class="thumb">
	<object id="nonagon1" data="nonagon.svg" type="image/svg+xml"></object>
</div>
var t = document.getElementsByClassName("thumb");
var i;
for (i = 0; i < t.length; i++)
{
	document.getElementById("nonagon"+i).addEventListener("load", function()
	{
		var doc = this.getSVGDocument();
		var path = doc.getElementById("path");
		TweenMax.to(path, 33, { rotation:360, repeat:-1, transformOrigin:"50% 50%", ease:Linear.easeNone });
	});
}

I love the fact with this technique you can animate each path within the svg with greensock, I only have one path named 'path', but I did test it out copying multiple paths with different tween speeds / opacity for special effects. Its great you can just select the inner path to animate and not cause the whole rectangular frame to spin. My nonagon.svg is pasted below with the resulting thumbnail.

<?xml version="1.0"?>
<svg version="1.1" class="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="180px" height="180px" viewBox="0 0 180 180">
	<g class="nonagon" opacity="1">
		<path id="path" d="M-86,90 C-86,-7 -7,-86 90,-86 C187,-86 266,-7 266,90 C266,187 187,266 90,266 C-7,266 -86,187 -86,90 M89,161 L44,144 L19,102 L28,54 L66,23 L115,23 L152,55 L161,103 L135,145 L89,161 Z" 
		style=" stroke:none; fill-rule:evenodd; fill:#ffffff; fill-opacity:1; "/>
	</g>
</svg>

I'm planning on animating each thumbnails svg frame on mouse over, so I guess there might have to be an array holding each tween/timeline triggering play/pause on mouseover.

post-35697-0-18454400-1435573772_thumb.jpg

Link to comment
Share on other sites

Hi Pauls  :)

 

i think this can help you :

var svgObject = document.getElementById("svgObject") ,
svgDoc = svgObject.contentDocument ,
svgChild = svgDoc.getElementById("svgChild");
Link to comment
Share on other sites

Thanks Diaco, always nice to get things referenced.

I was testing getElementsByTagName and childNodes earlier.
 
contentDocument is the way to go. I see a getSvgPath(id, svg, path) function forming, some try catch svg loading with fallback actions might be needed later.
 
Learning gsap on the side here so Im not fantastic with some of the dom/js stuff (php, c# here) thanks for the help.
Link to comment
Share on other sites

  • 9 months later...

Hi Scribble,

 

The SVG inside the <use> tags won't show up in your CodePen because the file is on another domain and you aren't referencing it (#left-hand).

 

<svg class="left-hand">
  <use xlink:href="http://my-server.com/left-hands.svg#left-hand"></use>
</svg>
However, using <use> might not be the best solution if you are trying to create SVG animations. First, IE does not support it, although there are ways around this. Second, the SVG is encapsulated so you won't be able to directly select your shapes/paths.

 

// Won't work with <use>
var hand = $("#left-hand-palm");
Diaco did a good job of showing us how to embed and reference an SVG. However, an embedded SVG is encapsulated inside an external document, so things like your CSS styles won't crossover into the SVG's document. 

 

I like to load external SVGs via Ajax, and then inject them into the page. Doing this will allow you to interact with the SVG just like an inline SVG. No need to modify your code!

 

Here's a demo of how to display an SVG using the ajax, object, use, and inline approaches. Notice how only the ajax version works like the inline version.

 

Plunker URL: http://plnkr.co/edit/LneUEK?p=preview

 

 

This method worked like charm for me on my wordpress site – thanks! ^^

 

I have a really long svg with more than 1000 lines that some how broke by using it inline in wordpress...

  • Like 1
Link to comment
Share on other sites

Here's a couple of other variations using jQuery.
 
Easiest way to load and inject a single SVG. Just make sure the SVG element has the xmlns="http://www.w3.org/2000/svg" attribute on it.

http://plnkr.co/edit/5l2al3EPl9HIK2FQgO2C?p=preview

 

Load and inject multiple SVGs.

http://plnkr.co/edit/IWTAV5jIxzSioTpj8UkJ?p=preview

  • Like 4
Link to comment
Share on other sites

Here's a couple of other variations using jQuery.

 

Easiest way to load and inject a single SVG. Just make sure the SVG element has the xmlns="http://www.w3.org/2000/svg" attribute on it.

http://plnkr.co/edit/5l2al3EPl9HIK2FQgO2C?p=preview

 

Load and inject multiple SVGs.

http://plnkr.co/edit/IWTAV5jIxzSioTpj8UkJ?p=preview

 

Oh yes, thats actually much easier than the .get() method! I tried to combine this with ScrollMagic to trigger a GSAP animation once a certain container is in the middle of the view port but it didn't work. With the .load() method I got it working...

 

Was a long way for me because it is the first GSAP animation I made!

 

Here is the result:

 

Link was deleted

 

Thanks again for pointing me into the right direction!

  • Like 1
Link to comment
Share on other sites

Very nice!

  • Like 1
Link to comment
Share on other sites

Hi Blake,

 

I am just wondering, does this not work on CodePen because of cross-domain issues ?

See the Pen JXObLV by celli (@celli) on CodePen

Link to comment
Share on other sites

Yeah. I'm not even sure you can get AJAX to work on CodePen with your own assets because they are hosted on Amazon, which is a different origin.

 

Even non-ajax stuff can cause issues. I always have problems loading my own assets in Pixi.js and have to prefix my URLs with crossorigin.me

var baseURL = "http://crossorigin.me/https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/";
  • Like 1
Link to comment
Share on other sites

  • 2 months later...

Some of these examples appear as though the SVG code is embedded within the page, rather then the SVG file being external, not the cleanest route if you have multiple SVG files and want to keep mark-up to a minimum ?

Link to comment
Share on other sites

Only one of these examples has the SVG inline, and that was used as comparison.

Link to comment
Share on other sites

blake are you referring to this;

<div>
    <svg>
      <use xlink:href="left-hands.svg#left-hand"></use>
    </svg>
  </div>

Where as the SVG is loaded externally ? Then again, if this is what you are referring too, can you read a class or id via xlink ?

Link to comment
Share on other sites

No, I was referring to index.html file from this example. There's an inline svg in the html.

http://plnkr.co/edit/LneUEK?p=preview

 

That use tag is reading an external file, and getting an id from that file. Look at the left-hands.svg file under Files in the panel on the far left. You can read classes and ids, but I wouldn't recommend doing that with an external file because of IE.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

The use tag is non-existent ?

It is exactly what I want to do to keep mark-up cleaner, what solution is there for IE 7+ ?

Link to comment
Share on other sites

  • 1 year later...
On 6/21/2016 at 3:40 PM, OSUblake said:

No, I was referring to index.html file from this example. There's an inline svg in the html.

http://plnkr.co/edit/LneUEK?p=preview

 

That use tag is reading an external file, and getting an id from that file. Look at the left-hands.svg file under Files in the panel on the far left. You can read classes and ids, but I wouldn't recommend doing that with an external file because of IE.

 

I used to use the 'svg4everybody' javascript (https://github.com/jonathantneal/svg4everybody) to get the svg inline like this:

<div class="container">
  <svg class="logo" role="presentation">
    <use xlink:href="img/logo.svg#raf_logo"></use>
  </svg>
</div>

The result is that the SVG is presented inline in the HTML document.

That works perfect for static icons, or when you do some CSS3 animations.

But wanting to do more complex animations, I decided to go with GSAP.

Unfortunately, the 'injected' SVG with 'svg4everybody' can not be animated using GSAP.

For some reason, I just can't go into the inline SVG. No classes or id's are recognized by GSAP.

For the time being I use the inject method as presented in this example: http://plnkr.co/edit/IWTAV5jIxzSioTpj8UkJ?p=preview

 

But can someone explain why the 'svg4everybody' method doesn't work with GSAP?

Link to comment
Share on other sites

On 2/13/2018 at 11:03 AM, Woohoo said:

But can someone explain why the 'svg4everybody' method doesn't work with GSAP?

 

That's what my first post was about. I even linked to svg4everybody. You can't animate what's inside a <use> element directly. Everything inside of it is hidden inside a shadow-root.

  • Like 1
Link to comment
Share on other sites

4 hours ago, OSUblake said:

 

That's what my first post was about. I even linked to svg4everybody. You can't animate what's inside a <use> element directly. Everything inside of it is hidden inside a shadow-root.

 

Hmmm, I managed to animate something inside a <use> element.

It's probably a hack, I don't know.

This is what I did in the HTML. In the head of this HTML I include the necessary 'svg4everybody' script files. In the HTML I put the SVG with a <use> tag.

Like so:

<html>
<head>
...
<script src="js/svg4everybody.legacy.min.js"></script>
<script>
svg4everybody({polyfill: true});
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<div class="wrapper">
	<div class="toptaak_icon"><svg class="alkmaar_icon" role="presentation"><use xlink:href="img/alkmaar_iconen.svg#maaltijdverzorging"></use></svg></div>
</div>
<script>
...
</script>
</body>

This SVG file contains around 60 icons, all defined as a <symbol> with a unique ID, and I only use one of these in this example.

Now comes the weird part.

I use bits of the javascript you referred to on plunker: http://plnkr.co/edit/LneUEK?p=preview

This is how that javascript (inside the HTML document) looks like:

$(function(){
  var container = $("#foo");
  var svgUrl    = "foo.svg";
  
  $.get(svgUrl)
    .then(injectSvg)
    .always(startAnimation);
  
  function injectSvg(xmlDoc) {
    var svg = $(xmlDoc).find("svg");
    container.append(svg);
  }
  
  function startAnimation() {
  	var tl = new TimelineMax();

	var icon		= $('#maaltijd');
	var show		= $('.toptaak_icon');
	
	tl.set(show, {autoAlpha:1});
	tl.from(icon,0.5,{scaleX:0.5, scaleY:0, transformOrigin:"50% 100%", ease:Elastic. easeOut.config( 1, 0.3)});
  }
});

The first part of this script (before 'function startAnimation()' ) makes it happen.

What is weird though, is that there is no element with an id of 'foo' in the HTML, there isn't even a SVG file named 'foo.svg'.

But when I delete those lines (everything before 'function startAnimation()' ) nothing is animated, and the SVG just renders as a static icon on screen.

So somehow, these lines are needed although they refer to elements that are not present.

 

You can see it working here: https://woohoodesign.nl/svg/raf/icon-preview.html

 

I don't know exactly how I got this working (my javascript skills are limited), but it is working.

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.
×