如何在画布中绘制线条

时间:2014-02-18 07:03:37

标签: javascript jquery html5 canvas html5-canvas

我想在画布上的圆圈内绘制一些线条,方法如下。

我不知道如何绘制如下所示的线条。但我掌握了在画布上绘制线条和弧线的基本知识。怎么办?

enter image description here

1 个答案:

答案 0 :(得分:7)

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

为了使用实际点获得直线点,您需要使用 基数样条线

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

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

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

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

如果我们想要说明这些点(用于比较),你显然会得到一个simple poly-line like this

Lines

使用基数样条线具有相同的三个点would give you this

Cardinal spline

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

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

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

Increasing the tension例如0.8给你这个结果:

ctx.curve(pts, 0.8);

Higher tension

lowering it例如0.3会降低平滑度:

ctx.curve(pts, 0.3);

Lower tension

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

实现扩展了画布上下文,但是如果你内心很暗,你可以提取方法并单独使用它。 : - )

为圆圈实现此

我希望我在这里正确地解释您的绘图......要将上面的内容用于圆圈,您只需要执行以下操作:

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

假设您想在-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();
}

哪会导致这个:

Globe

<强> Fiddle here

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

使用椭圆边绘制线

这就是说 - if 你想要地球更多,圆形:-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);
        }
    }
}

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

Globe

<强> Fiddle here

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

希望这有帮助!