0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【JavaScript】点列を2次ベジェ曲線で滑らかにつなごう【Canvas】

Last updated at Posted at 2020-10-29

#はじめに
mousemoveで得た点を滑らかにつないだ曲線をcanvasに描画したいとします。
#イメージ
赤〇は得られたデータです。
緑×は点の中点です。
緑× - 赤〇 - 緑× で2次ベジェ曲線を描画したのが青線です。
このようにベジェ曲線を引くと、曲線同士が滑らかにつながります。
image.png

曲線が端点につながっていませんが、点列が割と近いケースを想定しているのであまり問題になりません。
気になる方は直線で結んでください。

#解説
青色の曲線は3本の2次ベジェ曲線からなっています。
###1本目
test (1).png
###2本目
test (2).png
###3本目
test (3).png
###1本目と2本目
1本目の2,3つ目制御点と2本目の1,2つ目の制御点が一直線にあるので、滑らかに接続します。
2本目と3本目の接続も同様です。
test (7).png

#ソース

<!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>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?