Being able to draw smooth lines that connect arbitrary points is something that I find myself needing very frequently. This is a port of an old snippet that does just that. By averaging control points of a quadratic bezier curve we ensure that our resulting Bezier curves are always smooth.
The key can be seen here with the `bezierSkin` function. It draws either a closed or open curve.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // array of xy coords, closed boolean function bezierSkin(bez, closed = true) { var avg = calcAvgs(bez), leng = bez.length, i, n; if (closed) { c.moveTo(avg[0], avg[1]); for (i = 2; i < leng; i += 2) { n = i + 1; c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]); } c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]); } else { c.moveTo(bez[0], bez[1]); c.lineTo(avg[0], avg[1]); for (i = 2; i < leng - 2; i += 2) { n = i + 1; c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]); } c.lineTo(bez[leng - 2], bez[leng - 1]); } } // create anchor points by averaging the control points function calcAvgs(p) { var avg = [], leng = p.length, prev; for (var i = 2; i < leng; i++) { prev = i - 2; avg.push((p[prev] + p[i]) / 2); } // close avg.push((p[0] + p[leng - 2]) / 2); avg.push((p[1] + p[leng - 1]) / 2); return avg; } |
The control points are then averaged to ensure that the curve contains no sharp angles.