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
Sleep in JavaScript - Delay Between Actions
Persistent Service Worker in Chrome Extension
How to Simulate a Click With JavaScript
Jquery Scroll() Detect When User Stops Scrolling
How to Update the Parent'S State in React
Response to Preflight Request Doesn't Pass Access Control Check
Arrow Function Without Curly Braces
Why Does Babel Rewrite Imported Function Call to (0, Fn)(...)
JavaScript Call() & Apply() VS Bind()
JavaScript Add Leading Zeroes to Date
JavaScript: Remove Event Listener
Using Node.Js Require Vs. Es6 Import/Export
Finding the Max Value of an Attribute in an Array of Objects
Delete Firebase Data Older Than 2 Hours
Suppress Chrome 'Failed to Load Resource' Messages in Console
How to Run Multiple Npm Scripts in Parallel
How to Extend an Existing JavaScript Array with Another Array, Without Creating a New Array