绘制SVG贝塞尔曲线

时间:2016-06-03 14:24:27

标签: html svg bezier tweenmax gsap

我有一组控制点,代表一个高阶贝塞尔曲线 如何使用单个SVG路径绘制此曲线?

enter image description here

UPD:
例如,我有一组点:(x1,y1)(x2,y2)(x3,y3)(x4,y4)(x5,y5)。
如何在术语中使用SVG路径CSQT

UPD 2:解决方案
我问这个问题是用TweenMax描绘一个动画对象路径 后来我收到GreenSock forum的答复 这是CodePen example

2 个答案:

答案 0 :(得分:10)

简短回答:你不能。

SVG只有内置二次(二阶)和三次曲线(三阶),而你显示的曲线是四阶(四阶)。 SVG没有通用的“N term Bezier”绘图指令,所以你必须在这里做出妥协。

一些选项:

  1. 将曲线转换为(系列)三次曲线并改为渲染。这是一个非常难的问题,并不是真的值得推荐。
  2. 在足够的点处对曲线进行采样,使得通过这些点的多边形看起来像分辨率和缩放级别的曲线,人们将会看到它。这很容易做到,但当然你不再有“曲线”,你现在有了一个多边形。
  3. 如上所述,但点数较少,然后计算经过这些点的Catmull-Rom曲线序列,然后将这些CR曲线转换为三次贝塞尔曲线(它们是相同类型的函数,可以进行1:1变换从一个到另一个)。这比2更好,因为你有一条曲线,但它可能看起来不像原来那样相当。当然,你使用的点越多,结果就越好。
  4. 使用画布绘制N度贝塞尔曲线,使用toDataURL函数从结果中构建图像,然后在SVG中将该图像加载为图像。这将完美地运行,但如果您使用创建的SVG路径样式,使画布生成相同的样式可能是一个挑战。
  5. 这个列表可能会很长,所以现在就停在这里。
  6. 底线:如果你需要显示更高阶的贝塞尔曲线,SVG不是一个合适的技术(我建议你只使用画布做动画,或者更好,像d3.js或{ {3}}。可能是后者)。

    如果您最终自己动手,那么采样功能非常简单。曲线是参数化的,由值t控制,从0到1(包括),并且可以写为嵌套线性插值:

    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);
    }
    

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

    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)
      };
    }
    

    一个简单的jsbin示例:paper.js使用点

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

    给我们:

    http://jsbin.com/pesutibefu/edit?html,js,output

    虽然如果你需要动画漂亮的路径,可拖动的控制点等,Paper.js草图会更容易使用。

答案 1 :(得分:1)

SVG不支持Quadratic和Cubic以外的Bezier曲线。因此,在命令(C,S,Q或T)方面没有任何表示。

贝塞尔曲线可以用两种方式定义:使用“C”命令表示立方体或使用“Q”命令表示二次曲线。那些命令有固定长度的参数 4为二次方,6为立方,因此示例SVG字符串将显示为“Q 150,-300 300,0”您可以看到类似“Q 150,-300 300的SVG字符串,0 50,150 100,200“,但这只是一条接一条的两条四条曲线,”Q“的参数数量始终是4的倍数,”C“的参数数量总是6的倍数。

list中的每个命令:

M = moveto
L = lineto
H =水平线到
V =垂直线到
C =曲线到 S =平滑曲线 Q =二次Bézier曲线
T =平滑的二次Bézier曲线到
A =椭圆弧 Z =近距离

JavaScript或实际上在任何其他标准API(.NET绘图,核心图形,Android Canvas)中都有表示,但在所有这些API中除了Cubic或Quad之外没有任何其他方法。另外根据我的经验,我从未见过具有绘制更高阶贝塞尔曲线的特征的绘图应用程序。因此,您最好的选择是将高阶曲线简化为Q或C.