Animate along path

4,822 views
Skip to first unread message

James

unread,
Dec 4, 2013, 4:09:19 AM12/4/13
to sna...@googlegroups.com
Is it possible to animate an element along a path, Raphael has the .animateAlong() function which does that but I can't find anything similar with snap.svg

Matt Litherland

unread,
Dec 9, 2013, 12:32:21 PM12/9/13
to sna...@googlegroups.com
I'm looking for this also!

Matt Litherland

unread,
Dec 9, 2013, 12:43:06 PM12/9/13
to sna...@googlegroups.com
@James - I'm not fantastic at JS but i'm feeling it's along the .market lines here: http://snapsvg.io/docs/#Element.marker

Ian

unread,
Dec 9, 2013, 12:46:48 PM12/9/13
to sna...@googlegroups.com

Matt Litherland

unread,
Dec 10, 2013, 10:04:56 AM12/10/13
to sna...@googlegroups.com
@Ian had a look at this today and it's still a little over my head. Also not beign a seasoned JS developer i get easily confused when looking at Raphael and back at Snap but thanks for your help!

Ian

unread,
Dec 10, 2013, 10:53:09 AM12/10/13
to sna...@googlegroups.com
Np, so following Dmitrys post earlier about animating numbers, I wonder if we can use a similar approach ? For example, here's a quick fiddle I did http://jsfiddle.net/7EeJ2/1/

       var s = Snap("#svg1"), movePoint;

        var text = s.text(100,100,"Hi");
        var path = s.path( "M 100, 100 m -75, 0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0").attr({ 'fill': 'none', 'stroke': 'black' });

       // so lets find the path length, then we can find the coordinate of whatever steps we want to split by, and move our element to that coordinate.

        var pathLength = Snap.path.getTotalLength( path );     

        Snap.animate(0, pathLength, function( value ) {
                        movePoint = Snap.path.getPointAtLength( path, value );
                        text.attr({ x: movePoint.x, y: movePoint.y });
        }, 10000);

ian

Ian

unread,
Dec 10, 2013, 11:10:32 AM12/10/13
to sna...@googlegroups.com
In fact, maybe it could be broken down into a simple function like http://jsfiddle.net/7EeJ2/3/ so its easier to reuse if you don't know js so well. (There may be a better way already! Just if there are no other solutions).

function animateAlongPath( path, element, start, dur ) {
    var len = Snap.path.getTotalLength( path );
    Snap.animate( start, len, function( value ) {
            var movePoint = Snap.path.getPointAtLength( path, value );
            element.attr({ x: movePoint.x, y: movePoint.y });
    }, dur);
};

Ian

Matt Litherland

unread,
Dec 10, 2013, 12:17:02 PM12/10/13
to sna...@googlegroups.com
Thanks for your response Ian! I'm having a play in CodePen now and will let you know the outcome, I'm definitely more comfortable with functions as that's how i write most my Jquery :D

Matt Litherland

unread,
Dec 10, 2013, 12:29:32 PM12/10/13
to sna...@googlegroups.com

Ian

unread,
Dec 11, 2013, 4:11:51 AM12/11/13
to sna...@googlegroups.com
Not sure if you were posting that mid play, or as you were stuck..if you hadn't managed to get the circle animating along the path, you could try this fork, see if it helps. (may need to fiddle with speeds etc to get them to match up if thats what was wanted).


Ian

Matt Litherland

unread,
Dec 16, 2013, 10:59:14 AM12/16/13
to sna...@googlegroups.com
Hi Ian,

Thanks for doing that fork! Really got me going, I've gone on to this point now: http://codepen.io/mattsince87/pen/snqLy

Trying to work on animating a polyline or polygon along the path instead of a circle element. 
Only problem i'm having is that only circles use the cx and cy properties.

Any ideas? I'm really starting to have fun with SnapSVG now :)
Matt

Ian

unread,
Dec 16, 2013, 11:31:37 AM12/16/13
to sna...@googlegroups.com
So I guess for more complex fits all solution, you may want to change it a bit. Maybe you could put it in a group, and animate the transform to the group, then this can work for most stuff, I would imagine even a whole new svg element...

So... something like http://codepen.io/anon/pen/Bxabz

var triangleGroup = snapC.g( Triangle );
then in the animate call...
triangleGroup.transform( 't' + parseInt(movePoint.x - 20) + ',' + parseInt( movePoint.y - 40)); // (-20/40 are just offsets to test)

