const canvas = document.createElement('canvas');
const c = canvas.getContext('2d');
document.body.appendChild(canvas);
function draw() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
c.fillStyle = 'gray';
c.fillRect(0, 0, canvas.width, canvas.height);
c.strokeStyle = 'white';
c.lineWidth = 2;
c.beginPath();
c.moveTo(0, 0);
bezierSkin([10, 10, 210, 10, 10, 300, 210, 300], false);
bezierSkin([200, 10, 330, 10, 250, 300]);
bezierSkin(
Array(30)
.fill(0)
.map((a, b) => (b % 2 == 0) * 300 + Math.random() * 300)
);
c.stroke();
}
window.addEventListener('resize', draw);
draw();
// array of xy coords, closed boolean
function bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
let 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) {
const avg = [];
const leng = p.length;
let 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;
}