用两个不同大小的末端画一条线

Draw a line with two different sized ends

如何使用 canvas 使一条线具有两种不同的大小?

我正在用 canvas 画一条线,我想从 30 的宽度开始,然后逐渐(按比例)缩小到 15 的大小, 这样它就在行尾达到 15。

我想也许如果我在两个地方(开始和结束)设置 context.lineWidth 它会起作用。

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="578" height="200"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');

      context.beginPath();
      context.moveTo(100, 150);
      context.lineWidth = 30;
      context.lineTo(450, 50);
      context.lineWidth = 15;
      context.stroke();
    </script>
  </body>
</html>

我曾经想过构建这样一个可变宽度的线,我结束了构建自己的解决方案,并用它写了一篇博客post。
我会在这里复制它的第一部分,也可以在这里找到四舍五入的版本: https://gamealchemist.wordpress.com/2013/08/28/variable-width-lines-in-html5-canvas/


html5

中的可变宽度线

一旦我们意识到我们需要绘制的不是一条线:实际上它是一个多边形,那么绘制这样一条[可变宽度]线就很容易了。

如果我们要画的线段是(A,B),情况是这样的:

其实我们要画的是A1,A2,B2,B1多边形

如果我们称 N 为法向量(在方案中绘制),w1 和 w2 分别为 A 和 B 中的宽度,我们有:
A1 = A + N * w1/2
A2 = A – N * w1/2
B1 = B + N * w2/2
B2 = B – N * w2/2

那么我们如何找到这个法向量 N 呢?
数学说如果 (x,y) 定义了一个向量 V ,它的法线向量坐标是 (-y, x).
N,因此垂直于 AB 的向量将具有 ( – ( yB – yA ) , ( xB – xA ) ) 作为坐标。
但是这个向量有一个烦人的地方:它取决于 AB 的长度,而 AB 的长度不是 我们想要的:我们需要规范化这个向量,即将它的标准长度设为 1,所以当我们稍后将这个向量乘以 w1/2 时,我们得到正确的长度向量。

向量归一化 是通过将向量的 x 和 y 除以向量长度来完成的。 由于长度是使用phytagore定理求得的,所以得到2个平方,一个平方根,最后2个除以找到归一化向量N :

// computing the normalized vector normal to AB
length = Math.sqrt( sq (xB-xA) + sq (yB - yA) ) ;
Nx     =  -  (yB - yA) / length ;
Ny     =     (xB - xA) / length ;  

现在我们可以计算这四个点了,让我们用折线 link 它们,并填充生成的形状:我们的可变宽度段来了!

这是 javascript 代码:

// varLine : draws a line from A(x1,y1) to B(x2,y2)
// that starts with a w1 width and ends with a w2 width.
// relies on fillStyle for its color.
// ctx is a valid canvas's context2d.
function varLine(ctx, x1, y1, x2, y2, w1, w2) {
    var dx = (x2 - x1);
    var dy = (y2 - y1);
    w1 /= 2;  w2 /= 2; // we only use w1/2 and w2/2 for computations.
    // length of the AB vector
    var length = Math.sqrt(sq(dx) + sq(dy));
    if (!length) return; // exit if zero length
    dx /= length ;    dy /= length ;
    var shiftx = - dy * w1   // compute AA1 vector's x
    var shifty =   dx * w1   // compute AA1 vector's y
    ctx.beginPath();
    ctx.moveTo(x1 + shiftx, y1 + shifty);
    ctx.lineTo(x1 - shiftx, y1 - shifty); // draw A1A2
    shiftx =  - dy * w2 ;   // compute BB1 vector's x
    shifty =    dx * w2 ;   // compute BB1 vector's y
    ctx.lineTo(x2 - shiftx, y2 - shifty); // draw A2B1
    ctx.lineTo(x2 + shiftx, y2 + shifty); // draw B1B2
    ctx.closePath(); // draw B2A1
    ctx.fill();    
}

让我们看一个小例子的结果:在一个圆内用漂亮的 hsl 颜色绘制可变宽度的线段:

(关于@MarkE 关于链接线段的(有趣的)评论,我担心这是一个相当困难的目标,因为有许多具体情况取决于线段之间的线长度/w1/w2/角度。我完全解决了它使用力场和行进立方体,但我担心这完全是题外话!!:-))