Its worth having a quick read up how transforms work if you aren't used to them

Ian

Matt Litherland

unread,
Dec 16, 2013, 11:39:01 AM12/16/13
to sna...@googlegroups.com
Ian,
You are.. a legend. I'll have a read up on them now! Do you use twitter on anything i can follow you on?
Matt

Dom

unread,
Dec 20, 2013, 3:35:55 PM12/20/13
to sna...@googlegroups.com
Hey guys,

These examples have helped me tremendously! I am getting stuck now on moving the actual object that's being moved along the path in a certain direction, though. For example, say you have an arrow moving along that squiggly path, similar to SVG C. That arrow would need to change angles in order to point in the correct direction at each turn. Does that make sense?

Is there a way I can do this?

Ian

unread,
Dec 21, 2013, 6:32:16 AM12/21/13
to sna...@googlegroups.com
I think that makes sense, do you mean like this ? http://codepen.io/anon/pen/kmwvh

If so, http://snapsvg.io/docs/#Element.getPointAtLength has 'alpha' which will help us with the angle.

Ian

Matt Litherland

unread,
Dec 23, 2013, 10:19:24 AM12/23/13
to sna...@googlegroups.com
getPointAtLength gets all the 'points' along a path, so you can use it to animate an object (our triangle) along the path and it will rotate like in example C as you see :)

Dom

unread,
Jan 3, 2014, 10:05:28 AM1/3/14
to sna...@googlegroups.com
Hey guys, sorry for the late reply. I see that you got the triangle to actually rotate along the path as it's moving, that's excellent! What is actually making that happen? The movePoint variable?

Ian

unread,
Jan 3, 2014, 4:18:52 PM1/3/14
to sna...@googlegroups.com
Its setting a rotation as part of the transform string to an angle which is in this case movePoint.alpha (alpha is the change in angle, created from getPointAtLength)

movePoint = myPathC.getPointAtLength( value ); 
triangleGroup.transform( 't' + parseInt(movePoint.x - 20) + ',' + parseInt( movePoint.y - 30 ) + 'r ' + parseInt(90 + movePoint.alpha) ); 

Dom

unread,
Jan 6, 2014, 11:01:45 AM1/6/14
to sna...@googlegroups.com
Yeah, that's excellent! The only problem I'm encountering is on the very last frame of the motion, the triangle rotates about 90 degrees and just stays there, ignoring the motion that was happening previously. Here is what my code looks like:

            path.attr({fill: 'none', "stroke-dasharray": len + " " + len, "stroke-dashoffset": len }).animate({"stroke-dashoffset": 10}, 2500,mina.easeinout);
            Snap.animate(0, len, function( value ) {
               var movePoint = path.getPointAtLength( value );
               tri.transform( 't' + parseInt(movePoint.x - 352, 10) + ',' + parseInt( movePoint.y - 87, 10 ) + 'r ' + parseInt(195 + movePoint.alpha, 10) );
               console.log(value);
            }, 2500,mina.easeinout);

Matt Litherland

unread,
Jan 6, 2014, 11:06:08 AM1/6/14
to sna...@googlegroups.com
can you upload a demo please http://codepen.com - New

Dom

unread,
Jan 6, 2014, 11:16:33 AM1/6/14
to sna...@googlegroups.com

Ian

unread,
Jan 6, 2014, 11:38:46 AM1/6/14
to sna...@googlegroups.com
Quick fix I guess would be just to animate to len-1, so http://codepen.io/anon/pen/jztxq

Ian

Dom

unread,
Jan 6, 2014, 11:40:48 AM1/6/14
to sna...@googlegroups.com
Hmm that seems a bit random, is it a but or something?

Dom

unread,
Jan 6, 2014, 11:41:15 AM1/6/14
to sna...@googlegroups.com
bug*

Ian

unread,
Jan 6, 2014, 12:17:04 PM1/6/14
to sna...@googlegroups.com
Heh, not sure! Think it would probably need Dmitry or some clever svg/maths person to answer correctly. I was just guessing that to figure a derivative you maybe need 2 different points, so maybe the very last point becomes an issue as it doesn't have 2 different points to calculate an angle from. I suspect I'm not correct here, but just showing my line of thinking that led me to try that first.

Matt Litherland

