Skip to content

Instantly share code, notes, and snippets.

@eswak
Created February 19, 2015 21:17
Show Gist options
  • Save eswak/35409a9f2ef30f35025d to your computer and use it in GitHub Desktop.
Save eswak/35409a9f2ef30f35025d to your computer and use it in GitHub Desktop.
Progressively draw SVG to create a hand drawn effect
(function closure () {
// progressively draw each <svg> without .no-draw class
Array.prototype.forEach.call(document.querySelectorAll('svg:not(.no-draw)'), function(svg) {
// animation duration & delay (default values overriden by data attributes)
var animationTimeInSeconds = Number(svg.getAttribute('data-draw-time')) || 2;
var animationStartDelay = Number(svg.getAttribute('data-draw-start-delay'))*1000 || 0;
// init, hide all svgs
var totalFrames = animationTimeInSeconds * 60;
svg.style.display = 'none';
// start to draw each <svg> after "data-draw-start-delay" (attribute) time (in seconds)
setTimeout(function() {
svg.style.display = 'inline-block';
svg.id = svg.id || Math.random().toString(36).substring(2);
// store paths in an array
var paths = Array.prototype.slice.call(document.querySelectorAll('#' + svg.id + ' path'));
// for each path
paths.forEach(function(path, i) {
var handle = 0;
var l = path.getTotalLength();
path.style.strokeDasharray = l + ' ' + l;
path.style.strokeDashoffset = l;
// start to draw them after a delay
// ex: if <svg> is composed of 2 paths, and draws in 1s,
// path 1 will start to draw immediatly and will be drawn in 500ms,
// while path 2 will be drawn between 500ms and 1s
setTimeout(function() {
drawPath(path, l, 0, totalFrames/paths.length, handle, function() {
// add .drawn class to every svg <path> that have been completely drawn
path.classList.add('drawn');
if (i === paths.length -1) {
// add .all-paths-drawn class to <svg> dom element when all
// its paths have been drawn
svg.classList.add('all-paths-drawn');
}
});
}, i*(animationTimeInSeconds/paths.length)*1000);
});
}, animationStartDelay);
});
function drawPath(path, pathLength, currentFrame, totalFrames, handle, drawn) {
var progress = currentFrame/totalFrames;
if (progress > 1) {
window.clearTimeout(handle);
path.style.strokeDashoffset = 0;
drawn && drawn();
} else {
currentFrame++;
path.style.strokeDashoffset = Math.floor(pathLength * (1 - progress));
handle = window.setTimeout(function() {
drawPath(path, pathLength, currentFrame, totalFrames, handle, drawn);
}, 1000/60);
}
}
})();
@nbje
Copy link

nbje commented Jul 16, 2018

I found a solution to the "not a valid selector" problem. The thing is, selectors cannot start with a digit. But as it is randomly generated, there is a chance that it will. So you can just add a prefix to avoid this. Like so:
svg.id = svg.id || "something_"+Math.random().toString(36).substring(2);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment