#はじめに
mousemoveで得た点を滑らかにつないだ曲線をcanvasに描画したいとします。
#イメージ
赤〇は得られたデータです。
緑×は点の中点です。
緑× - 赤〇 - 緑× で2次ベジェ曲線を描画したのが青線です。
このようにベジェ曲線を引くと、曲線同士が滑らかにつながります。
曲線が端点につながっていませんが、点列が割と近いケースを想定しているのであまり問題になりません。
気になる方は直線で結んでください。
#解説
青色の曲線は3本の2次ベジェ曲線からなっています。
###1本目
###2本目
###3本目
###1本目と2本目
1本目の2,3つ目制御点と2本目の1,2つ目の制御点が一直線にあるので、滑らかに接続します。
2本目と3本目の接続も同様です。
#ソース
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>bezier smooth</title>
<script>
document.addEventListener('DOMContentLoaded', e => {
const vertices = [
{ x: 30, y: 200 },
{ x: 100, y: 100 },
{ x: 150, y: 200 },
{ x: 280, y: 340 },
{ x: 300, y: 180 },
];
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.lineWidth = 2;
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// 点群を描画(o)
ctx.strokeStyle = `red`;
vertices.forEach(v => {
ctx.beginPath();
ctx.arc(v.x, v.y, 5, 0, 2 * Math.PI, false);
ctx.stroke();
});
// 点の中点群を取得
let pre = null;
const centers = vertices.reduce((p, c) => {
if(pre) {
const center = { x: (c.x + pre.x) / 2, y: (c.y + pre.y) / 2 };
p.push(center);
}
pre = c;
return p;
}, []);
// 点の中点群を描画(x)
ctx.strokeStyle = `green`;
centers.forEach(center => {
const p = center;
ctx.beginPath();
ctx.moveTo(p.x - 5, p.y - 5);
ctx.lineTo(p.x + 5, p.y + 5);
ctx.moveTo(p.x - 5, p.y + 5);
ctx.lineTo(p.x + 5, p.y - 5);
ctx.stroke();
});
// 2次ベジェ曲線の制御点群を取得
pre = null;
let preCenter = null;
const cps = vertices.reduce((p, c) => {
if(pre) {
const center = { x: (c.x + pre.x) / 2, y: (c.y + pre.y) / 2 };
if(preCenter) {
p.push([ preCenter, pre, center ]);
}
preCenter = center;
}
pre = c;
return p;
}, []);
// 2次ベジェ曲線群を描画
ctx.strokeStyle = `blue`;
cps.forEach(cp => {
ctx.beginPath();
ctx.moveTo(cp[0].x, cp[0].y);
ctx.quadraticCurveTo(cp[1].x, cp[1].y, cp[2].x, cp[2].y);
ctx.stroke();
});
});
</script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
</body>
</html>