Welcome to our new tutorial. Today I’ll show you how to animate an SVG element along a predefined path using snapsvg javascript library. I've stumbled upon quite a few examples but none of them have a proper description on how to do this, so I've decided to explain the animation process, and show you a really nice and clean example.
This download contains the .html file and the .ai graphics.
SVG and SnapSVG Library Introduction
SVG stands for Scalable Vector Graphics. SVG defines vector-based graphics in XML format and represents a vector image format for two-dimensional graphics with support for interactivity and animation. Modern web browsers can display SVG just as any other types of media, such as images or html videos.
As a vector graphics format, SVG is mostly used for vector type diagrams like:
- Two-dimensional graphs in an X,Y coordinate system.
- Line charts, pie charts etc.
- Scalable icons and logos for web, tablet and mobile apps and web apps.
- Architecture and design diagrams
SnapSVG is a javascript based library that provides you the tools to create interactive vector graphics. Basically, SnapSVG is for SVG what jQuery is for html.
Other SVG libraries that can help you achieve the same results are: raphaeljs, bonsaijs, velocityjs, etc...
All things said, let's get started!
Importing the scene elements
I will keep it short with this since our goal is to explain how you can animate SVG elements along custom paths. The graphic is vectorial,created in illustrator. You can export SVG documents directly from illustrator, using the save as option.
Keep in mind that our spaceship was exported from a separate and trimmed document.
Animating along path
After importing all our scene elements, we can proceed further. And this is where it gets even more interesting.
First of all, we need to draw the path that we will be animating along. Here’s the code:
flight_path = map.path('M339.233,312.53c-37.779,16.943-119.567-21.598-134.165-71.924c-19.086-65.802,19.072-124.856,64.665-145.753s157.388-22.525,219.128,74.23s-20.242,229.959-114.73,240.688c-88.678,10.069-230.255-62.044-230.25-163.305').attr({ 'fill': 'none', 'stroke': 'none'});
In order to animate, we need to know a few things about our path. How long it is? We can find that out by using Snap.path.getTotalLength(path).
flight_path_length = Snap.path.getTotalLength(flight_path);
Now we can continue with our animation. SnapSVG provides us with an animate method: Snap.animate(from, to, setter, duration, [easing], [callback])
- from is the start point, that will be 0, since we want to start the animation from the start point of our path
- to is the end point, that will be equal to our path length variable
- setter is a function that will be called on every step of the animation. Setter function passes an integer parameter called step. We will use this parameter to calculate and animate our element position.
- callback is a function that will launch after the animation ends, and we will use the callback function to further animate our spaceship
IMPORTANT: Snap.animate() is a generic animation function that animates a number into another. It doesn't animate elements.
Since we know the path length and what Snap.animate() does, we can proceed with writing the animation’s function, and it will look something like this:
Snap.animate(0, flight_path_length, function(step){
//position code goes here
}, 5000, function(){
//callback
});
Now we will work inside the setter function. Notice that the setter function accepts a parameter called step. We will use step parameter to get a specific point on our path by calling Snap.path.getPointAtLength(flight_path, step), and translate our spaceship to that point. Since setter, is an iterator, the step parameter will have different values while animating.
The final function will look something like this:
Snap.animate(0, flight_path_length, function( step ) {
moveToPoint = Snap.path.getPointAtLength( flight_path, step );
x = moveToPoint.x - (spaceshipbbox.width/2);
y = moveToPoint.y - (spaceshipbbox.height/2);
spaceship.transform('translate(' + x + ',' + y + ') rotate('+ (moveToPoint.alpha - 90)+', '+spaceshipbbox.cx+', '+spaceshipbbox.cy+')');
},5000, mina.easeout ,function(){
ship_move_up();
});
Other animations and final code
Notice that in our example we also have two other small animations.
The thrusters of our spaceship are engaged in an endless up and down motion, and the spaceship itself is moving up and down after we finish the animation on our custom SVG path. Those animations are realized by splitting the motion in two functions: one for the up motion, one for the down motion. In both of them, we are animating the transform(x,y) property.
The final code:
var paper, map, spaceship, thruster, moon, flight_path, flight_path_length, last_point;
window.onload = function () {
paper = map;
map = Snap('#svg-doc');
spaceship = map.select('#spaceship');
spaceshipbbox = spaceship.getBBox();
thruster = map.select('#thruster');
moon = map.select('#moon');
flight_path = map.path('M339.233,312.53c-37.779,16.943-119.567-21.598-134.165-71.924c-19.086-65.802,19.072-124.856,64.665-145.753s157.388-22.525,219.128,74.23s-20.242,229.959-114.73,240.688 c-88.678,10.069-230.255-62.044-230.25-163.305').attr({ 'fill': 'none', 'stroke': 'none'});
flight_path_length = Snap.path.getTotalLength(flight_path);
last_point = flight_path.getPointAtLength(flight_path_length);
// starting the thruster animation
animate_thruster_down();
Snap.animate(0, flight_path_length, function( step ) {
moveToPoint = Snap.path.getPointAtLength( flight_path, step );
x = moveToPoint.x - (spaceshipbbox.width/2);
y = moveToPoint.y - (spaceshipbbox.height/2);
spaceship.transform('translate(' + x + ',' + y + ') rotate('+ (moveToPoint.alpha - 90)+', '+spaceshipbbox.cx+', '+spaceshipbbox.cy+')');
},5000, mina.easeout ,function(){
ship_move_up();
});
};
function ship_move_up(){
spaceship.animate({'transform': 'translate(' + (last_point.x - (spaceshipbbox.width/2)) + ',' + (last_point.y - (spaceshipbbox.height / 2) - 20) + ')'},1300, function(){
ship_move_down();
});
}
function ship_move_down(){
spaceship.animate({'transform': 'translate(' + (last_point.x - (spaceshipbbox.width/2)) + ',' + (last_point.y - (spaceshipbbox.height / 2)) + ')'},1100, function(){
ship_move_up();
});
}
function animate_thruster_up(){
thruster.animate({'transform': 'translate(0,-5)'},100, function(){
animate_thruster_down();
});
}
function animate_thruster_down(){
thruster.animate({'transform': 'translate(0,0)'},100, function(){
animate_thruster_up();
});
}
Final thoughts
Keep in mind that you can achieve the same results with other javascript libraries.
Hope you liked this tutorial and find it useful. And don’t hesitate to download the source and try out new projects with it. I will keep creating some other fun stuff. Until then, enjoy!
If you have any questions or suggestions you can post them in the comment section below. I will reply and find answers as often as I can.
Comments