How to animate SVG paths using GreenSock’s GSAPJS

  • Polygon.com SVG animation

In 2013, Twitter was all abuzz about the impressive animation that polygon.com used for their Xbox and PS4 review. After I saw it I wanted to find out whether I could do something similar.

So how would you go about writing code for animating SVG paths?

The theory that speaks to svg graphics animaion is pretty simple. You need to select the SVG document, collect all the paths within it, calculate their total lengths, then animate the graphics. The SVG graphics come with stroke-dasharray and stroke-dashoffset properties; the first property controls the pattern of dashes and gaps in svg paths; the second property controls the distance to the start of the dash pattern. In this SVG animation approach, stroke-dasharray contains comma or white space separated length values that specify the length of dashes and spaces. By adding the same values to both properties we can make the SVG graphic dissapear (or at least appear to). Once the graphic disappears, all that’s left is to animate the value of the stroke-dashoffset to give the illusion of lines drawing on the screen.

SVG Animation: Easier said than done though, right?

Not at all; it’s pretty straightforward.
A quick search revealed the easiest way to carry out this animation is through the use of the <object> element and embedding the SVG graphic in your document, but I decided not to go this way. Polygon inserts their SVG graphic right in the document and then manages to animate the svg paths–I decided to do the same.

Immediately, I hit a hurdle. Using the document.getElementsByTagName() or  document.getElementById() can select the SVG elements but you won’t have access to the methods that come with the SVG so calculating the svg path length may prove difficult. document.getElementsByTagNameNS() to the rescue! It does similar work that getElementsByTagName does, but returns the list of elements belonging to the given namespace.

Animating SVG paths in 10 simple steps

Let’s begin the build process by adding your SVG graphics to the document:

<div id=”animation”>
    Paste your svg document here;
</div>

Now the document should show your image; click the image below to see what we are about to build.

svgf3result

Let’s jump to the animation script; the next few lines of JavaScript is where the magic happens. For the purpose of this example I am using GreenSock’s GSAPJS, which is pretty much the best tweening library out there, but you can apply the same principles using jQuery Animate or using requestAnimationFrame() or setInterval().

Because there are multiple paths, I decided to use TimelineMax that is a part of TweenMax library. Let’s define and cache our svg animation timeline:

Step 1: Select our SVG container.

var svgContainer = document.getElementById(“animation”);

Step 2: Set up our SVG element namespace to use when selecting elements.

var nS = “http://www.w3.org/2000/svg”

(If you look in your SVG markup you’ll notice the xmlns property is the same)

Step 3: Set up our svg animation timeline.

var animation = new TimelineMax();

Step 4: Prevent the svg animation from playing straight away.

animation.pause();

Step 5: Select all the SVG paths.

var svgPaths = svgcontainer.getElementsByTagNameNS(ns,”path”)

Now the variable svgPaths hold an array of svg paths, so we need to traverse through it, apply base styles and push the svg animation into the animation queue.

Step 6: Traverse through paths, apply base styles and push them onto the svg animation queue.

