
Canvas+JavaScriptで多角形/星型多角形を描いた話
はじめに
JavaScriptとCanvasの練習がてら、多角形/星形多角形を描いて遊びました。
具体的には下記を実装してみました。
・円と線分を描く
・1秒ごとに頂点の数を増やす
・隣の頂点と繋ぐ/隣の隣と繋ぐ…とN個飛ばしで頂点をつなげるようにする



html
ヘッダー画像のページを作ります。
canvasが上下中央に配置されるように、body要素に高さを指定(横幅は勝手にされる)。flexを指定して子要素のcanvasが上下中央に来るようにしました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Draw star</title>
<style>
body{
margin: 0px;
padding: 0px;
background: #b0c4de;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#canvas{
border: 1px solid #c2d6ef;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
JavaScript
"use strict";
// async/awaitでループ中にスリープしつつ
// draw関数を呼び出す
(async () => {
let i = 3;
while (true) {
draw(i, 3);
await wait(1000); // 1秒ごとに描写
i++;
}
})();
function wait(msec) {
return new Promise(resolve => setTimeout(resolve, msec));
}
// 頂点数vertices、頂点を(skip-1)個飛ばしで繋いだ図を描写する
function draw(vertices, skip) {
console.log(vertices);
// パラメータ
const height = 1000;
const width = 1000;
const radius = Math.min(height, width)/2;
// canvasのお作法
const cvs = document.getElementById('canvas'); // canvas要素への参照の取得
const ctx = canvas.getContext('2d'); // コンテキストの取得
cvs.width = width;
cvs.height = height;
// 円周を描写
ctx.beginPath();
ctx.arc(height/2, width/2, radius, 0, 2*Math.PI);
ctx.closePath();
ctx.stroke();
// 頂点の座標を格納する配列を作成
let verticesPos = [];
let i;
for(let i=0; i<vertices; i++){
if(vertices == 1) break;
var rad = 2*Math.PI / vertices;
verticesPos.push([height/2 + radius*Math.sin(rad*i) , width/2 - radius*Math.cos(rad*i) ]);
}
// 線を描写
for(i=0; i<vertices; i++){
// 頂点数がスキップ数以下だったら描写しない
if(vertices <= skip){ break; };
// スキップした先が配列の要素数を超えた場合の処理
// (450度→90度にするようなイメージ)
let j = i + skip;
if(j>=vertices){ j = j -vertices; };
// 線分を描写
ctx.beginPath();
ctx.moveTo(verticesPos[i][0], verticesPos[i][1]); // ペンを点Iへ移動
ctx.lineTo(verticesPos[j][0], verticesPos[j][1]); // 点Iから点Jへ線を引く
ctx.stroke();
}
}