Jump to content
Search Community

Animating SVG paths within a timeline

MOH test
Moderator Tag

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

Hey Guys,

 

I am still new to GSAP animation, and i need some help. I am implementing a timeline using greesock js which handles a presentation of different SVG images mainly made up of simple lines, circles and paths. What is want to achieve is the animation of these SVGs while to timeline is being moved. As far as the timeline implementation goes, all is well. But when it comes to animating the svg the way i want i am reaching a road block. I can animate the scaling, width and opacity with no problems. The code is as such:

 

 

TimeLine.from($('#Shape2 polygon'), 2, {
    scale: 0, onStart: function () {                                      
//Dont mind the variables
        mainTimeline.timeScale(NormalTimeScale);
    }
}, timeShift)
 
 
What i want to achieve is the drawing effect of the lines circles etc... As the user moved the timeline scroll bar, the vector graphics should be drawn and of course the reverse effect should be obvious. I am mainly trying to achieve this with stroke-dashoffset and stroke-dasharray but i cannot alter these properties even after i included the AttrPlugin. This is what i am trying:
 
Timeline.from($('#Shape2 line'), 1, { atrr: { 'stroke-dasharray': '20px'  }}, timeShift + 1)
 
Please note that these are just example blocks of code.
 
Can you guys help me with this please?
 
Link to comment
Share on other sites

Hi and welcome to the forums.

 

I have no idea how you can achieve that but looking around I found this in stackoverflow:

 

http://stackoverflow.com/questions/14275249/how-can-i-animate-a-progressive-drawing-of-svg-path/14282391#14282391

 

The first two answers are the key to this stuff and the beauty of this is that their using a very simple timer mechanism (setInterval), so it'll be super easy to replace that timer with an onUpdate call on a tween/timeline, so while you animate the elements the onUpdate callback of that tween will do the drawing. I did something similar to draw a circle using canvas, just update the circle's angle and redraw the entire canvas on each update.

 

On how specifically the drawing works you'll have to look into that, but if you look at this example's code:

 

http://phrogz.net/svg/progressively-drawing-svg-path-via-dasharray.html

 

There are two things that caught my attention, the amount of code is ridiculously small and the magic happens in this function:

function increaseLength(){
	var pathLength = orig.getTotalLength();
	length += distancePerPoint;
	orig.style.strokeDasharray = [length,pathLength].join(' ');
	if (length >= pathLength) clearInterval(timer);
}

Since my knowledge in SVG is even worst than my knowledge in Canvas I can't help you more than this, but it seems like a good starting point for what you're after.

 

Also the engine has a plugin for RaphaelJS so you should take a look at that and the possibilities Raphael can give you in this matter.

 

Also they use canvas to draw the path on top of the SVG and the same timer mechanism is used so this could be replaced in the same way using GSAP.

 

I hope this can help you getting on your way and perhaps another user with more experience in SVG and Canvas could lend a hand.

 

Best,

Rodrigo.

  • Like 3
Link to comment
Share on other sites

AMAZING research Rodrigo! I certainly had no idea that technique was even possible. 

 

I couldn't resist borrowing from the Stackoverflow demo you linked to.

Check out this pen: http://codepen.io/GreenSock/pen/zLiux

 

Crazy.

 

Moh,

 

At this moment I don't know enough about the stroke-dasharray attribute but from some quick research its value seems to be not a single value like "20px" but an array of values.

 

I'm thinking it may require a custom plugin, and certainly more looking into. If one of our team finds more info we will be sure to share it.

  • Like 5
Link to comment
Share on other sites

Mhhh I see the demo got "upgraded" a tiny bit.... ;)

 

Excellent job Carl!!!

 

Yep the technique is new to me too, and the beauty of this is that, as the sample shows, the only thing you have to worry now is to get the path coordinates correctly and the engine does the rest for you. Is just amazing how little JS code is needed for something as cool as this.

 

Happy tweening!!

  • Like 2
Link to comment
Share on other sites

Now I'm trying to follow the codepen drawing that Carl made, and this is my codepen where I'm testing it;

 

See the Pen CDHoB by anon (@anon) on CodePen

 

The thing is, that the only the last javascript code is getting executed.

 

Sorry if this is something really basic, but I'm new to javascript, let alone tweenmax.

 

Thanks!

Link to comment
Share on other sites

Yeah the problem is that you are re-using the same object, tween, and callback names multiple times.

 

