How to Animate a Progressive Drawing of Svg Path

How can I animate a progressive drawing of svg path?

There are three techniques listed in this answer:


There is an all-SVG solution that involves progressively modifying the stroke-dasharray for the shape to draw a longer and longer 'dash' followed by an enormous gap.

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

Relevant code:

var distancePerPoint = 1;
var drawFPS = 60;

var orig = document.querySelector('path'), length, timer;
orig.addEventListener('mouseover',startDrawingPath,false);
orig.addEventListener('mouseout', stopDrawingPath, false);

function startDrawingPath(){
length = 0;
orig.style.stroke = '#f60';
timer = setInterval(increaseLength,1000/drawFPS);
}

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

function stopDrawingPath(){
clearInterval(timer);
orig.style.stroke = '';
orig.style.strokeDasharray = '';
}

Alternatively, you can still use all SVG and choose to build the SVG path one command at a time:

Demo: http://phrogz.net/svg/progressively-cloning-svg-path.html

Relevant code:

// Assumes 'orig' and dup' are SVG paths
function addNextPathSegment(){
var nextIndex = dup.pathSegList.numberOfItems;
if (nextIndex<orig.pathSegList.numberOfItems){
var nextSegment = orig.pathSegList.getItem(nextIndex);
var segmentDup = cloneSVGPathSeg( dup, nextSegment );
dup.pathSegList.appendItem( segmentDup );
}
}

function cloneSVGPathSeg( path, seg ){
switch(seg.pathSegTypeAsLetter){
case 'M': return path.createSVGPathSegMovetoAbs(seg.x,seg.y); break;
case 'm': return path.createSVGPathSegMovetoRel(seg.x,seg.y); break;
case 'L': return path.createSVGPathSegLinetoAbs(seg.x,seg.y); break;
case 'l': return path.createSVGPathSegLinetoRel(seg.x,seg.y); break;
case 'H': return path.createSVGPathSegLinetoHorizontalAbs(seg.x); break;
case 'h': return path.createSVGPathSegLinetoHorizontalRel(seg.x); break;
case 'V': return path.createSVGPathSegLinetoVerticalAbs(seg.y); break;
case 'v': return path.createSVGPathSegLinetoVerticalRel(seg.y); break;
case 'C': return path.createSVGPathSegCurvetoCubicAbs(seg.x,seg.y,seg.x1,seg.y1,seg.x2,seg.y2); break;
case 'c': return path.createSVGPathSegCurvetoCubicRel(seg.x,seg.y,seg.x1,seg.y1,seg.x2,seg.y2); break;
case 'S': return path.createSVGPathSegCurvetoCubicSmoothAbs(seg.x,seg.y,seg.x2,seg.y2); break;
case 's': return path.createSVGPathSegCurvetoCubicSmoothRel(seg.x,seg.y,seg.x2,seg.y2); break;
case 'Q': return path.createSVGPathSegCurvetoQuadraticAbs(seg.x,seg.y,seg.x1,seg.y1); break;
case 'q': return path.createSVGPathSegCurvetoQuadraticRel(seg.x,seg.y,seg.x1,seg.y1); break;
case 'T': return path.createSVGPathSegCurvetoQuadraticSmoothAbs(seg.x,seg.y); break;
case 't': return path.createSVGPathSegCurvetoQuadraticSmoothRel(seg.x,seg.y); break;
case 'A': return path.createSVGPathSegArcAbs(seg.x,seg.y,seg.r1,seg.r2,seg.angle,seg.largeArcFlag,seg.sweepFlag); break;
case 'a': return path.createSVGPathSegArcRel(seg.x,seg.y,seg.r1,seg.r2,seg.angle,seg.largeArcFlag,seg.sweepFlag); break;
case 'z':
case 'Z': return path.createSVGPathSegClosePath(); break;
}
}

Finally, you may choose to draw your path to an HTML5 canvas by sampling the SVG path periodically and drawing to the canvas. (Note that the SVG path does not need to be displayed for this to happen; you can build an SVG path element entirely in JavaScript and sample it):

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

Relevant code:

function startDrawingPath(){
points = [];
timer = setInterval(buildPath,1000/drawFPS);
}

