如何逐步绘制矢量路径? (Raphael.js)

时间:2011-01-07 22:52:54

标签: javascript animation vector svg bezier

如何对矢量路径进行动画制作,就像逐渐绘制它一样?换句话说,逐个像素地慢慢显示路径。

我正在使用Raphaël.js但是如果你的答案不是特定于库的 - 就像有一些通用的编程模式来做那种事情(我对矢量很新)动画) - 欢迎!


使用直线路径很容易,就像that page ::

上的示例一样简单
path("M114 253").animate({path: "M114 253 L 234 253"});

但尝试更改该页面上的代码,比如说,这样::

path("M114 26").animate({path: "M114 26 C 24 23 234 253 234 253"});

你会明白我的意思。从初始状态(点“M114 26”)到结束状态(曲线“C 24 23 234 253 234 253”,从点“M114 26”开始),路径肯定是动画的,但不是以有问题的方式指定,不是像正在被吸引。

我不知道animateAlong如何做到这一点。它可以沿着路径为对象设置动画,但是如何在沿着对象动画对象的同时使这条路径逐渐显示出来?


解决方案?

(通过peteorpeter's answer。)

似乎目前最好的方法是使用原始SVG通过'假'短划线。有关说明,请参阅第4页的this demothis document

  

如何制作渐进式绘图?

     

我们必须使用stroke-dasharraystroke-dashoffset并知道要绘制的曲线长度。   此代码在屏幕上不显示圆形,椭圆形,折线,多边形或路径:

<[element] style="stroke-dasharray:[curve_length],[curve_length]; stroke-dashoffset:[curve_length]"/>
     

如果在animate元素stroke-dashoffset减少到0,我们将逐步绘制曲线。

<circle cx="200" cy="200" r="115"
    style="fill:none; stroke:blue; stroke-dasharray:723,723; stroke-dashoffset:723">
    <animate begin="0" attributeName="stroke-dashoffset"
        from="723" to="0" dur="5s" fill="freeze"/>
</circle>

如果你知道更好的方法,请留下答案。


更新(2012年4月26日):找到一个很好地说明这个想法的示例,请参阅Animated Bézier Curves

11 个答案:

答案 0 :(得分:26)

也许有人正在寻找答案,就像我一样,现在待了两天:

// Draw a path and hide it:
var root = paper.path('M0 50L30 50Q100 100 50 50').hide();
var length = root.getTotalLength();

// Setup your animation (in my case jQuery):
element.animate({ 'to': 1 }, {
    duration: 500,
    step: function(pos, fx) {
        var offset = length * fx.pos;
        var subpath = root.getSubpath(0, offset);
        paper.clear();
        paper.path(subpath);
    }
});

只有使用RaphaelJS方法才能解决这个问题。

以下是评论http://jsfiddle.net/eA8bj/

中请求的jsFiddle示例

答案 1 :(得分:17)

尤里卡! (也许 - 假设你在拉斐尔的友好领域之外走进纯净的SVG土地......)

您可以使用SVG keyTimes keySplines

这是一个有效的例子:

http://www.carto.net/svg/samples/animated_bustrack.shtml

......这里有一些可能有用的解释:

http://msdn.microsoft.com/en-us/library/ms533119(v=vs.85).aspx

答案 2 :(得分:11)

我想提供一种替代的,Raphael + JS-only解决方案,我已经在我自己的工作中充分利用了它。它比davidenke的解决方案有几个优点:

  1. 每次循环都不清除纸张,允许动画路径与其他元素很好地共存;
  2. 使用Raphael自己的渐进式动画重用单一路径,制作更流畅的动画;
  3. 资源密集程度大大减少。
  4. 这是方法(可以很容易地重新组合成扩展名):

    function drawpath( canvas, pathstr, duration, attr, callback )
    {
        var guide_path = canvas.path( pathstr ).attr( { stroke: "none", fill: "none" } );
        var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
        var total_length = guide_path.getTotalLength( guide_path );
        var last_point = guide_path.getPointAtLength( 0 );
        var start_time = new Date().getTime();
        var interval_length = 50;
        var result = path;        
    
        var interval_id = setInterval( function()
        {
            var elapsed_time = new Date().getTime() - start_time;
            var this_length = elapsed_time / duration * total_length;
            var subpathstr = guide_path.getSubpath( 0, this_length );            
            attr.path = subpathstr;
    
            path.animate( attr, interval_length );
            if ( elapsed_time >= duration )
            {
                clearInterval( interval_id );
                if ( callback != undefined ) callback();
                    guide_path.remove();
            }                                       
        }, interval_length );  
        return result;
    }
    

    以下是我网站上使用的两个示例:一个用于Path Transformation,另一个用于Progressive Lettering

答案 3 :(得分:6)

使用“pathLength”属性,我们可以将虚拟长度设置为路径。从那时起,我们可以在“stroke-dasharray”中使用这个虚拟长度。 因此,如果我们将“pathLength”设置为100个单位,那么我们可以将“stroke-dasharray”设置为“50,50”,这将是50%,50%的路径!

这种方法存在一个问题:唯一支持此属性的浏览器是Opera 11。

Here是没有javascript或硬编码长度的平滑曲线drawind动画的示例。(仅在Opera 11中正常工作)

答案 4 :(得分:5)

我已经为此创建了一个脚本:Scribble.js,基于这个伟大的dasharray/dashoffset technique

只需将其实例化为一堆SVG var scribble = new Scribble(paths, {duration: 3000}); scribble.erase(); scribble.draw(function () { // done }); s:

USAGE

-

注意:此处有完整的urlpatterns = [ url(r'^$', post_list, name='list'), url(r'^create/$', post_create, name='create'), url(r'^haystack/$', display_hay, name='haystack'), url(r'^search_f/$', search_title), url(r'^search_results/$', post_search, name='search-page'), url(r'^tag/(?P<slug>[\w-]+)/$', tag_list, name="tag_list"), url(r'^(?P<slug>[\w-]+)/$', post_detail, name='detail'), url(r'^(?P<slug>[\w-]+)/edit/$', post_update, name='update'), url(r'^(?P<id>\d+)/delete/$', post_delete, name='delete'), url(r'^submit_video/$', submit_video, name='submit_video'), url(r'^privacy/$', privacy, name='privacy'), url(r'^terms/$', terms, name='terms'), url(r'^dcma/$', dcma, name='dcma'), # url(r'^search/', include('haystack.urls')), 代码:https://gist.github.com/abernier/e082a201b0865de1a41f#file-index-html-L31

享受;)

答案 5 :(得分:3)

安东&amp;当路径变得复杂时,Peteorpeter的解决方案可能会在Chrome中崩溃。这个链接演示中的公交地图很好。看看我创建的动画“花瓣”jsfiddle,它在FF10和Safari5中正确绘制,但在Chrome中无法控制地闪烁:

http://jsfiddle.net/VjMvz/

(这是所有HTML和内联SVG,没有javascript。)

我仍在为此寻找非Flash解决方案。 AnimateAlong显然不会因为我正在做的事而削减它。 Raphael.js可以工作,虽然它有可能很快变成回调意大利面。

Davidenke,你能发布一个有效的解决方案吗?我无法让它发挥作用。我在Chrome 18中遇到一个错误,即使用“.hide”设置为“display:none”的节点没有方法'getTotalLength'。

答案 6 :(得分:2)

不幸的是,正如你似乎同意的那样,你可能不会在拉斐尔中优雅地做到这一点。

然而,如果通过%deity%的某个笔划,您不需要支持此特定功能的IE,则可以放弃Raphael API和manipulate the SVG directly。然后,也许,你可以装备mask沿着路径骑行并以自然的速度展示线。

你可以在IE中优雅地降级,只使用Raphael显示路径,而不需要动画。

答案 7 :(得分:1)

我正是这样做的。我尝试的第一件事是安东的解决方案,但性能很糟糕。

最后,获得我想要的结果的最简单方法是为animate函数使用替代的“keyframe”语法。

无形地绘制最终路径,然后在循环中使用getSubpath生成一大堆关键帧。

创建一个可见且等于第一个关键帧的新路径。

然后执行以下操作:

path.anmimate({keyFrameObject,timeframe});

您不应该为要绘制的每个像素都使用关键帧。在玩完参数之后,我发现每个关键帧的值为100px对于我试图“绘制”的复杂性/大小起作用

答案 8 :(得分:1)

只需对此进行更新,您就可以尝试Lazy Line Painter

答案 9 :(得分:0)

你试过拉斐尔的animateAlong吗?您可以在行动on a demo page中看到它。

答案 10 :(得分:0)

好吧,这是我对此的看法......解决方案离理想太远了。

逐渐显示路径意味着我们应该逐点显示它。矢量路径不是由点组成,而是由曲线组成,所以在我看来,没有“自然”的方法可以逐渐“绘制”矢量图形中的路径。 (虽然我对此很新,可能会弄错。)

唯一的方法是以某种方式将路径转换为多个点并逐个显示。

目前我的解决方法是绘制路径,使其不可见,将其分解为多个子路径,并逐个显示子路径。

这对拉斐尔来说并不难,但它也不优雅,而且在很大的路径上相当慢。不接受我的回答,希望有更好的方法......