For instance you shouldn't have 2 functions called drawLine(), 2 objects called obj or 2 tweens named t.

 

There are definitely ways to make the code more flexible by passing parameters into functions and such, but for now, simply renaming everything obj1, obj2, drawLine1(), drawLine2() etc will work as shown here:

 

http://codepen.io/GreenSock/pen/Amjgd

  • Like 1
Link to comment
Share on other sites

Hey Guys,

 

Carl your project on codepen is excellent. I have already done something like that before, using the exact same methods. Manipulating the stroke-dasharray and stroke-offset as well. I got the drawing animation working for me. 

 

When i was using the jquery UI dragger/Slider all is well. But i decided to replace it with greensock's Draggable in order to get the slick throwing and snapping effects.

 

Currently I am stuck on updating the draggable position when the timeline is autoplaying.

 

In Jquery UI dragger I was using something like your code:

 

function updateSlider() {
  $("#slider").slider("value", t.progress()* 100);
}  

Can you show me how to replace this code with the on to update the 'x' of the greensock dragger? I was trying something like this:

theDragger[0].x = mainTimeline.totalProgress() * $('#theCont').width();

But no luck. Please help me. Thanks

Link to comment
Share on other sites

Hi,
 
The progress method works as a setter by passing the progress value for the particular instance, which has to be a number between 0 and 1, like this:

var tn = TweenLite.to(elem, time, {vars, paused:true});
tn.progress(0.5);//the playhead will be at the tween's mid-point

The update method you're mentioning works specifically with the Draggable instance and has no correlation with updating a tween, in this case at least. In order to modify and update a tween's progress you should use the onDrag callback, which works in the exact same way as the onUpdate method for any tween instance. For example every time you drag a draggable's target element, that callback is triggered, like that you can link that function to a tween's progress:

var tn = TweenLite.to(element, time, {vars}),
    progressNumber;

Draggable.create(draggableTarget,
{
  type:'x',
  bounds:draggableBounds,
  edgeResistance:1,
  onDrag:function()
  {
    progressNumber = number//here you perform the calculations to set that number
    tn.progress(progressNumber);//here you update the tween's progress on every drag event
  }
});

I set up a codepen illustrating this code:

See the Pen Batoc by rhernando (@rhernando) on CodePen

 

Rodrigo.

  • Like 2
Link to comment
Share on other sites

Thank you for the answer Rodrigo,

 

Maybe i was not clear enough. I do not have a problem with updating the timeline or tweens when dragging the draggable. I am using the progress() and totalProgress() as well.

 

What i want is the opposite. The timeLineMax instance has the pause: false attribute which means that when the page is loaded the tweens start automatically without the draggable. How can I update the draggable.x in order for it to be in sync with the tweens "WHILE AUTOPLAYING". 

 

My code starts with autoplaying the tweens, and when the user touches the draggable the autoplay is stopped and then the tween is affected by dragging the draggable.

 

Take a look: 

 

var mainTimeline = new TimelineMax({ onUpdate: updateSlider });


var theDragger = Draggable.create("#Slider1", {
    type: "x", bounds: "#theCont", edgeResistance: 1, throwProps: true, 
    onDrag: function () {
        mainTimeline.pause();
        var theProgress = (theDragger[0].x / $('#theCont').width());
        //console.log(theProgress);
        mainTimeline.totalProgress(theProgress);
    },
    onThrowUpdate: function () {
        var theProgress = (theDragger[0].x / $('#theCont').width());
        mainTimeline.totalProgress(theProgress);
    }
});




function updateSlider() {
    theDragger[0].update(true);
}

In the updateSlider function i want to edit the dragger position to stay in sync with the autoplaying tween set.

 

I hop this clears the confusion.

 

Thank you

Link to comment
Share on other sites

Hi guys,

 

Thank you so much for the information you share on this forum. I often have a look to see what issue people are having, to not only find fixes, but also as a way to find some inspiring code examples.

 

A few weeks ago I was also looking for a way to draw lines using GSAP and then went down the SVG route using Lazy Line Painter. http://lazylinepainter.info/

 

I can't wait to try out the above examples so that I can have more control over the lines.

 

Thank you very much for sharing :)

Link to comment
Share on other sites

Hi Barry,

 

Interesting plugin, specially since it helps with the code to draw the paths. Would be very nice to combine that with the technique in the codepen created by Carl, it'll be definitely a step forward in terms of how much time anyone will spend in getting the drawing correct.

 

