绘制SVG贝塞尔曲线 [英] Draw SVG Bezier curve

查看:743
本文介绍了绘制SVG贝塞尔曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组表示高阶Bezier曲线的控制点阵列。

如何使用单个SVG路径绘制此曲线?





UPD:

例如,我有一组点:(x1,y1)(x2,y2)(x3,y3)(x4,y4)(x5,y5)。
SVG路径在 C S Q T



UPD 2:解决方案

我问了这个问题以描绘一个对象路径动画与 TweenMax

稍后,我收到了 GreenSock论坛

这里是 CodePen示例

解决方案

p>

SVG仅建立在二次曲线(二阶)和三次曲线(三阶)上,而您显示的曲线是四次曲线(四阶)。 SVG没有通用的N term Bezier绘制指令,所以你必须在这里妥协。



一些选项:


  1. 将曲线转换为(一系列)三次曲线,然后渲染它们。这是一个相当困难的问题,并没有真正推荐。

  2. 在足够的点上对曲线进行采样,使得通过这些点的多边形看起来像人们在分辨率和缩放级别的曲线它。这很容易做到,但当然你不再有曲线,你现在有一个多边形。

  3. 如上所述,但点较少,然后计算Catmull-Rom曲线通过这些点的序列,然后将这些CR曲线转换为三次Bezier(它们是相同类型的函数,并且可以从一个变换到另一个)。这比2好,因为你有一条曲线,但它可能看起来和原来的相同。当然,您使用的点越多,结果就越好。
  4. 使用画布绘制N阶Bezier曲线,使用 toDataURL 函数,然后在SVG中将该图像加载为图像。这可以很好地工作,但是如果使用创建的SVG路径样式,使画布生成相同的样式可能是一个挑战。

  5. 这个列表可能会变得很长,所以让我们在这里停下来底线:如果你需要显示更高阶的贝塞尔曲线,SVG不是一个合适的技术使用(我愿意建议只使用画布进行动画制作,或者更好些,比如 d3.js paper.js 。可能是后者)。

    如果你最终打了你自己的,那么抽样函数是非常简单的。曲线是参数化的,由值为 t 的值控制,该值从0到1(包含),并且可以写为嵌套线性插值:

      getCurvePoint(t,points){
    if(points.length === 1)return points [0];
    var newpoints = [];对于(var i = 0,j = 1; j newpoints [i] = lerp2d(t,points [i],points [j])的
    ;
    }
    返回getCurvePoint(t,newpoints);
    }

    lerp 函数是标准的线性插值函数:

      lerp(ratio,start,end){
    return ratio * start + (1-比率)*端;
    }

    lerp2d(ratio,start,end){
    return {
    x:lerp(ratio,start.x,end.x),
    y :lerp(ratio,start.y,end.y)
    };
    }

    和一个简单的jsbin例子: http://jsbin.com/pesutibefu/edit?html,js,output 使用积分



    < pre $ var points = [
    {x:50,y:100},
    {x:50,y:250},
    { 210,y:250},
    {x:250,y:50},
    {x:380,y:150}
    ];

    给我们:



    尽管如果您需要动画美学路径,可拖动控制点等,Paper.js草图将更容易处理。


    I have an array of control points that represent a high-order Bezier curve.
    How can I draw this curve using a single SVG-path?

    UPD:
    For example, I have a set of points: (x1, y1) (x2, y2) (x3, y3) (x4, y4) (x5, y5).
    How SVG-path will look like in the terms of C, S, Q or T?

    UPD 2: SOLUTION
    I asked this question to depict a object path animated with
    TweenMax.
    Later I received reply on GreenSock forum.
    Here's CodePen example.

    解决方案

    Short answer: you can't.

    SVG only has built in Quadratic (2nd order) and Cubic curves (3rd order), whereas the curve you're showing is Quartic (4th order). SVG has no generic "N term Bezier" draw instruction, so you're going to have to compromise here.

    Some options:

    1. convert the curve to a (series of) cubic curves and render those instead. This is a pretty hard problem and not really recommended.
    2. sample your curve at enough points such that the polygon through those points looks like a curve at the resolution and zoom level people will be looking at it. This is easy to do, but of course you no longer have a "curve", you now have a polygon.
    3. as above, but fewer points, and then compute the Catmull-Rom curve sequence that goes through those points, then convert those CR curves to cubic Bezier (they're the same type of function, and can be 1:1 transformed from one to the other). This is nicer than 2 because you have a curve, but it might not look quite the same as the original. Of course the more points you use, the better the result will be.
    4. use a canvas to draw your Nth degree Bezier curve, build an image out of the result using the toDataURL function and then load that image as image in your SVG. This will work perfectly fine, but if you use created SVG path styling, making the canvas generate the same style could be a challenge.
    5. this list can get very long, so let's stop here for now.

    Bottom line: if you need to show higher order Bezier curves, SVG is not an appropriate technology to use (I'd recommend just doing your animation using the canvas, or better yet, something like d3.js or paper.js. Probably the latter).

    And if you end up rolling your own, the sampling function is ludicrously simple. Curves are parametric, controlled by a value t that runs from 0 to 1 (inclusive), and can be written as a nested linear interpolation:

    getCurvePoint(t, points) {
      if (points.length === 1) return points[0];
      var newpoints = [];
      for(var i=0,j=1; j<points.length; i++,j++) {
        newpoints[i] = lerp2d(t, points[i], points[j]);
      }
      return getCurvePoint(t,newpoints);
    }
    

    with the lerp function being the standard linear interpolation function:

    lerp(ratio, start, end) {
      return ratio*start + (1-ratio)*end;
    }
    
    lerp2d(ratio, start, end) {
      return {
        x: lerp(ratio, start.x, end.x),
        y: lerp(ratio, start.y, end.y)
      };
    }
    

    And a simple jsbin example: http://jsbin.com/pesutibefu/edit?html,js,output using points

    var points = [
      {x:50, y:100},
      {x:50, y:250},
      {x:210, y:250},
      {x:250, y:50},
      {x:380, y:150}
    ];
    

    gives us:

    Although a Paper.js sketch would be easier to work with if you need animated pretty paths, with draggable control points, etc.

    这篇关于绘制SVG贝塞尔曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