当与样条线一起使用时,canvas fill()不会按预期工作

时间:2014-08-04 23:30:18

标签: javascript canvas html5-canvas

我正在画画"关闭"使用样条线算法的数字,当我尝试在最后填充它时,我没有得到预期的结果。如果您想使用它来查看来源http://jsfiddle.net/9CJv6/14/

var canvas = document.getElementById('canvas');
var points = [100, 300, 10, 150, 100, 180, 120,10, 400,200];
var context = canvas.getContext('2d');
drawSpline(context, points, 0.4);

function drawSpline(ctx, pts, t){
ctx.lineWidth = 3;
var cp = [];   // array of control points, as x0,y0,x1,y1,...
var n = pts.length;

//   Append and prepend knots and control points to close the curve
pts.push(pts[0],pts[1],pts[2],pts[3]);
pts.unshift(pts[n-1]);
pts.unshift(pts[n-1]);
for (var j = 0; j < n; j += 2){
   cp = cp.concat(getControlPoints(pts[j],pts[j+1],pts[j+2],pts[j+3],pts[j+4],pts[j+5],t));
  }
cp = cp.concat(cp[0], cp[1]);   
ctx.strokeStyle = 'red';       
ctx.fillStyle = "yellow";
ctx.beginPath();

for(var i = 2; i < n+2; i += 2){
  ctx.moveTo(pts[i], pts[i+1]);
  ctx.bezierCurveTo(cp[2*i-2], cp[2*i-1], cp[2*i], cp[2*i+1], pts[i+2], pts[i+3]);
}
 ctx.stroke();
ctx.fill();
}

function getControlPoints(x0,y0,x1,y1,x2,y2,t){
//  x0,y0,x1,y1 are the coordinates of the end (knot) pts of this segment
//  x2,y2 is the next knot -- not connected here but needed to calculate p2
//  p1 is the control point calculated here, from x1 back toward x0.
//  p2 is the next control point, calculated here and returned to become the 
//  next segment's p1.
//  t is the 'tension' which controls how far the control points spread.

//  Scaling factors: distances from this knot to the previous and following knots.
var d01=Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2));
var d12=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));

var fa=t*d01/(d01+d12);
var fb=t-fa;

var p1x=x1+fa*(x0-x2);
var p1y=y1+fa*(y0-y2);

var p2x=x1-fb*(x0-x2);
var p2y=y1-fb*(y0-y2);  

return [p1x,p1y,p2x,p2y]
}

这是我得到的:

enter image description here
这就是我的期望:

enter image description here

1 个答案:

答案 0 :(得分:1)

Bezier曲线的端点未连接以形成闭合路径。因此,您有多条独立曲线(如在顶部图像中),而不是一条闭合曲线(如底部图像中所示)。

例如,请参阅&#34; hitch&#34;在你图像的这一部分。

enter image description here

每个上一条曲线的终点必须是下一条曲线的起点,否则曲线不会被关闭。

你可以通过删除循环中的ctx.moveTo来实现这一目标,但是你需要关闭最后一个底部:

for(var i = 2; i < n+2; i += 2){
  ctx.bezierCurveTo(cp[2*i-2], cp[2*i-1], cp[2*i], cp[2*i+1], pts[i+2], pts[i+3]);
}