Jump to content


Animate SVG Object Along Motion Path

Moderator Tag
Go to solution Solved by GreenSock,

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

Using the standard animateMotion, it is very straightforward how one is to go about animating an object along a motion path. Looking at the documentation for GreenSock, however, makes this simple task seem highly confusing.


Is there a basic example or CodePen anywhere of how to go about animating an object along a motion path?

See the Pen ef9f0e1242263cf23067b09be894cfa9 by SaraSoueidan (@SaraSoueidan) on CodePen

Link to comment
Share on other sites

  • Solution

No problem:



Keep in mind:

  1. TweenMax contains BezierPlugin
  2. BezierPlugin is much, much more flexible than the <animateMotion> SMIL thing which is probably why it seems more complex. It can handle multiple types of beziers (cubic or quadratic) or it can even plot a smooth bezier through a set of points (anchors) that you provide, and it can rotate the element in the direction of the path (autoRotate:true). It's so flexible, in fact, that it can animate non-positional data. It's not limited to x/y data. It can literally animate ANY numeric property. But x/y are the most common, of course, and that's what we're seeing in this example. 
  3. The reason MorphSVGPlugin is necessary is simply because it contains all the code to parse entire SVG paths and convert them to cubic bezier data, so even though we're not morphing anything here, MorphSVGPlugin's power is being leveraged. We could, of course, dump all that code directly into BezierPlugin but that'd likely double its size. It seemed cleaner to keep BezierPlugin relatively compact and let MorphSVGPlugin do the heavy-lifting on the SVG parsing. 
  4. MorphSVGPlugin is a membership benefit of Club GreenSock, so it's not in the public github repo or the CDN. 

The docs are here: http://greensock.com/docs/#/HTML5/GSAP/Plugins/MorphSVGPlugin/pathDataToBezier/

There's a YouTube video explaining it here: 


Does that answer your question? 

  • Like 7
Link to comment
Share on other sites

Fantastic! Exactly what I was looking for. You saved me hours of digging through docs. Thanks very much.

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

I'm also looking for an alternative to SMIL animateMotion. Is there a way to achieve the finer grained control of animation timing that the keyPoints/keyTimes mechanism provides?


What I need to achieve, is let the user draw a path, record it and play back the drawing at the exact speed it was drawn. This is fairly trivial to present with SMIL animateMotion.

Link to comment
Share on other sites

The good thing about what Jack posted above is that GSAP will make your animation work cross browser! Whereas SMIL animation is not supported in any Microsoft browser (IE and Edge). SMIL animations perform inconsistent or sometimes sluggish in Chrome, Safari, and Firefox.




Also some other limitations using SMIL animations:

  • Partial support in older Safari versions refers to not working in HTML files or CSS background images.
  • As of Chrome 45 & Opera 32 SMIL is deprecated and usage will result in a warning in the console. Support is expected to be dropped in some future version.

So in Google Chrome SMIL is deprecated as of version 45, and Safari has partial support. Leaving GSAP as the only contender to animate SVG cross browser!



  • Like 1
Link to comment
Share on other sites

Hi Jameson,


You could use DrawSVG to handle the animation. To draw paths, I like to use Draggable because of the way it handles nested transforms, mouse and touch events, and event throttling. If you need path smoothing, here's two different ways you can do that.


Catmull-Rom - faster, but shows more imperfections.

See the Pen BowJed?editors=0010 by osublake (@osublake) on CodePen


Bezier Interpolation - slower, but looks smoother.

See the Pen by osublake (@osublake) on CodePen


Here's a demo of timed path drawing using DrawSVG and Draggable...

See the Pen dGwZBx by osublake (@osublake) on CodePen




For the DrawSVGPlugin, it's really annoying having to convert this...

<polygon points="100,200,300,400,500,600" />

To this...

<polygon points="100,200 300,400 500,600" />

Can you confirm that you can't use an array of points for polygons/polylines? Like everything in the SVG spec, the only people that can understand it are the people that wrote it. I haven't come across an example of it not working.

  • Like 3
Link to comment
Share on other sites

Much better!


Could you add support for arrays to the MorphSVGPlugin? I know it's not that hard to convert to a string, but it makes things simpler. So someting like this...

var points = [100,200,300,400,500,600];
var data = ["M",100,200,"L",300,400,500,600];

// From this
TweenLite.to(polyline, 1, { morphSVG: points.toString() });
TweenLite.to(path, 1, { morphSVG: data.join(" ") });

// To this
TweenLite.to(poly, 1, { morphSVG: points });
TweenLite.to(path, 1, { morphSVG: data });
Link to comment
Share on other sites

Hm, I'm not sure about that one Blake - I totally see why you'd ask about that, but I'm a bit concerned about:

  1. Sensing correctly when it's an array that should be joined like that - what if someone passes in a jQuery object that's the target shape? That'd kinda look like an array and we can't do (if obj instanceof Array) because that breaks in a multi-window environment. 
  2. I'm sure I could put together enough conditions to pretty accurately determine when it's an array with the proper data and do what you're asking (check the contents of the array and look for numbers and/or strings), but I'm not sure it's worth the extra kb and processing time for something that's so simple to do externally as you showed above. 
  3. Again, it's dead-simple to do manually. If it requires 8x as much code internally, is that delivering much benefit? 

