简体   繁体   中英

canvas fill() doesn't work as expected when used with spline lines

I'm drawing "closed" figures using a spline line algorithm and when I try to fill them at the end I don't get the expected result. see source if you want to play with it 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]
}

Here is what I get:

在此处输入图片说明
Here is what I was expecting:

在此处输入图片说明

The endpoints of your Bezier curves are not connecting to form a closed path. Therefore you have multiple independent curves (as in your top image) not one closed curve (as in your bottom image).

For example, see the "hitch" in this part of your image.

在此处输入图片说明

The end point of every prececessor curve must be the starting point of the next curve or else the curve will not be closed.

You can almost get there by removing the ctx.moveTo inside your loop, but you need to close that last bottom section:

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]);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM