【问题标题】:Draw SVG Bezier curve绘制 SVG 贝塞尔曲线
【发布时间】:2016-06-03 14:24:26
【问题描述】:

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

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

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

【问题讨论】:

  • 我喜欢这个!你想画哪一部分?您是否也想为笔画设置动画?
  • @ChrisW。不不不,图像只是为了清楚起见。我需要通过控制点绘制静态曲线
  • 那么,您对路径数据有多熟悉?您将使用M 属性定义您的起点,C 定义您的起点曲线,您的点跟随第一条弧线,Z 结束这一切。您可能会使用this 之类的东西来获得一点熟悉感。或者如果它是静态的,我通常只是在 Adob​​e Illustrator 中创建这些资源并导出到 SVG。但是,如果没有看到您尝试过的内容或不了解要点等,这个问题确实非常广泛。
  • C 只允许构建三次贝塞尔曲线,即通过 4 个控制点。我需要通过任意数量的控制点来构建贝塞尔曲线:3、4、5、6 等。
  • 哦,对不起,一定是嗡嗡作响,以为我看到了故意的。然后你有选择,你可以坚持使用 Cubic 并用 S 将单独的线串在一起以保持坡度。或者更好的是,使用 T 进行多次二次计算,甚至更进一步在 Q 中定义点,但是有多个文档/教程可以更好地解释,而不是我有时间在 cmets 中解释。

标签: html svg bezier gsap


【解决方案1】:

简短的回答:你不能。

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

一些选项:

  1. 将曲线转换为(一系列)三次曲线并渲染它们。这是一个相当困难的问题,并不推荐。
  2. 在足够多的点对曲线进行采样,这样通过这些点的多边形在分辨率和缩放级别上看起来就像人们会看到的曲线。这很容易做到,但当然你不再有“曲线”,你现在有一个多边形。
  3. 同上,但点少,然后计算通过这些点的Catmull-Rom曲线序列,然后将这些CR曲线转换为三次Bezier(它们是相同类型的函数,可以1:1转换从一个到另一个)。这比 2 更好,因为您有一条曲线,但它可能看起来与原始曲线不同相当。当然,使用的积分越多,效果就越好。
  4. 使用画布绘制第 N 度贝塞尔曲线,使用 toDataURL 函数根据结果构建图像,然后将该图像作为图像加载到 SVG 中。这会很好地工作,但如果您使用创建的 SVG 路径样式,使画布生成相同的样式可能是一个挑战。
  5. 这个列表可能会很长,所以我们先到此为止。

底线:如果您需要显示更高阶的贝塞尔曲线,则 SVG 不是一种合适的技术(我建议您只使用画布制作动画,或者更好,例如 d3.jspaper.js . 可能是后者)。

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

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 示例: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}
];

给我们:

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

【讨论】:

  • 谢谢,您的解决方案很聪明,但我在 GreenSock 论坛上收到了另一个有趣的答案:greensock.com/forums/topic/…
  • 当然,这将绘制一个曲线近似值,我将其解释为选项#1。它确实绘制实际曲线。如果这对你来说足够好,那就继续吧。但是,在另一个论坛上获得“正确”答案意味着您要么接受你在这里得到的最好的答案,因为它是一个不同的论坛,要么你现在根据你在其他地方得到的答案发布你自己的答案,然后 24 小时后接受这是正确的答案。你不会只为自己提出关于 SO 的问题,其他人也会遇到这个问题,并且也想知道答案是什么 =)
  • 另外,看看 tweenmax,这并不能解决您的问题:它实际上是通过 船体点绘制曲线,所以现在您仍然需要生成正确的 on-使用我帖子中的函数的曲线点,使“通过”曲线的曲率与真实曲线对齐。而这快速和简单。
【解决方案2】:

SVG 不支持除二次和三次以外的贝塞尔曲线。所以在命令(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 = 移动到
L = lineto
H = 水平线到
V = 垂直线到
C = 曲线
S = 平滑曲线到
Q = 二次贝塞尔曲线
T = 平滑二次贝塞尔曲线
A = 椭圆弧
Z = 关闭路径

JavaScript 或任何其他标准 API(.NET 绘图、Core Graphics、Android Canvas)中都有表示,但在所有这些 API 中,除了 Cubic 或 Quad 之外没有其他方法。同样以我的经验,我从未见过具有绘制更高阶贝塞尔曲线的功能的绘图应用程序。因此,您最好的选择是将高阶曲线简化为 Q 或 C。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-26
    • 1970-01-01
    • 2017-11-18
    • 2021-09-10
    • 1970-01-01
    • 2014-09-29
    • 2017-05-18
    • 1970-01-01
    相关资源
    最近更新 更多