// Assumes that 'orig' is an SVG path
function buildPath(){
var nextPoint = points.length * distancePerPoint;
var pathLength = orig.getTotalLength();
if (nextPoint <= pathLength){
points.push(orig.getPointAtLength(nextPoint));
redrawCanvas();
} else stopDrawingPath();
}

function redrawCanvas(){
clearCanvas();
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for (var i=1;i<points.length;i++) ctx.lineTo(points[i].x,points[i].y);
ctx.stroke();
}

AnimeJS Progressive Fill of an SVG path

Apparently there is no way to do it with pure CSS. ended up following this tutorial and it worked Great

https://medium.com/@anatacreative/handwriting-animation-with-svg-638931410cfa

svg progressive line drawing hickups, problems with jQuery animate-step

The selector $('path[fill*="none"]').animate({ selects all path elements. To make it work you need to replace it with $(line.node).animate({ .

How to draw a vector path progressively? (Raphael.js)

I've created a script for this: Scribble.js, based on this great dasharray/dashoffset technique.

Just instantiate it overs a bunch of SVG <path>s:

var scribble = new Scribble(paths, {duration: 3000});
scribble.erase();
scribble.draw(function () {
// done
});

--

NB: Full USAGE code here: https://gist.github.com/abernier/e082a201b0865de1a41f#file-index-html-L31

Enjoy ;)

How do you animate an SVG path in IOS?

Try animating the 'stroke-dashoffset' (note that you need a matching 'stroke-dasharray' with it), see this example. The length of the path that needs to be computed to be able to use this successfully can be fetched via script like:

var pathlength = yourPathElm.getTotalLength()

View source on the example to see how it's done.

How can I animate infinite marker movement down an SVG path without very high CPU usage?

It seems indeed that animating the stroke-dashoffset attribute causes a lot of calculations. The original example causes a CPU usage at around 50% when I open it in Firefox.

There's another approach that seems to give better results: manually increment the stroke-dashoffset and loop that using setInterval. Here's a proof of concept:

http://bl.ocks.org/kmandov/raw/a87de2dd49a21be9f95c/

Here's how I update the dashoffset:

var lines = d3.selectAll('.flowline');

var offset = 1;
setInterval(function() {
lines.style('stroke-dashoffset', offset);
offset += 1;
}, 50);

I know that it doesn't look very good but it (surprisingly) performs a lot better than relying on css animations or transitions. In Firefox I now get CPU usage at about 15%.

I can imagine that this approach won't perform very well if you have a lot of links, because the update will take too long. But maybe it's a viable hack for simpler use cases where you animate linearly a fixed amount of links.

SVG semi-arc clockwise animation over 180 degrees (half of a circle) with pure CSS/JS

A possible solution would be animating a very thick stroke (the double of the radius of the circle).

In this case the radius of the circle is 20 so the stroke-width="40"

In the next example I'm animating the stroke-dasharray of the path from: 62.84,0 (stroke length = 62.84, gap = 0) to 0, 62.4 (stroke length = 0, gap = 62.84) where 62.84 is the length of the path.

Please read about how How SVG Line Animation Works

path {
stroke-dasharray: 62.84,0;
animation: anim 5s linear infinite;
}

@keyframes anim {
to {
stroke-dasharray: 0, 62.84;
}
}
<svg viewBox="-50 -50 100 100" width="90vh">
<path stroke-width="40" fill="none" stroke="black" d="M20,0A20,20 0 0 0 -20,0"/>
</svg>

Snap SVG - Animating a path element

I have a solution that shows some buggy behavior (blinking extra lines) in Chrome and Opera

var yourElement = s.select('path#test');
var pathLength = yourElement.getTotalLength();
yourElement.attr({
'stroke-dasharray': '' + pathLength + ' 0'
});
Snap.animate(0, pathLength, function(t){
yourElement.attr({'stroke-dasharray': '' + t + ' ' + (pathLength - t)});
}, 10000);

The idea is pretty simple - animate stroke's dasharray from zero to full length. I hope this could be a good step for a clean solution



Related Topics



Leave a reply



Submit