Happy tweening!!

Link to comment
Share on other sites

  • 2 weeks later...

Hello GSAP! I'm trying to accomplish this same thing via Raphael. I can progressively draw a basic path with Raphael but I'm having issue trying to incorporate TweenLite/Max. Normally I'd go straight to StackOverflow for this but there seems there may already be a focused community right here! :) I've used most of the examples in this post as reference so I won't go on about what I'm trying to accomplish etc. The jsfiddle here should be pretty straight forward. I'm hoping I'm just missing something entirely silly... I've been looking at soooo many different js canvas/svg drawing libraries in the last 5 days my head is spinning so maybe my head is just still stuck in another framework. Any thoughts on what I'm not doing right here?

Link to comment
Share on other sites

Thanks you Carl for providing the GSAP way! This actually brought a few things into perspective for me. A couple things though. First, I'm not sure the easing is being used. I forked your fiddle and added the EasePack plugin (since I realized it was missing to begin with) but that didn't seem to help. New fiddle here. Second, I'm also currently looking at a way to draw a path without using the clear() method on the paper with the goal being that I'd be able to draw one shape via a path, then convert that into a standard shape after the animation completes (which I'm not sure how I'd address just yet, but figure that's a common task in Raphael), then "chain" the next path animation, continuing until all animations have been drawn to the screen and converted to shapes that could then be scaled on window resize. Here's a fiddle of where I am with that if you feel like another challenge. :P My main question though is in regard to the easing, as I understand the other aspects may be out of the scope of what you guys want to support via the forum. Thanks again to you and all the guys here at Greensock!

Link to comment
Share on other sites

Hi Anthony,

 

Actually Carl included TweenMax.min.js which includes, among others, the CSS Plugin, Ease Pack, and Bezier Plugin, so that's why it made no difference when you included the Ease Pack.

 

In terms of avoiding the clear method, what you could do is create different papers and animate each shape in a separate canvas, that also will help you to chain the animations, just create a master timeline and nest child timelines that could handle each drawing and some other animations (if they're required).

 

Best,

Rodrigo.

Link to comment
Share on other sites

Thanks for the reply rhernando! Duh, totally forgot TweenMax has everything. :P Still not sure why the easing doesn't seem to work in the first fiddle in my previous post though. Also, I have considered using multiple canvases, but foresee it becoming a bit messy. Though it's still my fallback option, I already have a method in the second fiddle in my previous post to draw without the clear method, just not sure how that'll work when using TweenMax for the animation yet as the previous native vs GSAP fiddle Carl helped out with.

Link to comment
Share on other sites

Looks like someone fiddled with my fiddle. Turns out simply adding 

shape.length = 0;

 resolves the easing issue. New fiddle here.

 

EDIT:

 

Didn't notice before but whoever fiddled also changed one other aspect. The calculation of the offset in the drawLine method doesn't use the tween.progress(). Changing:

offset = obj.pathLength * tween.progress();

to:

offset = pathLength * (shape.length / pathLength);

seems to work. Not quite sure why the progress method doesn't work though.

  • Like 1
Link to comment
Share on other sites

Ok, it took me a while but I've hacked away at this to find a way for the progression to be handled without a clear method having to be called on the paper, so that it'd be possible to draw multiple paths progressively at the same time. Once again though, I can't seem to find out how to accomplish the same thing via GSAP. Here's a fiddle showing how I'm handling the progression without the clear, a simple test theory showing that I feel this could be a possible solution, and my attempt via GSAP. Rodrigo... pick up the bat phone! lol :P

Link to comment
Share on other sites

Hi Anthony,

 

I'm the one that fiddled your fiddle to get the Bounce ease to work. Could have sworn I forked or updated it and even posted a response here. Must have been late at night.

 

Using the progress() to determine the offset didn't work because progress() is just a value between 0 and 1 that doesn't reflect the how the eases are impacting the values being tweened.  

 

To tell you the truth, getting all that to work was a bit of a stab in the dark. I'm not really following everything going on in Raphael, don't know much about their API,  lots of trial and error. 

  • Like 1
Link to comment
Share on other sites

Totally understandable. I'm also in the process of moving to Snap.svg which is a fork from the creator of Raphael that basically drops the VML rendering so IE 6,7, & 8 support is lost (:D yay) in favor of gaining more svg capabilities across modern browsers. Either way, thanks for fiddling, it did give me a bit more insight as to other potential approaches.

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