One way is through a nifty plugin (that comes with AE) called Create Nulls From Paths. Located in the Menu bar -> Window -> Create Nulls From Paths. There are currently 3 features available. The first one, as its name suggests, is to create a Null point at each anchor point of your chosen path. The path points are then parented to their respective Null's position. The second feature allows you to choose the inverse: where the Null's follow the path points. Finally, there is an option called Trace Path that is what we are interested in.
To work, you simply select your path, then choose Trace Path. This will create a Null that has its position constrained to the path you chose. It features a handy slider named Progress that you can access in the effects panel of the Null layer. Progress controls the flow of the Null along your path where 0% is the beginning, and 100% is the end of your path. Pretty straightforward! You also have a Loop checkbox option that allows the progress animation to loop the set keyframes. This works by toggling a loopOut('cycle')
expression. You can see this if you toggle the expression panel of the progress control in the timeline.
//Expression applied to Null's "Progress" Slider
if(thisProperty.propertyGroup(1)("Pseudo/ADBE Trace Path-0002") == true && thisProperty.numKeys > 1){
thisProperty.loopOut("cycle");
} else {
value
}
All this expression is doing is verifying whether the Loop checkbox is checked == true
**and that there are at least 2 keyframes set in the timeline numKeys > 1
. If both are true
then the loop is activated.
The remaining two properties that are controlled by expressions are position and rotation.
//Null Position Expression
var pathLayer = thisComp.layer("Path");
var progress = thisLayer.effect("Pseudo/ADBE Trace Path")("Pseudo/ADBE Trace Path-0001")/100;
var pathToTrace = pathLayer("ADBE Root Vectors Group")(1)("ADBE Vector Shape");
pathLayer.toComp(pathToTrace.pointOnPath(progress));
The position of the Null, relative to the path, is calculated using the pointOnPath()
method; that returns the position of a point on the path based on a range of 0
to 1
, where 0
is the position of the curve point at the beginning of the path, and 1
is the position of the curve point at the end of the path. To track progress of the flowing object, a percent scale is used for convenience, so the value passed as an argument to the pointOnPath()
method must then be divided by 100
- to conform to the accepted range of 0
to 1
.
//Null Rotation Expression
var pathToTrace = thisComp.layer("Path")("ADBE Root Vectors Group")(1)("ADBE Vector Shape");
var progress = thisLayer.effect("Pseudo/ADBE Trace Path")("Pseudo/ADBE Trace Path-0001")/100;
var pathTan = pathToTrace.tangentOnPath(progress);
radiansToDegrees(Math.atan2(pathTan[1],pathTan[0]));
The rotation property of the Null, at the specified progress time, is calculated by finding the inverse tangent (arctangent) of the path point using Math.atan2()
, and then converting the result to degrees using the radiansToDegrees()
function. In the next section we'll build a custom example to better understand how the math works and have a more customizable setup.
In a similar way to the Trace Path, we can setup objects to flow along the path as the path draws itself. Let's build an example with animated arrows. We'll be using a set of expressions that give us direct control over path points.
What we'll be creating...
0,0
. Rename this layer to: "Path".g
key) while having the new Shape Layer selected. Once you are done, a group will be created in your shape layer contents that contains your path, a fill, stroke, and a transform. To simplify our example, drag your path and stroke out of the group and rename them to "Path", ****and "Stroke" respectively. Set your stroke width to a reasonable size for better visibility.