In modern HTML you can embed SVGs directly into your DOM. This allows for pretty visuals, using the powers of both css and svg. One use that I have had on multiple occasions is path animations.
Here is a mockup of what it looked like:
Doing something like this is actually quite easy. The basic idea is to use a very long dashed stroke that will be
animated. In practice this means setting stroke-dasharray
to 100%
and animating stroke-dashoffset
from 100%
to 0%
or the other way around.
This can be done in multiple ways, I will show two that I happened to have used:
CSS Animation
CSS animations are powerful and perfect for this kind of animation. To use them, we need to prepare our SVG a little. For the example above I created the following file in Inkscape:
Next, we need a little CSS inside the SVG file. For that, add the following styles into the <defs></defs>
of your SVG:
<style>
.hiddenPath {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.animatedPath {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 1s linear forwards;
}
#DP1 {
transform-origin: 102px 114px;
}
#DP2 {
transform-origin: 473px 145px;
}
#DP3 {
transform-origin: 345px 287px;
}
#DP4 {
transform-origin: 132px 322px;
}
@keyframes dash {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
.hiddenInfoBubble {
transform: scale(0);
}
.animatedInfoBubble {
transform: scale(1);
transition: transform 0.35s ease-in-out;
}
</style>
To make use of these styles set the class of all bubbles to hiddenInfoBubble
and the class of all paths to hiddenPath
. Also set the IDs of all bubbles to the values
from the stylesheet. Of course, the transform-origin
s will differ for you.
Controlling these animations is done using JavaScript. The code below is what is used in the example above and should give you a rough idea what needs to be done.
var state = 0;
function next_action()
{
var svg = document.getElementById("svg-container").contentDocument;
switch(state)
{
case 0:
svg.getElementById("DP1").setAttribute("class", "animatedInfoBubble");
state++;
break;
case 1:
svg.getElementById("DP1-DP2").setAttribute("class", "animatedPath");
setTimeout(function(){
svg.getElementById("DP2").setAttribute("class", "animatedInfoBubble");
}, 350);
state++;
break;
case 2:
svg.getElementById("DP2-DP3").setAttribute("class", "animatedPath");
setTimeout(function(){
svg.getElementById("DP3").setAttribute("class", "animatedInfoBubble");
}, 240);
state++;
break;
case 3:
svg.getElementById("DP3-DP4").setAttribute("class", "animatedPath");
setTimeout(function(){
svg.getElementById("DP4").setAttribute("class", "animatedInfoBubble");
}, 240);
state++;
break;
case 4:
svg.getElementById("DP1-DP2").setAttribute("class", "hiddenPath");
svg.getElementById("DP2-DP3").setAttribute("class", "hiddenPath");
svg.getElementById("DP3-DP4").setAttribute("class", "hiddenPath");
svg.getElementById("DP1").setAttribute("class", "hiddenInfoBubble");
svg.getElementById("DP2").setAttribute("class", "hiddenInfoBubble");
svg.getElementById("DP3").setAttribute("class", "hiddenInfoBubble");
svg.getElementById("DP4").setAttribute("class", "hiddenInfoBubble");
state = 0;
break;
}
}
A few points to note about the code:
- The following line is used to get access to the child DOM of the SVG:
var svg = document.getElementById("svg-container").contentDocument;
- The timeouts are the time the animation needs until the path has reached its destination. Because the animation is pixel based, this time will be different for each path segment. By using pixels, the paths will always move with the same speed, but if you prefer all paths taking the same time you can use percentage based animations.
Another article about css/svg animations can be found on tympanus.net.
JavaScript
In some cases, CSS animations are unfortunately not enough. One example is, if you want to move an object along with the path. For this, some JavaScript is required:
var path = ...;
var obj = ...;
var path_length = path.getTotalLength();
function frame(t) {
// Animate path
path.style = "stroke-dashoffset: -" + (t * path_length);
// Animate object
var pos = path.getPointAtLength(t * g.length);
obj.x = pos.x;
obj.y = pos.y;
}
This style of animation is used for the wires at the top ot this page. A demo can be found here.