I'm still open to that possibility, but I'm just sharing why I'm reluctant at this point. Feel free to offer other thoughts.

Link to comment
Share on other sites

Yeah, maybe it doesn't add much value if it complicates things.


As a side note about determining if something is an array. Unless you want to shim IE8, you don't need to use duck typing, instance, or toString checks anymore. You're pretty well covered using Array.isArray. It solves the multi-window environment issue, and works in all modern browsers.




  • Like 1
Link to comment
Share on other sites

Thanks for the info, Blake. And yeah, I think in the next major release, we'll strongly consider dropping support for IE8 and earlier. 

  • Like 1
Link to comment
Share on other sites

  • 4 months later...

pathDataToBezier is great! However, is there any way to animate to a percentage of the length of the bezier path?

Link to comment
Share on other sites

Sure, you could just create a tween that animates along the entire path with Linear ease, pause() it, and then tween its progress to whatever percentage you want. Pseudo code: 

var bezierTween = TweenLite.to(..., {bezier:{...}, ease:Linear.easeNone}).pause();
var percent = 0.6; //let's animate to 60%...replace this with whatever you want.
TweenLite.to(bezierTween, percent * bezierTween.duration(), {progress:percent});

You can apply whatever ease you want to that last tween. 


So you're basically using one tween to animate the "progress" value of another tween. Mind-bending, right? ;)

  • Like 3
Link to comment
Share on other sites

Cheers Jack, and Carl for the pen. Mind blown! Starting to feel a little like Inception. A dream within a dream. Or should I say 'A tween within a tween'? Boom! ;-)

  • Like 3
Link to comment
Share on other sites

Can this also be done when using TimelineMax?

Link to comment
Share on other sites

Absolutely. TimelineMax is basically a container for tweens, and it extends the same base class so that it has all the same core methods for maximum flexibility (like progress(), seek(), play(), pause(), reverse(), timeScale(), etc.)

  • Like 1
Link to comment
Share on other sites

I've added this pen to show you what I mean: 

See the Pen LkLpYq by petebarr (@petebarr) on CodePen

I'm not sure how to implement it in TimelineMax using the method you described.

Link to comment
Share on other sites

hmm, I'm really not sure what you mean. 

It really helps to provide a reduced demo with just code related to what needs solving.


Jack, was describing that a TimelineMax also has a progress() method that can be animated.


I'm sort of guessing that you are asking to animate progress() of the animation that moves the circles.


Maybe something like this: 

var tl = new TimelineMax({repeat:-1, repeatDelay:2});
var baseTime = 0.7;
var percs = [53, 60, 66, 85, 100];
var linesPerc = ["0% "+percs[0]+"%", "0% "+percs[1]+"%", "0% "+percs[2]+"%", "0% "+percs[3]+"%", "0% "+percs[4]+"%"];

var bezTimeline = new TimelineLite({paused:true});
bezTimeline.staggerTo(".circ", 2, {
  cycle: {
    bezier: function(i) { 
      var line = ".line"+[i];
      var circ = ".circ"+[i];
      var motionPath = MorphSVGPlugin.pathDataToBezier(line, {align:circ});
      return {values:motionPath, type:"cubic"};
}, 0.15);

tl.fromTo('#center-circ', baseTime*1, { scale: 0 }, { 
    scale: 1,
    delay: 0.5,
    ease: Elastic.easeOut.config(0.5, 0.4)
}, 0.15)

//control the progress of the bezierTimeline?
tl.to(bezTimeline, 1, {progress:0.2, ease:Back.easeOut})
  .to(bezTimeline, 1, {progress:0.4, ease:Back.easeOut}, "+=1")
  .to(bezTimeline, 1, {progress:1}, "+=1")



If not, please try to be more specific about the effect you are trying to achieve. Thanks.

Link to comment
Share on other sites

I'm trying to get the dots to rotate round with the ends of the white lines at the same time as they draw out, as if they are stuck to the ends of the lines.

Link to comment
Share on other sites

hmm, it sounds like you need to control the progress of individual tweens. Instead of using the staggerTo and cycle to generate the circle-along-a-motion path tweens you should make them all separately outside the timeline and then inside your timeline create tween's that animate the progress of each when each line starts animating with DrawSVG. 


If it were me I'd back away from using stagger for each effect. Create a loop that does the animation for 1 circle and 1 line in each iteration. Will make it easier to put each animation in the main timeline at the right time. 

Link to comment
Share on other sites

Cheers Carl, I'll give that a blast later. Really appreciate your help guys!! Awesome!

Link to comment
Share on other sites

That worked Carl, cheers again. 

See the Pen LkLpYq by petebarr (@petebarr) on CodePen


My code could be cleaned up a little in a loop, but works for now :-)

  • Like 4
Link to comment
Share on other sites

Very nice! Glad you got it working. Thanks for the update.

Link to comment
Share on other sites

  • 3 weeks later...

Hey Jack and Carl,


Just thought I'd show you the final live result for the project I was using this in: http://murraytweetindex.ie/


Thanks for the great support once again!


Pete (aka Barman) ;-)


Also, I've got all the main animations in pens if they are of help to anyone else:




See the Pen LkLpYq by petebarr (@petebarr) on CodePen


See the Pen YWLjQW by petebarr (@petebarr) on CodePen


See the Pen WxyvqO by petebarr (@petebarr) on CodePen

  • Like 6
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.