unread,
Jan 6, 2014, 3:53:36 PM1/6/14
to sna...@googlegroups.com
Dom, you need to draw your path and polygon to the exact size of your artboard:

like so:

This will mean the math's and integer values will actually make sense.

Dom

unread,
Jan 7, 2014, 2:09:55 PM1/7/14
to sna...@googlegroups.com
How exactly do you go about doing that? I had to convert my polygon / polyline to a path with this script here (http://stackoverflow.com/questions/10717190/convert-svg-polygon-to-path) in order to make the code you've written work in my situation. Obviously, I'm very very new to SVG.

Anyway, I assumed that that script would have done it correctly anyway since all it is doing it taking it from the original SVG file and converting the polygon / polyline to a path, keeping the math intact.

J David Eisenberg

unread,
Jan 7, 2014, 5:03:50 PM1/7/14
to sna...@googlegroups.com
Silly question, but wouldn't it be possible to script SVG's <animateMotion> element (http://www.w3.org/TR/SVG/animate.html#AnimateMotionElement)?

Ian

unread,
Jan 8, 2014, 4:27:40 AM1/8/14
to sna...@googlegroups.com
I suspect you could use most SVG elements scripted. I guess it depends if you want to stay away from that though. Is there a reason to though? I.e is there something you want to do with animateTransform that you can't with the above solution iyswim.

J David Eisenberg

unread,
Jan 8, 2014, 11:16:07 AM1/8/14
to sna...@googlegroups.com
My reasoning is as follows: the functionality that the original poster wants appears to exist already in the <animateMotion> element. Why go to the trouble of re-implementing that functionality in JavaScript? You're unlikely to improve on the speed or performance of the "built-in" SVG element. If the functionality is something that <animateMotion> can't do, then yes, definitely, use JavaScript.

Ian

unread,
Jan 8, 2014, 12:19:23 PM1/8/14
to sna...@googlegroups.com
I agree, if thats all you need, no need to reinvent the wheel. I think the difficulties often appear when needing to integrate with other bits.

Anthony Greco

unread,
Mar 11, 2014, 11:17:06 AM3/11/14
to sna...@googlegroups.com
First let me say thanks to everyone that contributed to this thread. Really saved me some time digging. :) I have an issue though where my element that's "attached" to the path starts to get an offset after a curve in the line. Here's a jsfiddle: http://jsfiddle.net/anthonygreco/ahuy9/

Does anything stand out to anyone as to what would be causing this? Thoughts even?

Thanks in advance!

Anthony Greco

unread,
Mar 12, 2014, 9:40:41 AM3/12/14
to sna...@googlegroups.com
Bump?

Anthony Greco

unread,
Mar 12, 2014, 10:23:53 AM3/12/14
to sna...@googlegroups.com
OK. So I've updated some things and realizing that my issue is simply that my shape that I'm attaching to the end of the line is an "off-center" element. Changing to a path that's a simple arrow shows it to be working great now, aside from the flipping of the arrow at the end which I'm also still trying to find a better solution than length-1, since the line will draw itself through the shape at the end -- though I imagine I could offset that too. Does anyone have any ideas on how I would go about getting a path "attached" that is't a symmetrical shape? Or rather, how to handle the offsets during the positioning of said shape?

Anthony Greco

unread,
Mar 12, 2014, 11:13:03 AM3/12/14
to sna...@googlegroups.com
Another update. Figure out how to get the orientation resolved.

var rotation = (notePoint.alpha !== 90)? 90 : 270;
noteHead
.attr({fill: params.color}).transform('t'+parseInt(notePoint.x-5, 10)+','+parseInt(notePoint.y-5, 10)+'r'+(notePoint.alpha-rotation));


Anthony Greco

unread,
Mar 12, 2014, 2:12:38 PM3/12/14
to sna...@googlegroups.com
Another update. Just thoughts... So I believe I've confirmed the issue is that the shape I'm using is not symmetrical (though I'm still not 100% on that... please, I see that people are still viewing this thread, someone... anyone, chime in and prove me wrong, give me ideas/thoughts, tell me to RTFM again :P) and therefore needs to be offset differently. Perhaps my issue could be solved by setting the shapes translate and rotate origins to be at the corner of the shape? Anyone know how I'd go about that?

Anthony Greco

unread,
Mar 12, 2014, 4:23:01 PM3/12/14
to sna...@googlegroups.com
Well, I guess this is just an extremely dead thread... Kinda discouraging seeing that I see several folks have viewed it since my initial update. IDK, maybe people are just looking at the first few and then abandoning... perhaps I'll try posting a new thread entirely later.

So I know my issue is with offsetting an element so that it's "attached" to the path properly. But I can't seem to figure out how to address this. I've updated my fiddle once again to more clearly show my issue. http://jsfiddle.net/anthonygreco/ahuy9/ The arrow should stay on the same side of the line but when the line curves it moves to the other side. Can anyone tell me why we're using an alpha property to drive rotation values for that matter? Seems weird... maybe I just need to dig deeper into the math that's going on... Still, not sure what other properties I can use as a reference as a "driving" property. Furthermore, I'm not 100% sure if the offsetting is coming from the translation or the rotation, but I'm suspecting it's only the translation. Again, if anyone has any ideas, thoughts, rants....

Ian

unread,
Mar 12, 2014, 8:00:08 PM3/12/14
to sna...@googlegroups.com
Heya,

I have been looking and having a play on a fiddle, but haven't had much time or come up with anything further than yourself. I thought the problem was maybe having an end point that was offset similar to yourself? So maybe if the icon 'point' was at the centre of path somehow, so that when its rotated its still accurate, but its quite confusing isn't it!               

I had also wondered if the final rotation in the transform needed to be around some relative translated point for a path that was offset, but I'm not sure that made sense, or maybe translate the path co-ordinates themselves!

Sorry, not a lot of help. I think its one of those problems where the solution will ping into someones mind at some point. Stackoverflow could be worth a try as well (maybe draw a bounding box around it also, that sometimes helps visualise whats happening), as there's some clever chaps there.

Ian

Ian

unread,
Mar 13, 2014, 8:15:39 AM3/13/14
to sna...@googlegroups.com
Had a bit more of a play, and this is where I got to. I think there must be an easier way which someone good at matrices and coords could sort, but it may help...

I've


        //feels clunky, so not sure this is a good solution, but the logic may help
        var noteBB = noteHead.getBBox();
        var myMatrix = new Snap.Matrix();
        myMatrix.e = ( noteBB.x - noteBB.width/2 );
        myMatrix.f = ( noteBB.y - noteBB.height/2 );
        noteHead.attr({ d: Snap.path.map( noteHead, myMatrix ) });

My thoughts were to get the bounding box of the complex path when we start. Then translate the path points so that its now centred around 0,0 to make it simpler later (I'm not convinced of my own logic there, but hey ho!). Note: I'm assuming all of this can be skipped if the path is centred initially when created (otherwise there need to be further complex offsets maybe).

Then later tweak with some adjustment, because the 'pointing' of the shape is also offset further

noteHead.transform('t'+parseInt(notePoint.x, 10)+','+parseInt(notePoint.y, 10)+'r'+(notePoint.alpha-rotation)+'t-3.5,-3.5');

Hope some of it helps. Its also worth noting in firefox, it seems to animate in chunks, and doesn't work in Opera, but this is the same with the original as well. Its worth bearing in mind, as it may be there needs to be a tweak with the general solution as well (not sure if thats a snap/jquery/svg issue, but I would look at that separately and isolate).






Anthony Greco

unread,
Mar 13, 2014, 9:23:37 AM3/13/14
to sna...@googlegroups.com
Hi Ian,

Thanks so much for taking a look and fiddling around. I have been plotting points to make more sense of some of these values I'm less familiar with as well as better understanding the Snap Matrix. Looks like I was at least looking in the right direction. Per your comment, "My thoughts were to get the bounding box of the complex path when we start. Then translate the path points so that its now centred around 0,0 to make it simpler later", can you explain what you mean a bit more in regard to "now centered around 0,0". Are you saying that you're effectively SETTING the cx/cy value of to the bottom left corner of the element? As I mentioned before I felt like some of my issue was my origin of my element. I also though that my guide path using absolute and relative positioning in the path may be causing issues.

You go on to say "I'm assuming all of this can be skipped if the path is centred initially when created". I use Illustrator to draw and then just grab the path data. Wish I could find a way to tell Illustrator to only use absolute or only relative, though in my debugging it didn't seem to me to have any relevance. Do you know how exactly one creates it so the path is centered initially? Before my post here, my original svg had some extra artboard space around it and therefore its path data was pretty far from the 0,0 (bottom left) mark, but since then I removed all of the extra space. That obviously showed a great difference in the "offset" issue I'm presented with as it got much closer to my pointAtLength. Are you saying maybe my original still isn't drawn as best as it could be? Is there any pointers you may have for making it "0,0" originally in AI? I come from a 3D background and used several types of modeling software which all have a method called something to the nature of "freeze transformations" which zeros out the local point space values and so long as your model is at 0, 0 in global space you know things are in an exact position. Do you know if there's any similar command in AI?

I'll most likely hit up SO eventually just to see if there's any better way to go about this. Either way, thanks again for giving this a whirl! Really appreciate it.

Ian

unread,
Mar 13, 2014, 10:57:59 AM3/13/14
to sna...@googlegroups.com
Firstly, I was just thinking that previous code could be shortened a bit to the following, http://jsfiddle.net/hyZnT/8/ 

        var noteBB = noteHead.getBBox();
        var myMatrix = new Snap.Matrix().translate( noteBB.x - noteBB.width/2, noteBB.y - noteBB.height/2);;
        noteHead.attr({ d: Snap.path.map( noteHead, myMatrix ) });

I'm hesitant to give too much answer when I'm not sure what I'm talking about, so take with a pinch of salt!

I was thinking that typically with Snap/Raphael, I guess if you don't specify a rotation centre point, it will rotate around its own centre (whereas svg typically rotates around 0,0 I think unless specified). Question is, what is that the centre of ? (if you have a lobsided shape for example), so I'm guessing that may be part of the problem. If you're rotating, what are you rotating around ? Maybe I'm wondering whats the 'anchor point' if thats the right terminology. It may be the centre, or it could be some arbitrary bit of the path that you have to figure out ( or it could be outside the path bounding box if you always want to point to be pointing at some object ) ?

Rather than thinking about centering points, maybe it makes more sense to think about an anchoring point (as they may not be the same thing) ? Maybe I've confused the issue talking about centering rather than the point we want to rotate.

Not sure about the 3d stuff, not come across that before. I ultimately think it shouldn't matter where the object was created positionally with any solution. This must happen a lot, I think whatever there will need to be transformations or setting of a specific rotation point.

I still think there's a simpler solution, but I also think it helps the mind if the rotation/anchor point is understood, and how it will coincide with the alpha (this is all the bit I'm finding difficult :)). 





Anthony Greco

unread,
Mar 13, 2014, 1:25:36 PM3/13/14
to sna...@googlegroups.com
Thanks again Ian. I just learned a whole lot about Snap matrices. :D (though now my head hurts too...lol) 

There's still some edge case issues I need to address. The rotation being off at the last pixel of the path mainly... the conditional 90 vs 270 hack i had was simply that, a hack; I've updated to keep track of the previous rotation and the previous step from the rotation before to its current and I used that for the rotation transform string. I still see an issue if the animation happens very fast since step would be way off if the last "tick" was 30px back or so. May have to run that animation transparently and determine the step between the second to last and last "tick" of the animation and store that for use later. IDK, still mulling it over. Either way, I wanted to re-share my progress for any others that may could learn something from all of this.

Veck Hsiao

unread,
Jan 19, 2016, 11:11:07 PM1/19/16
to Snapsvg
Hi, guys! I just jumped into the world of SVG, and I tried to use Snap.svg to animate an element that along a path. So I found this post and another solution http://michaeltempest.com/the-missing-snap-svg-function .

I want to ask for some discussion whether this function should be a part of Snap.svg library? Or what's the reason this function is not available in Snap.svg. (Simply call element.animateAlongPath(duration) or element.animateAlong(path, duration), ... and so on.)

This thread seems to be hibernated. Hope someone could give me some feedback. :)

Ian

unread,
Jan 20, 2016, 2:48:40 AM1/20/16
to Snapsvg
I would just include it as a plugin. I do think its a useful one, but I suppose I look at Snap as more of a tool rather than a solution thing.

That example is a nice one, but it will probably have issues if the image being moved wasn't designed with the correct centre, then you need to tweak it, then you need more code etc.

I certainly think it wouldn't be a problem being there, but what you don't want is code in there that you can't bend to make it do what you need.

Veck Hsiao

unread,
Jan 22, 2016, 1:49:48 AM1/22/16
to Snapsvg
Yap, I found that solution is not reusable if I don't add more code. I think making a object moving along path is still useful for my project.
Reply all
Reply to author
Forward
0 new messages