如何在canvas上画线

我想以如下方式在canvas上的圆圈内绘制一些线条。

我不知道如何绘制如下所示的线条。 但我有基本知识在canvas上绘制线条和弧线。 如何进行?

在此处输入图像描述

您可以使用带有控制点的注释中建议的贝塞尔曲线,但是,这些曲线很难控制(没有双关语),因为它们不会通过您定义的点,并且您始终需要定义两个控制点。

为了使用实际点实现直线穿越,您需要使用基数样条曲线。

这些没有内置的支持,但不久前我为JavaScript和canvas做了一个实现(代码可以从这里下载,MIT许可证)。

通过这种方法,您可以简单地将三个点定义为最小值(以获得简单的曲线),并且该函数将负责在具有设定张力值的点之间绘制平滑曲线。

例如,如果您定义了以下三点:

var pts = [10,100, 200,50, 390,100]; 

如果我们想要说明这些点(用于比较),你显然会得到一个这样的简单折线 :

行

使用具有相同三个点的基数样条曲线 可以得到 :

红衣主教样条

以下代码生成上面的曲线(没有显示点坐标的红点):

 ctx.beginPath(); ctx.curve(pts); ctx.stroke(); 

现在只需移动点(特别是中心点)就可以采用曲线。 为用户添加张力滑块可能是一个优势:

将张力增加到例如0.8可以得到这样的结果:

 ctx.curve(pts, 0.8); 

张力更高

并将其降低到例如0.3会降低平滑度:

 ctx.curve(pts, 0.3); 

降低张力

还有其他参数(请参阅顶部的链接以获取文档),如果要添加超精细控制,则可以在点arrays中具有“无限”的点数。

实现扩展了canvas上下文,但是如果你内心模糊,你可以提取方法并单独使用它。 🙂

为圆圈实现这一点

我希望我在这里正确地解释您的绘图…要使用上面的圆形,您只需要执行以下操作:

  • 定义范围,您想要绘制线条的圆的边。
  • 定义步骤,即。 每条线之间的空间。

让我们说你想在-70°和70°之间绘制线条,最多5行你可以做这样的事情:

 var ctx = canvas.getContext('2d'), cx = canvas.width * 0.5, cy = canvas.height * 0.5, pts, startAngle = -70, endAngle = 70, lines = 5, angle, range, steps, radius = 90, delta = 15, x, y, i; ctx.lineWidth = 3; ctx.strokeStyle = '#059'; /// draw arc ctx.beginPath(); ctx.arc(cx, cy, radius, 0, 2 * Math.PI); ctx.stroke(); /// calculate angle range normalized to 0 degrees startAngle = startAngle * Math.PI / 180; endAngle = endAngle * Math.PI / 180; range = endAngle - startAngle; steps = range / (lines + 1); /// calculate point at circle (vertical only) for(i = 1; i <= lines; i++) { pts = []; /// right side x = cx + radius * Math.cos(startAngle + steps * i); y = cy + radius * Math.sin(startAngle + steps * i); pts.push(x, y); /// center pts.push(cx, y + delta * ((y - cy)/ cy)); /// flip for left side x = cx - (x - cx); pts.push(x, y); /// draw curve ctx.beginPath(); ctx.curve(pts, 0.8); ctx.stroke(); } 

这会导致:

地球

在这里小提琴

现在只需要玩弄值(例如delta)并计算水平行 - 我将把它作为OP的练习:

使用椭圆边绘制线条

话虽这么说 - 如果你想要地球更多,圆形:-S,你也可以使用一个函数来计算椭圆的一部分,并将其绘制为线条。 如果将是与上面相同的实现,但具有子函数以使用线和中间点之间的差异作为半径来计算左侧和右侧之间的椭圆。

例如:

 /// calculate point at circle (vertical only) for(i = 1; i <= lines; i++) { pts = []; /// right side x = cx + radius * Math.cos(startAngle + steps * i); y = cy + radius * Math.sin(startAngle + steps * i); pts.push(cx - radius, cy); pts.push(cx, y); pts.push(cx + radius, cy); /// draw ellipse side ctx.beginPath(); drawEllipseSide(pts, true); ctx.stroke(); } 

然后在方法中(仅显示垂直方向):

 function drawEllipseSide(pts, horizontal) { var radiusX, radiusY, cx, cy, x, y, startAngle, endAngle, steps = Math.PI * 0.01, i = 0; if (horizontal) { radiusX = Math.abs(pts[4] - pts[0]) * 0.5; radiusY = pts[3] - pts[1]; cx = pts[2]; cy = pts[1]; startAngle = 0; endAngle = Math.PI; x = cx + radiusX * Math.cos(startAngle); y = cy + radiusY * Math.sin(startAngle); ctx.moveTo(x, y); for(i = startAngle + steps; i < endAngle; i += steps) { x = cx + radiusX * Math.cos(i); y = cy + radiusY * Math.sin(i); ctx.lineTo(x, y); } } } 

导致这一点(我在最后的绘图中作了一点作用,给出了一个更清晰的画面(没有双关语),如果你继续沿着这些行继续下去将会是什么样的结果(没有双关语,我是双关语),这里给出了:):

地球

在这里小提琴

我的代码 - OCD踢了:-P但是你至少应该有一些选择。 研究代码以了解如何计算垂直线并采用水平线。

希望这可以帮助!