Javascript 如何为 svg 路径的渐进式绘图设置动画?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14275249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I animate a progressive drawing of svg path?
提问by Dan Ovidiu Boncut
I want to animate a progressive drawing of a line using only css with svg/canvas and js maximum. An idea of the line I want to draw can be found here
我想仅使用带有 svg/canvas 和 js 最大值的 css 来为一条线的渐进绘制动画。我想画的线的想法可以在这里找到
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<g>
<title>Layer 1</title>
<path d="m33,104c1,0 2.1306,-0.8037 23,3c9.07012,1.65314 10,2 24,2c7,0 29,0 33,0c8,0 9,0 11,0c2,0 8,0 11,0c9,0 17,0 18,0c10,0 12,0 20,0c1,0 6,0 7,0c2,0 3.07613,0.38268 4,0c2.61313,-1.08239 2,-3 2,-6c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0.30745,-3.186 -1,-5c-0.8269,-1.14727 -0.09789,-2.82443 -2,-4c-0.85065,-0.52573 -2.82443,-0.09789 -4,-2c-0.52573,-0.85065 -2.58578,-0.58578 -4,-2c-0.70711,-0.70711 -1.81265,-1.20681 -4,-3c-2.78833,-2.28588 -3.64749,-2.97251 -8,-4c-2.91975,-0.68926 -4.82375,-2.48626 -7,-3c-2.91975,-0.68926 -5.15224,-0.23463 -7,-1c-1.30656,-0.5412 -4.38687,-1.91761 -7,-3c-1.84776,-0.76537 -5.03609,0.37821 -7,0c-5.28799,-1.01837 -8,-3 -9,-3c-2,0 -5.0535,-0.54049 -7,-1c-2.17625,-0.51374 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -3,-1 -4,-1c-2,0 -5,-1 -6,-1c-1,0 -3,-2 -6,-2c-2,0 -5,-2 -6,-2c-2,0 -2.02583,-0.67963 -4,-1c-3.12144,-0.50654 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -2,-1 -3,-1c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-2,0 -3.85273,0.1731 -5,1c-1.81399,1.30745 -5.18601,1.69255 -7,3c-1.14727,0.8269 -1.82375,2.48626 -4,3c-0.97325,0.22975 -1.69344,1.45881 -3,2c-0.92388,0.38268 -1.45951,1.0535 -1,3c0.51374,2.17625 3.07844,2.78985 6,4c2.06586,0.85571 3.38688,1.91761 6,3c1.84776,0.76537 5.2987,-1.05146 7,0c1.90211,1.17557 3.82375,2.48626 6,3c0.97325,0.22975 3.29289,0.29289 4,1c0.70711,0.70711 4,2 9,4c5,2 8,4 11,4c2,0 5,0 7,0c3,0 5,0 7,0c2,0 4,0 7,0c2,0 4,0 8,0c3,0 7,0 10,0c4,0 7,0 12,0c3,0 5,0 6,0c2,0 3,0 5,0c1,0 1.09789,-0.82443 3,-2c0.85065,-0.52573 3.07613,0.38268 4,0c1.30656,-0.5412 0.71022,-2.04291 1,-3c1.04483,-3.45084 2.84723,-5.04132 4,-9c0.88414,-3.03616 1.85194,-5.22836 3,-8c0.5412,-1.30656 1.5405,-2.0535 2,-4c0.51375,-2.17625 2.71413,-4.21167 5,-7c2.68979,-3.28101 4,-6 5,-7c1,-1 2,-2 2,-4c0,-1 0.70711,-2.29289 0,-3c-0.70711,-0.70711 -2.07613,0.38268 -3,0c-1.30656,-0.54119 -2,-1 -4,-1c-3,0 -6.87856,-2.49346 -10,-3c-2.96126,-0.48055 -6.71201,-0.98162 -12,-2c-2.94586,-0.56732 -5,-1 -9,-1c-3,0 -6,-1 -8,-1c-2,0 -5,-3 -7,-3c-2,0 -5.38687,-0.91761 -8,-2c-0.92388,-0.38268 -3.0535,-0.54049 -5,-1c-2.17625,-0.51374 -4.58578,0.41421 -6,-1c-0.70711,-0.70711 -1,-1 -2,-1c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -3,0 -4,0c-3,0 -5,0 -7,0c-2,0 -4,0 -6,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-2,0 -4,0 -5,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,1l-1,0" id="svg_1" stroke-width="5" stroke="#000000" fill="none"/>
</g>
</svg>
回答by Phrogz
There are three techniques listed in this answer:
此答案中列出了三种技术:
There is an all-SVG solution that involves progressively modifying the stroke-dasharrayfor the shape to draw a longer and longer 'dash' followed by an enormous gap.
有一个全 SVG 解决方案,它涉及逐步修改stroke-dasharray形状以绘制越来越长的“破折号”,然后是一个巨大的间隙。
Demo: http://phrogz.net/svg/progressively-drawing-svg-path-via-dasharray.html
演示: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:
或者,您仍然可以使用所有 SVG 并选择一次一个命令构建 SVG 路径:
Demo: http://phrogz.net/svg/progressively-cloning-svg-path.html
演示: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):
最后,您可以选择通过定期采样 SVG 路径并绘制到画布来绘制到 HTML5 画布的路径。(请注意,无需显示 SVG 路径即可实现此目的;您可以完全在 JavaScript 中构建 SVG 路径元素并对其进行采样):
Demo: http://phrogz.net/svg/progressively-drawing-svg-path.html
演示: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();
}
回答by Joonas
So there's this similar question with this answer.
所以这个答案有这个类似的问题。
I took your path and put it into the code in that answer.
我选择了您的路径并将其放入该答案中的代码中。
Html:
网址:
<html>
<style>
#canvas
{
border-style:solid;
border-width:1px;
}
</style>
<div id="canvas">
<p>Hover over me</p>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
Javascript ( Note that Jquery 1.8.3 and Raphael 1.5.2 was used in the example ):
Javascript (请注意,示例中使用了 Jquery 1.8.3 和 Raphael 1.5.2):
$(function() {
animateLine = function(canvas, hoverDivName, colorNumber, pathString) {
$('#' + hoverDivName).hover(
function() {
var line = canvas.path(pathString).attr({
stroke: colorNumber
});
var length = line.getTotalLength();
$('path[fill*="none"]').animate({
'to': 1
}, {
duration: 5000,
step: function(pos, fx) {
var offset = length * fx.pos;
var subpath = line.getSubpath(0, offset);
canvas.clear();
canvas.path(subpath).attr({
'stroke-width': 5,
stroke: colorNumber
});
},
});
}, function() {
$('path[fill*="none"]').stop(true, false).fadeOut();
});
};
var canvas = Raphael('canvas', 200, 200);
var pathString = "m33,104c1,0 2.1306,-0.8037 23,3c9.07012,1.65314 10,2 24,2c7,0 29,0 33,0c8,0 9,0 11,0c2,0 8,0 11,0c9,0 17,0 18,0c10,0 12,0 20,0c1,0 6,0 7,0c2,0 3.07613,0.38268 4,0c2.61313,-1.08239 2,-3 2,-6c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0.30745,-3.186 -1,-5c-0.8269,-1.14727 -0.09789,-2.82443 -2,-4c-0.85065,-0.52573 -2.82443,-0.09789 -4,-2c-0.52573,-0.85065 -2.58578,-0.58578 -4,-2c-0.70711,-0.70711 -1.81265,-1.20681 -4,-3c-2.78833,-2.28588 -3.64749,-2.97251 -8,-4c-2.91975,-0.68926 -4.82375,-2.48626 -7,-3c-2.91975,-0.68926 -5.15224,-0.23463 -7,-1c-1.30656,-0.5412 -4.38687,-1.91761 -7,-3c-1.84776,-0.76537 -5.03609,0.37821 -7,0c-5.28799,-1.01837 -8,-3 -9,-3c-2,0 -5.0535,-0.54049 -7,-1c-2.17625,-0.51374 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -3,-1 -4,-1c-2,0 -5,-1 -6,-1c-1,0 -3,-2 -6,-2c-2,0 -5,-2 -6,-2c-2,0 -2.02583,-0.67963 -4,-1c-3.12144,-0.50654 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -2,-1 -3,-1c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-2,0 -3.85273,0.1731 -5,1c-1.81399,1.30745 -5.18601,1.69255 -7,3c-1.14727,0.8269 -1.82375,2.48626 -4,3c-0.97325,0.22975 -1.69344,1.45881 -3,2c-0.92388,0.38268 -1.45951,1.0535 -1,3c0.51374,2.17625 3.07844,2.78985 6,4c2.06586,0.85571 3.38688,1.91761 6,3c1.84776,0.76537 5.2987,-1.05146 7,0c1.90211,1.17557 3.82375,2.48626 6,3c0.97325,0.22975 3.29289,0.29289 4,1c0.70711,0.70711 4,2 9,4c5,2 8,4 11,4c2,0 5,0 7,0c3,0 5,0 7,0c2,0 4,0 7,0c2,0 4,0 8,0c3,0 7,0 10,0c4,0 7,0 12,0c3,0 5,0 6,0c2,0 3,0 5,0c1,0 1.09789,-0.82443 3,-2c0.85065,-0.52573 3.07613,0.38268 4,0c1.30656,-0.5412 0.71022,-2.04291 1,-3c1.04483,-3.45084 2.84723,-5.04132 4,-9c0.88414,-3.03616 1.85194,-5.22836 3,-8c0.5412,-1.30656 1.5405,-2.0535 2,-4c0.51375,-2.17625 2.71413,-4.21167 5,-7c2.68979,-3.28101 4,-6 5,-7c1,-1 2,-2 2,-4c0,-1 0.70711,-2.29289 0,-3c-0.70711,-0.70711 -2.07613,0.38268 -3,0c-1.30656,-0.54119 -2,-1 -4,-1c-3,0 -6.87856,-2.49346 -10,-3c-2.96126,-0.48055 -6.71201,-0.98162 -12,-2c-2.94586,-0.56732 -5,-1 -9,-1c-3,0 -6,-1 -8,-1c-2,0 -5,-3 -7,-3c-2,0 -5.38687,-0.91761 -8,-2c-0.92388,-0.38268 -3.0535,-0.54049 -5,-1c-2.17625,-0.51374 -4.58578,0.41421 -6,-1c-0.70711,-0.70711 -1,-1 -2,-1c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -3,0 -4,0c-3,0 -5,0 -7,0c-2,0 -4,0 -6,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-2,0 -4,0 -5,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,1l-1,0";
animateLine(canvas, "canvas", "#000", pathString);
});
- I took your path from the [
d] attribute and put it inside thepathStringvariable. - I also added a line to define the [
stroke-width]
- 我从 [
d] 属性中取出您的路径并将其放入pathString变量中。 - 我还添加了一行来定义 [
stroke-width]
I've only played around with raphael quite briefly once, but checking the examples and looking at how the code is constructed ( from page source) gets you quite far ( I couldn't remember how/where to put the stroke-width, so I checked the method from the page source of this example. ).
我只简单地玩过一次 raphael,但是检查示例并查看代码的构造方式 ( from page source) 会让你走得很远(我不记得如何/在哪里放置stroke-width,所以我从这个例子的页面来源。)。
You can find raphael + more info from here.
Just for fun, I made my own path...
只是为了好玩,我开辟了自己的道路......
回答by carl
Using Phrogz excellent technique I created a very basic GreenSock animation using TweenLite to tween the length value to getTotalLength() value.
使用 Phrogz 出色的技术,我创建了一个非常基本的 GreenSock 动画,使用 TweenLite 将长度值补间到 getTotalLength() 值。
As you can see in the demo, hooking this into a tween engine gives you tons of control and it involves very little code.
正如您在演示中看到的那样,将其连接到补间引擎中可以为您提供大量控制,并且只涉及很少的代码。
var orig = document.querySelector('path'), length, timer;
var obj = {length:0,
pathLength:orig.getTotalLength()};
orig.style.stroke = '#f60';
var t = TweenMax.to(obj, 10, {length:obj.pathLength, onUpdate:drawLine, ease:Linear.easeNone})
function drawLine() {
orig.style.strokeDasharray = [obj.length,obj.pathLength].join(' ');
updateSlider();
}
Much respect to Phrogz for the awesome idea and code.
非常尊重 Phrogz 令人敬畏的想法和代码。
回答by Ashley Sheridan
I did something similar last year to animate a drawing in canvas. The paths are all SVG-type paths with curves and lines, so you could take those straight out of your SVG file and put them into the Javascript array.
去年我做了类似的事情来为画布上的一幅画制作动画。这些路径都是带有曲线和线条的 SVG 类型路径,因此您可以直接从 SVG 文件中取出这些路径并将它们放入 Javascript 数组中。
http://www.ashleysheridan.co.uk/coding/javascript/Animated+Glowing+Line+Drawing+in+Canvas
http://www.ashleysheridan.co.uk/coding/javascript/Animated+Glowing+Line+Drawing+in+Canvas