for (var x = 0; x < svgPaths.length; x++){
 //select a path
 var path = svgPaths[x];
 //get the pixel length of the SVG path
 var pathDimensions = svgPaths.getTotalLength();
 // apply styles to stroke-dasharray and stroke-dashoffset
 path.style.strokeDasharray = pathDimensions+” “+pathDimensions;
 path.style.strokeDashoffset = pathDimensions;
 animation.add(TweenMax.to(path.style,1,{strokeDashoffset:0});
 }

The above does exactly what it says on the tin: we apply base styles to the svg path (strokeDashoffset and strokeDasharray) that are the total pixel length of the given path and using the .add() method we push the TweenMax tween definition onto the queue. The number 1 in the TweenMax definition represents seconds. If you add the animation.play() after the for loop you should see that your svg paths are animating, but the order is sequential and each is triggered once the previous element in the queue finishes animating.

To fix that and just offset the animations a little, add the negative time offset to make them animate as the other elements in the queue are animating. It’s easy with GSAP. Bear in mind that you wouldn’t want to offset the first path. The code below accounts for that. “-=0.8” will tell the svg animation queue to start animating 0.2 seconds after the previous animation started 1-0.8 = 0.2.

Step 7: Offset the SVG animation

 for (var x = 0; x < svgPaths.length; x++){
 //select a path
 var path = svgPaths[x];
 //get the pixel length of the SVG path
 var pathDimensions = svgPaths.getTotalLength();
 // apply styles to stroke-dasharray and stroke-dashoffset
 path.style.strokeDasharray = pathDimensions+” “+pathDimensions;
 path.style.strokeDashoffset = pathDimensions;
 animation.add(TweenMax.to(path.style,1,{strokeDashoffset:0},(x>0)?”-=0.8”:””);
 }

Step 8: Play the SVG animation

All you need to do now is to add the play call after the for loop.

 for (var x = 0; x < svgPaths.length; x++){
 //select a path
 var path = svgPaths[x];
 //get the pixel length of the SVG path
 var pathDimensions = svgPaths.getTotalLength();
 // apply styles to stroke-dasharray and stroke-dashoffset
 path.style.strokeDasharray = pathDimensions+” “+pathDimensions;
 path.style.strokeDashoffset = pathDimensions;
 animation.add(TweenMax.to(path.style,1,{strokeDashoffset:0},(x>0)?”-=0.8”:””);
 }
 animation.play();

Step 9: Solving browser problems

You probably noticed that Firefox and Internet Explorer have some issues animating the SVG paths (at least at the time of writing this article).

Firefox:

It seems that Firefox redraws the path multiple times during the animation.  It quickly became apparent that the strokeDashoffset value is wrong if you have used the path pixel length. The fix was actually pretty surprising and it came out to be the SVG stroke width. You will need to collect the path stroke width and divide the pathDimensions by it. Just add to your code.

var strokeWidth = (path.getAttribute(“stroke-width”) == null)?1:path.getAttribute(“stroke-width”);

then update your strokeDashoffset line to accommodate the above (just in Firefox).

path.style.strokeDashoffset = (/Firefox/i.test(navigator.userAgent))?pathDimensions/strokeWidth:pathDimensions;

Now Firefox should animate your SVG paths nicely and just once!

Internet Explorer:

You may have noticed that IE has a little bit of a problem with redrawing the SVG and parts of your image disappear on animation. The SVG object has forceRedraw() method but that seemed not to be the case. The fix for that is to force IE to redraw the whole document. Thankfully the TweenMax comes with onUpdate method in which you can control what happens each time the frame is drawn. Thomas Fuchs presents a very simple method to force the DOM redraw.

I’m going to use parts of it to achieve the required effect.

Animation.add(TweenMax.to(line.style,1,{strokeDashoffset:0,opacity:1,onUpdate:function(){
 var n = document.createTextNode(' ');
 document.body.appendChild(n);
 document.body.removeChild(n);
 }}),(x>0)?"-=0.8":"");

What the above code does is add the space character in the body element and then immediately removes it forcing the browser to redraw. Simple but very effective.

Step 10: TA DAH! You’re animating SVG paths!

That is it! Your code should now look more or less like this:

<script>
 var svgContainer = document.getElementById("animation");
 var nS="http://www.w3.org/2000/svg";
 var animation = new TimelineMax();
 animation.pause();
 var svgPaths = a.getElementsByTagNameNS(nS,"path");
 for(var x = 0; x<svgPaths.length;x++){
 var path = svgPaths[x];
 var pathDimensions = path.getTotalLength();
 var strokeWidth = path.getAttribute("stroke-width");
 path.style.strokeDasharray = (pathDimensions)+" "+(pathDimensions);
 path.style.strokeDashoffset = (/Firefox/i.test(navigator.userAgent))? pathDimensions/strokeWidth : pathDimensions;
 animation.add(TweenMax.to(path.style,1,{strokeDashoffset:0,onUpdate:function(){
 var n = document.createTextNode(' ');
 document.body.appendChild(n);
 document.body.removeChild(n);
 }}),(x>0)?"-=0.8":"");
 }
 animation.play();
 </script>

This code is somewhat flawed and it only supports the “path” element of an SVG–and there is so much more than just paths to it. With simple alterations to the above code you can extend it so it supports more than just the SVG path.

Share this article
Tags


Yes is the answer. Even if not directly, we can always point you in the right direction. But chances are that with our broad experience across the branding, digital and marketing spectrums, we can help you to win and make it fun along the way.

  • Dave
  • Daniel
  • Sebastian
  • Laura

© Copyright Factor 3 Communications Ltd. 2016 | Privacy policy | Cookie policy